• 08 突破512字节的限制 下


    参考

    https://www.cnblogs.com/wanmeishenghuo/tag/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/

    https://blog.51cto.com/13475106/category6.html

    及狄泰软件相关课程

    上一节我们进行了文件的查找实验,文件查找成功了,这一节,我们将文件的内容加载进内存,再一次将整体的流程给出如下:

      读取文件的内容时,我们需要根据FAT表找到存储文件内容的每一个扇区,然后进行内容的读取,在上一节中,我们将整个目录区的内容加载到了内存并根据文件名找到了所在的目录项,为了节省内存,我们将找到的目录项拷贝到另一片内存区域中,因为这个目录项中还有我们需要的内容,比如文件的起始扇区号等。而原来加载目录区的那一部分内存便可以另作他用,比如可以将FAT表加载到该区域。

      目标文件的目录信息如下:

      内存拷贝时,为了防止已经拷贝的内容将原来还没有拷贝的内容覆盖,我们需要考虑一下拷贝的方向,示意图如下:

      当源地址小于等于目标地址时,要从后向前拷贝,如上图中左半部,当源地址大于目标地址时,要从头部向尾部拷贝,如上图右半部。

      用到的汇编指令如下所示:

      

      下面直接给出内存拷贝的汇编代码:

    org 0x7c00
    
    jmp short start
    nop
    
    define:
        BaseOfStack      equ 0x7c00
        BaseOfLoader     equ 0x9000
        RootEntryOffset  equ 19
        RootEntryLength  equ 14
        EntryItemLength  equ 32
        FatEntryOffset   equ 1
        FatEntryLength   equ 9
    
    header:
        BS_OEMName     db "D.T.Soft"
        BPB_BytsPerSec dw 512
        BPB_SecPerClus db 1
        BPB_RsvdSecCnt dw 1
        BPB_NumFATs    db 2
        BPB_RootEntCnt dw 224
        BPB_TotSec16   dw 2880
        BPB_Media      db 0xF0
        BPB_FATSz16    dw 9
        BPB_SecPerTrk  dw 18
        BPB_NumHeads   dw 2
        BPB_HiddSec    dd 0
        BPB_TotSec32   dd 0
        BS_DrvNum      db 0
        BS_Reserved1   db 0
        BS_BootSig     db 0x29
        BS_VolID       dd 0
        BS_VolLab      db "D.T.OS-0.01"
        BS_FileSysType db "FAT12   "
    
    start:
        mov ax, cs
        mov ss, ax
        mov ds, ax
        mov es, ax
        mov sp, BaseOfStack
    
        mov ax, RootEntryOffset
        mov cx, RootEntryLength
        mov bx, Buf
    
        call ReadSector
    
        mov si, Target
        mov cx, TarLen
        mov dx, 0
    
        call FindEntry
    
    ;    cmp dx, 0
    ;    jz output
    
        mov si, Target
        mov di, MsgStr
        mov cx, TarLen
    
        call MemCpy
    
    
    output:
        mov bp, MsgStr
        mov cx, MsgLen
        call Print
    
    last:
        hlt
        jmp last
    
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    MemCpy:
        push si
        push di
        push cx
        push ax
    
        cmp si, di
    
        ja btoe
    
        add si, cx
        add di, cx
        dec si
        dec di
    
        jmp etob
    
    btoe:
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        inc si
        inc di
        dec cx
        jmp btoe
    
    etob:
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        dec si
        dec di
        dec cx
        jmp etob
    
    done:
        pop ax
        pop cx
        pop di
        pop si
        ret
    
    ; es:bx --> root entry offset address
    ; ds:si --> target string
    ; cx    --> target length
    ;
    ; return:
    ;     (dx !=0 ) ? exist : noexist
    ;        exist --> bx is the target entry
    FindEntry:
        push di
        push bp
        push cx
    
        mov dx, [BPB_RootEntCnt]
        mov bp, sp
    
    find:
        cmp dx, 0
        jz noexist
        mov di, bx
        mov cx, [bp]
        call MemCmp
        cmp cx, 0
        jz exist
        add bx, 32
        dec dx
        jmp find
    
    exist:
    noexist:
        pop cx
        pop bp
        pop di
    
        ret
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    ;
    ; return:
    ;        (cx == 0) ? equal : noequal
    MemCmp:
        push si
        push di
        push ax
    
    compare:
        cmp cx, 0
        jz equal
        mov al, [si]
        cmp al, byte [di]
        jz goon
        jmp noequal
    goon:
        inc si
        inc di
        dec cx
        jmp compare
    
    equal:
    noequal:
        pop ax
        pop di
        pop si
    
        ret
    
    ; es:bp --> string address
    ; cx    --> string length
    Print:
        mov dx, 0
        mov ax, 0x1301
        mov bx, 0x0007
        int 0x10
        ret
    
    ; no parameter
    ResetFloppy:
        push ax
        push dx
    
        mov ah, 0x00
        mov dl, [BS_DrvNum]
        int 0x13
    
        pop dx
        pop ax
    
        ret
    
    ; ax    --> logic sector number
    ; cx    --> number of sector
    ; es:bx --> target address
    ReadSector:
        push bx
        push cx
        push dx
        push ax
    
        call ResetFloppy
    
        push bx
        push cx
    
        mov bl, [BPB_SecPerTrk]
        div bl
        mov cl, ah
        add cl, 1
        mov ch, al
        shr ch, 1
        mov dh, al
        and dh, 1
        mov dl, [BS_DrvNum]
    
        pop ax
        pop bx
    
        mov ah, 0x02
    
    read:
        int 0x13
        jc read
    
        pop ax
        pop dx
        pop cx
        pop bx
    
        ret
    
    MsgStr db  "No LOADER ..."
    MsgLen equ ($-MsgStr)
    Target db  "LOADER     "
    TarLen equ ($-Target)
    EntryItem times EntryItemLength db 0x00
    Buf:
        times 510-($-$$) db 0x00
        db 0x55, 0xaa
    

    以上程序将Target处的字符串拷贝到了MsgStr处,然后将MsgStr处的内容打印出来,结果如下:

      下一步,我们进行FAT表项的读取,并根据表项的内容加载文件数据,FAT表项中每个表项占用1.5个字节,即使用3个字节表示两个表项,如下图所示:

      以前读取a.img的实验中,我们是将FAT表项完全读取后做了一次转换,生成了一个向量,向量中的每一项占用2个字节,那是一次性将所有FAT表项转换好的,而在我们的汇编程序中,我们使用动态组装的方法,即每用到一个表项就进行临时组装,组装后的FAT表项的下标和起始字节的关系图如下:

      

      组装时用到的关系式如下所示:

      需要用到的乘法汇编指令如下:

       

      我们先打开之前写的读取a.img的Qt程序,添加一行,如下所示:

      我们新添加了224行,将数据所在的扇区号分别打印出来,运行程序,得到如下结果:

      上图中只打印出了4,说明数据只存在第4扇区,也就是222行的循环只循环了一次,第二次循环是vec[j]已经不再小于0xFF7,也就是FAT表项不再是一个有效项,而是一个结束项。

      下面给出汇编程序:

    org 0x7c00
    
    jmp short start
    nop
    
    define:
        BaseOfStack      equ 0x7c00
        BaseOfLoader     equ 0x9000
        RootEntryOffset  equ 19
        RootEntryLength  equ 14
        EntryItemLength  equ 32
        FatEntryOffset   equ 1
        FatEntryLength   equ 9
    
    header:
        BS_OEMName     db "D.T.Soft"
        BPB_BytsPerSec dw 512
        BPB_SecPerClus db 1
        BPB_RsvdSecCnt dw 1
        BPB_NumFATs    db 2
        BPB_RootEntCnt dw 224
        BPB_TotSec16   dw 2880
        BPB_Media      db 0xF0
        BPB_FATSz16    dw 9
        BPB_SecPerTrk  dw 18
        BPB_NumHeads   dw 2
        BPB_HiddSec    dd 0
        BPB_TotSec32   dd 0
        BS_DrvNum      db 0
        BS_Reserved1   db 0
        BS_BootSig     db 0x29
        BS_VolID       dd 0
        BS_VolLab      db "D.T.OS-0.01"
        BS_FileSysType db "FAT12   "
    
    start:
        mov ax, cs
    	mov ss, ax
    	mov ds, ax
    	mov es, ax
    	mov sp, BaseOfStack
    	
    	mov ax, RootEntryOffset
    	mov cx, RootEntryLength
    	mov bx, Buf
    	
    	call ReadSector
    	
    	mov si, Target
    	mov cx, TarLen
    	mov dx, 0
    	
    	call FindEntry
    	
    	cmp dx, 0
    	jz output
    	
    	mov si, bx
    	mov di, EntryItem
    	mov cx, EntryItemLength
    	
    	call MemCpy
    	
    	mov ax, FatEntryLength
    	mov cx, [BPB_BytsPerSec]
    	mul cx
    	mov bx, BaseOfLoader
    	sub bx, ax
    	
    	mov ax, FatEntryOffset
    	mov cx, FatEntryLength
    	
    	call ReadSector
    	
    	mov cx, [EntryItem + 0x1A]
    	
    	call FatVec
    	
    	jmp last
    	
    output:	
        mov bp, MsgStr
        mov cx, MsgLen
    	call Print
    	
    last:
        hlt
    	jmp last	
    
    
    ; cx --> index
    ; bx --> fat table address
    ;
    ; return:
    ;     dx --> fat[index]
    FatVec:
        mov ax, cx
        mov cl, 2
        div cl
        
        push ax
        
        mov ah, 0
        mov cx, 3
        mul cx
        mov cx, ax
        
        pop ax
        
        cmp ah, 0
        jz even
        jmp odd
    
    even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
        mov dx, cx
        add dx, 1
        add dx, bx
        mov bp, dx
        mov dl, byte [bp]
        and dl, 0x0F
        shl dx, 8
        add cx, bx
        mov bp, cx
        or  dl, byte [bp]
        jmp return
        
    odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
        mov dx, cx
        add dx, 2
        add dx, bx
        mov bp, dx
        mov dl, byte [bp]
        mov dh, 0
        shl dx, 4
        add cx, 1
        add cx, bx
        mov bp, cx
        mov cl, byte [bp]
        shr cl, 4
        and cl, 0x0F
        mov ch, 0
        or  dx, cx
    
    return: 
        ret
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    MemCpy:
        push si
        push di
        push cx
        push ax
        
        cmp si, di
        
        ja btoe
        
        add si, cx
        add di, cx
        dec si
        dec di
        
        jmp etob
        
    btoe:
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        inc si
        inc di
        dec cx
        jmp btoe
        
    etob: 
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        dec si
        dec di
        dec cx
        jmp etob
    
    done:   
        pop ax
        pop cx
        pop di
        pop si
        ret
    
    ; es:bx --> root entry offset address
    ; ds:si --> target string
    ; cx    --> target length
    ;
    ; return:
    ;     (dx !=0 ) ? exist : noexist
    ;        exist --> bx is the target entry
    FindEntry:
        push di
        push bp
        push cx
        
        mov dx, [BPB_RootEntCnt]
        mov bp, sp
        
    find:
        cmp dx, 0
        jz noexist
        mov di, bx
        mov cx, [bp]
        call MemCmp
        cmp cx, 0
        jz exist
        add bx, 32
        dec dx
        jmp find
    
    exist:
    noexist: 
        pop cx
        pop bp
        pop di
           
        ret
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    ;
    ; return:
    ;        (cx == 0) ? equal : noequal
    MemCmp:
        push si
        push di
        push ax
        
    compare:
        cmp cx, 0
        jz equal
        mov al, [si]
        cmp al, byte [di]
        jz goon
        jmp noequal
    goon:
        inc si
        inc di
        dec cx
        jmp compare
        
    equal: 
    noequal:   
        pop ax
        pop di
        pop si
        
        ret
    
    ; es:bp --> string address
    ; cx    --> string length
    Print:
        mov dx, 0
        mov ax, 0x1301
    	mov bx, 0x0007
    	int 0x10
        ret
    
    ; no parameter
    ResetFloppy:
        push ax
        push dx
        
        mov ah, 0x00
        mov dl, [BS_DrvNum]
        int 0x13
        
        pop dx
        pop ax
        
        ret
    
    ; ax    --> logic sector number
    ; cx    --> number of sector
    ; es:bx --> target address
    ReadSector:
        push bx
        push cx
        push dx
        push ax
        
        call ResetFloppy
        
        push bx
        push cx
        
        mov bl, [BPB_SecPerTrk]
        div bl
        mov cl, ah
        add cl, 1
        mov ch, al
        shr ch, 1
        mov dh, al
        and dh, 1
        mov dl, [BS_DrvNum]
        
        pop ax
        pop bx
        
        mov ah, 0x02
    
    read:    
        int 0x13
        jc read
        
        pop ax
        pop dx
        pop cx
        pop bx
        
        ret
    
    MsgStr db  "No LOADER ..."	
    MsgLen equ ($-MsgStr)
    Target db  "LOADER     "
    TarLen equ ($-Target)
    EntryItem times EntryItemLength db 0x00
    Buf:
    	times 510-($-$$) db 0x00
    	db 0x55, 0xaa
    

     运行bochs,在程序的第77,79行打断点(具体方法见上节反汇编ndisasm使用方法),然后运行到第一个断点处,打印寄存器内容如下:

      可以看到ecx中的后两个字节(bochs为16字节操作)确实为4,这就是文件数据起始扇区号,edx此时还为0,继续运行到下一个断点处,打印寄存器如下:

      寄存器edx的内容为0xfff,这就是FAT表项中的内容,说明文件结束了,文件的内容只存在了一个扇区中。本节中的FatVec函数并没有完善,本节还没有进行文件内容的读取,只是根据文件数据起始扇区号,读取了下一个FAT表项的内容,下一节继续。。。

      

      

  • 相关阅读:
    Angular InjectionToken
    ionic 使用入门
    EFcore 横向分表
    .Netcore 默认认证授权
    anut 设计资源
    Aunt entity
    百度人脸真人认证
    Angular 省市区级联
    apache安装
    ppb|ppm
  • 原文地址:https://www.cnblogs.com/lh03061238/p/14005333.html
Copyright © 2020-2023  润新知