理解ORG指令

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

你可能感兴趣的:(汇编,职场,org,休闲)