nasm的汇编和反汇编
步骤:
1. 汇编(boot.asm为boot.bin)
nasm boot.asm -o boot.bin
2. 反汇编(boot.bin为disboot.asm)
ndisasm -o 0x7C00 boot.bin >> disboot.asm
注:nasm和ndisasm工具都是nasm的组件:)
****************************************************************************
"boot.asm"文件:
org 07c00h ; 告诉编译器程序加载到7c00处(见下面解释) mov ax, cs mov ds, ax mov es, ax call DispStr ; 调用显示字符串例程 jmp $ ; 无限循环 DispStr: mov ax, BootMessage mov bp, ax ; ES:BP = 串地址 mov cx, 16 ; CX = 串长度 mov ax, 01301h ; AH = 13, AL = 01h mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮) mov dl, 0 int 10h ; 10h 号中断 (这是BIOS中断,功能号AH=13表示“从指定位置起显示字符 串”,详见附件) ret BootMessage: db "Hello, OS world!" times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节 dw 0xaa55 ; 结束标志
为什么要org 07c00h?
有很多人看了"自己动手写操作系统"或其第二版这本书后对这一行提出疑问.
这个问题在书中作者的解释是:
告诉编译器,将来我们的这段程序要被加载到07c00处执行.
我们知道编译器本身在汇编时对指令的地址计算的是相对地址.而对于引导扇区,一切只是从无生有的
阶段,是按绝对地址执行.那么对于用相对地址编译的执行码就要换算成绝对地址.
一般而言,"真实开始执行的引导扇区"都会固定装载到07c00处,主意这句话是说一个真正的引导扇区.
对于硬盘上,会有一个主引导扇区,然后由它来控制和其它引导扇区,比如grub控制windows,linux等.
那么这个主引导扇区会加载在0600h处,当选择其它可引导扇区时再将真正的可引导扇区加载到07c00h.
所以一般而言真正的可引导扇区都装载到07c00h处.
因为编译器在编译时的地址是从第一行开始用0000h开始相对计算的.假如我们定义一个str: dw "zxy"
它的相对地址是0100h,如果我们mov ax str那么就是将0100h传给ax,这在编译后的执行码中是固定的.
而引导扇区是使用绝对地址执行的,指令从07c00h处开始执行,那么访问0100h绝对是错误的访问.真实
的绝对地址是07c00h+0100h,所以如果你不写org 07c00h,把mov ax str写成mov ax str+07c00h对于
传址操作是一样的目的.对于作者的那段程序可以去掉第一行的org 07c00h.把"mov ax,BootMessage"
改成"mov ax,BootMessage+07c00h",效果是一样的.
但是如果有大量的传址操作,那就要在每个地方都要+07c00h,那是一件非常头痛的事.
所以在第一行加上org 07c00h只是让编译器从相对地址org 07c00h处开始编译第一条指令,那么下面的
相对地址被编译加载后就正好和绝对地址吻合.
****************************************************************************
"disboot.asm"文件:
//ndisasm -o 0x7c00 boot.bin >> disboot.asm //下面是反汇编boot.bin得到的disboot.asm文件: //1. 程序框架 00007C00 8CC8 mov ax,cs 00007C02 8ED8 mov ds,ax 00007C04 8EC0 mov es,ax 00007C06 E80200 call word 0x7c0b 00007C09 EBFE jmp short 0x7c09 //2. 显示字符串子例程 00007C0B B81E7C mov ax,0x7c1e 00007C0E 89C5 mov bp,ax 00007C10 B91000 mov cx,0x10 00007C13 B80113 mov ax,0x1301 00007C16 BB0C00