本文最后更新于 250 天前,其中的信息可能已经有所发展或是发生改变。
内容目录
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 内存没有重叠 正常情况
测试2:
纠正:红色框中注释部分修改为 si < di
纠正:红色框中注释部分修改为 si < di
测试3:
因为是从后向前拷贝,最前面两个肯定是被拷贝到相邻的空间里去了,打印一下相邻的空间看下
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不符 ???
打断点 看寄存器的值
调用FatVec函数前后值的变化