本文最后更新于 370 天前,其中的信息可能已经有所发展或是发生改变。
内容目录
0x01 定义栈空间
sp寄存器的值
为什么要用0x7c00用作栈的起始地址?
程序执行从0x7c00从低地址到高地址执行;栈的增长方向是高地址到低地址(和程序执行方向相反);
用0x7c00作为栈的起始地址是可以的,函数调用的操作(栈增长)不会影响程序的执行;
0x02 读取数据
需要的文件
bochsrc
############################################################### # Configuration file for Bochs ############################################################### # how much memory the emulated machine will have megs: 32 # filename of ROM images romimage: file=/usr/local/share/bochs/BIOS-bochs-latest vgaromimage: file=/usr/share/vgabios/vgabios.bin # what disk images will be used floppya: 1_44=data.img, status=inserted # choose the boot disk. boot: a # where do we send log messages? # log: bochsout.txt # disable the mouse mouse: enabled=0 # enable key mapping, using US layout as default. keyboard_mapping: enabled=1, map=/usr/local/share/bochs/keymaps/x11-pc-us.map
Makefile
.PHONY : all clean rebuild SRC := boot.asm OUT := boot.bin IMG := data.img RM := rm -fr all : $(OUT) $(IMG) dd if=$(OUT) of=$(IMG) bs=512 count=1 conv=notrunc @echo "Success!" $(IMG) : bximage $@ -q -fd -size=1.44 $(OUT) : $(SRC) nasm $^ -o $@ clean : $(RM) $(IMG) $(OUT) rebuild : @$(MAKE) clean @$(MAKE) all
boot.asm
org 0x7c00 ;补上三个字节 jmp short start nop ;栈的起始地址(定义栈空间) define: BaseOfStack equ 0x7c00 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 ;sp指向栈的起始地址,这样就有栈空间了 mov ax, 34 ;读取自己计算出来的扇区号 mov cx, 1 ;连续读取一个扇区 mov bx, Buf ;读取长度 call ReadSector mov bp, Buf mov cx, 29 ; 读取自己计算的长度 call Print last: hlt jmp last ; es:bp --> string address ; cx --> string length Print: 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] ; BPB_SecPerTrk 每个柱面18个扇区 div bl ; =》 逻辑扇区号 / 柱面扇区数 =》ax / bl mov cl, ah add cl, 1 ; 余数+1 表示扇区号 mov ch, al shr ch, 1 ; 柱面号 mov dh, al and dh, 1 ;磁头号 mov dl, [BS_DrvNum] ; 驱动器号 pop ax ;扇区长度出栈,放到al里 pop bx mov ah, 0x02 ; 规定值 read: ;读取失败就继续读 int 0x13 jc read pop ax pop dx pop cx pop bx ret MsgStr db "Hello, DTOS!" MsgLen equ ($-MsgStr) ; 地址差就是长度了 Buf: times 510-($-$$) db 0x00 db 0x55, 0xaa
2.1 测试方法:
在windows上用vs2019打开img文件,搜到自己写的文件内容,接下来就要读取这个字符串;
确定这个字符串位于那个扇区 : 0x4400转换为十进制17408, 17408 / 512 = 34 位于34扇区(逻辑扇区号)第0字节处; 字符串长度:29
打印出来,看是否是这个字符串
2.2 结果分析
发现一个问题: 这个数据长度无论设置为多大,都可以完整读取整个字符串,每次读取一个扇区的原因吗?
那这个字符串的长度就没有必要设置了,后来发现不设置也是可以的;
0x03 调试
反编译出bin文件,再通过bin文件反编译出函数地址信息出来,通过调试 查看寄存器和内存的状态是否是期望的状态;
反编译命令: ndisasm -o 0x7c00 boot.bin > boot.txt
从0x7c00处开始,在 boot.txt中可以查找到函数对应的地址,进一步就可以调试了