《自己动手写操作系统》书中第二页的代码1-1中对于 org07c00h是这样注释的:“告诉编译器程序加载到7c00h处”
org 07c00h
mov ax,cs
mov ds,ax
mov es,ax
call screen
jmp $
screen:mov ax,bootmsg
mov bp,ax
mov cx,16
mov ax,01301h
mov bx,000ch
mov dl,0
int 10h
ret
bootmsg:db'Hello OS world!'
times 510-($-$$) db 0
dw 0xaa55
但是我看到一些资料说,bios会自动将引导程序加载到07c00h处,也就是说无论代码是什么都会被bios加载到07c00h处,那么为什么还要写呢?后来我去掉org 7c00h试了一下,仍可以启动。只是显示乱码。
org 会在编译期影响到内存寻址指令的编译(编译器会把所有程序用到的段内偏移地址自动加上org 后跟的数值),而其自身并不会被编译成机器码。就是为程序中所有的引用地址(需要计算的相对地址)增加一个段内偏移值。org 指令本身并不能决定程序将要加载到内存的什么位置,它只是告诉编译器,我的程序在编译好后需要加载到xxx 地址,所以请你在编译时帮我调整好数据访问时的地址。
如果没有org指令,那么编译器计算偏移量(虽然nasm中没有offset但编译器仍会进行这个运算)是从0000开始的,如果有了org,就会在最后加上org后面跟的数字。
在这个引导程序中:mov ax,bootmsg 在编译的时候实际上是将 mov ax,bootmsg所在的地址与bootmsg同当前语句(mov ax,bootmsg)地址的偏移量相加所计算出来的。没有org则偏移量从0000h开始,于是虽然整个代码被加载到0x7c00处,但当执行到mov ax,bootmsg一句的时候,由于没有算入偏移量7c00从而没有将bootmsg字符串的首地址放入ax,以至发生错误。
Ndisasm -o 0x0000 boot.bin >> disboot1.asm 所得到的汇编文件:
Ndisasm –o 0x7c00 boot.bin >> disboot2.asm所得到的汇编文件:
通过反汇编,模拟了引导程序被加载到0000:0000处和0000:7c00处时的不同情形。第一次为0000:0000第二次为 0000:7C00。而对于mov ax,bootmsg一句的翻译却是一样的,都是 mov ax,0x7c1e 。显然第一次发生了错误(因为在整个程序中就没有出现0x7c1e这个地址,也就是说这是个无效地址)。错误产生的原因就是由于当代码被编译器编译的时候编译器是按照从7c00处开始计算地址的。也证明了bootmsg的地址是由编译器计算出来的。
最后我们来分析一下为什么有时候去掉org 指令程序也能正常执行?
如:
ORG 7C00H
msg: db 'HELLO WORLD',0
MOV DX, OFFSET msg
在有ORG 7C00H的情况下,MOV DX, OFFSET msg对应的指令为MOV DX,7C4B(这里4B为msg在当前数据段中的偏移位置)如果没有ORG 7C00H,那么真正被执行的指令将为MOV SI,004B,试想,BIOS已经将该代码装载到0000:7C00处,0000:0000–0000:7C00之间的数据可能为其他更重要的数据,如果使用004B就得不到我们所要访问字符串msg,因为我们的字符串被BIOS放在7C4B这里了,所以我们的程序(最终由编译器来完成)就必须迎合BIOS的这种规定了。
因此,如果在程序中没有牵扯到地址的计算,那么完全可以不写org(没有做实验验证)
以下是我参考的文章,给了我很大的帮助。可以从我的blog资源中下载
http://blogimg.chinaunix.net/blog/upfile/070306125420.pdf