【OS】08 – 突破512字节的限制(下)【Memcpy、FatVec:通过Fat表加载文件到内存】
本文最后更新于 250 天前,其中的信息可能已经有所发展或是发生改变。
内容目录

参考:【OS】08 – 突破512字节的限制(下)

 

0x01 Memcpy

1.1 code

Memcpy函数完成并测试

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

    ;test MemCpy 内存没有重叠
    ;mov si, Target
    ;mov di, Buf
    ;mov cx, TarLen
    ;call MemCpy

    ;test MemCpy 内存重叠 si < di  把源内存的内容向后移动两个字节,打印顺序etob
    ;mov si, Target
    ;mov di, si
    ;add di, 2
    ;mov cx, TarLen
    ;call MemCpy

    ;test MemCpy 内存重叠 si > di,打印顺序btoe
    mov si, Target
    mov di, si
    sub di, 2
    mov cx, TarLen
    call MemCpy

output: 
    ;mov bp, Buf    ;打印内存没有重叠
    ;mov cx, TarLen

    ;mov bp, Target ;打印内存重叠si < di
    ;add bp, 2      ;改进:Target向后偏移两个字节的地方开始打印,去掉开头部分的打印
    ;mov cx, TarLen

    mov bp, MsgStr ;打印内存重叠si > di
    mov cx, MsgLen
    ; "LOADER     "拷贝到"No LOADER ..."时,由于sub di, 2操作,拷贝的目标地址是从"No LOADER ..."最后两个".."开始的
    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

 

1.2 验证结果

;test MemCpy 内存没有重叠 正常情况

file

 

测试2:
纠正:红色框中注释部分修改为 si < di

file

 
纠正:红色框中注释部分修改为 si < di

file

 

测试3:

因为是从后向前拷贝,最前面两个肯定是被拷贝到相邻的空间里去了,打印一下相邻的空间看下

file

 

file

 

0x02 FatVec

备注: 这个验证和验证结果不太理解,有待补充

2.1 code

org 0x7c00

jmp short start
nop

define:
    BaseOfStack      equ 0x7c00
    BaseOfLoader     equ 0x9000 ;最后要把目标程序加载到这个地址处,fat表加载到这个地址的前面
    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 ;在拷贝之后,EntryItem是目录项入口地址
    mov cx, EntryItemLength

    call MemCpy

    ;########加载fat表,计算fat表占用的内存########
    mov ax, FatEntryLength  ;扇区长度
    mov cx, [BPB_BytsPerSec];每个扇区的大小
    mul cx                  ;ax中就保存了fat表占用的内存
    mov bx, BaseOfLoader    ;0x9000 -> fat表加载到0x9000地址的前面
    sub bx, ax              ;减去fat表在内存中占的字节数,bx中存放的是fat表起始位置

    mov ax, FatEntryOffset
    mov cx, FatEntryLength

    ; ax    --> logic sector number
    ; cx    --> number of sector
    ; es:bx --> target address
    call ReadSector      ;fat表就在内存当中了

    ;########查表 cx对应的表项########
    mov cx, [EntryItem + 0x1A] ;cx表示起始簇的值,0x1A是 DIR_FstClus目标项的偏移位置

    ; cx --> index
    ; bx --> fat table address 在内存当中的起始位置(基址)
    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]  fat表项的值
FatVec:
    mov ax, cx
    mov cl, 2
    div cl      ; 判断是奇数还是偶数,进入不同的关系式处理流程,商al 余数ah

    push ax     ;商合余数入栈

    ; i = j / 2 * 3
    mov ah, 0 ;index/2之后取正数,把这个余数置为0
    mov cx, 3
    mul cx
    mov cx, ax ;cx保存对应的表项在内存中的起始位置:i = index/2*3

    pop ax

    cmp ah, 0
    jz even
    jmp odd

even:           ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i]; 
    mov dx, cx  ;Fat[i]中i
    add dx, 1   ;Fat[i+1]中的i+1
    add dx, bx  ;计算真正的 Fat[i+1] 的地址,为什么真正的地址这么计算?
    mov bp, dx
    mov dl, byte [bp] ;拿到Fat[i+1]的值
    and dl, 0x0F
    shl dx, 8
    add cx, bx   ; cx是表项在内存当中的起始字节数,加上bx就是内存地址
    mov bp, cx   ;
    or  dl, byte [bp] ;结果存在dl中,也就是dx的低八位
    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 ; 高8位清空,右移位可以保存值
    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 ; 高8位清空,右移位可以保存值
    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

 

2.2 验证结果

读取一下img文件,加载LOADER文件文件

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QString img = "/home/delphi/OS/Fat12Test/data.img";
    Fat12Header f12;

    qDebug() << "Read Header:";
    PrintHeader(f12, img);
    qDebug() << endl;

    qDebug() << "Print Root Entry:";
    PrintRootEntry(f12, img);
    qDebug() << endl;

    qDebug() << "Print File Content:";
    QString content = QString(ReadFileContent(f12, img, "LOADER"));
    qDebug() << content;

    return a.exec();
}

 

读取到的j为4,表示起始簇号为4,并且只使用一个扇区来保存文件的内容,

for(int i=0, j=re.DIR_FstClus; j<0xFF7; i+=512, j=vec[j])

vec[j]获取表项值的时候,得到了一个非法的值,和j<0xFF7不符 ???

file

 

打断点 看寄存器的值

file

 

调用FatVec函数前后值的变化

file

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇