MASM中ORG伪指令的作用
在学习16位MASM汇编时,生成一个com格式的可执行文件,需要在代码的第一行写上org 0100h,各处的资料解释不尽相同,如:
1、程序从0100h处开始执行;
2、告诉编译器讲程序加载到0100h;
3、代码的偏移地址整体向后移动0100h,或段内的代码或数据从0100h开始放置。
这些解释在当时的情况作用确实如此,但是org为什么有这么多功能呢,经过读取官方文档才明白:
org的作用很简单,就是告诉编译器,当编译到org指令时,org指令后面的代码从org指定的偏移地址开始,即编译器将org后面生成的机器码,从org指定的偏移地址开始放置。官方文档原文:ORG expression,Subsequent code and data offsets begin at the new offset specified set by expression。
首先,MASM中所有的数据和代码都必须属于某个段(segment),段中的代码和数据都是通过偏移地址(offset,段中代码或数据相对于段首的距离)进行访问的,如:
datasg segment
msg1 db "hello"
msg2 db "word"
datasg ends
如果没有org伪指令,数据和代码按顺依次存储和编址。该代码msg1的偏移地址就是[0000],msg2的偏移地址是[5],因为'h'、'e'、'l'、'l'、'o'把前面5个空间占用了(地址从0开始编码,即[0000]、[0001]、[0002]、[0003]、[0004]5个地址)。
如果改成如下代码:
datasg segment
org 0005h
msg1 db "hello"
msg2 db "word"
datasg ends
编译器在编译时,就会从偏移地址[0005]处开始放置数据,即'h'、'e'、'l'、'l'、'o'的偏移地址分别是[0005]、[0006]、[0007]、[0008]、[0009]。那前面的5个空间做什么用了呢,答案是:空着。所以,并不只是将地址从0005处开始编码,而是真的把数据放到哪个位置去,后面的数据依次放置。
那是不是数据整体偏移了呢,答案是:不完全对,如下示例:
datasg segment
org 0005h
msg1 db "hello"
org 0002h
msg2 db "word"
datasg ends
如果是数据整体后移,那就是msg1的地址是向后移动5个即[0005],msg2的地址也向后移动2个,即[0009]+2=[000B]呢,答案是否定的。后面的msg2,会从[0002]处开始放置,显然,会覆盖msg1的数据。
验证如下,如下代码masm5编译后,debug载入:
assume cs:codesg,ss:stacksg,ds:datasg
;--------------------------------------
stacksg segment stack
stacksg ends
;--------------------------------------
datasg segment
org 0005h
msg1 db "aaaaa"
org 0002h
msg2 db "bbbbb"
datasg ends
;--------------------------------------
codesg segment
start:
mov ax,datasg
mov ds,ax
mov ax,4c00h
int 21h
codesg ends
end start
datasg段的前2个字节空着,msg2的数据覆盖了部分msg1的数据。
问题1:那com文件中org 0100h到底是不是告诉系统从0100h处开始执行呢?
答:当然不是,系统是从0100h处开始执行,但不是org 0100h导致的,是系统加载com文件就会从偏移地址0100h处执行,无论该处是否有正确的代码或编译时是否有org指令。如何保证0100处有正确的代码,org 0100h就能达到目的。哪怕org指令后是jmp都行,然后跳转到正确的代码地址处。16位cpu是从偏移地址0100h处执行,那段地址呢,一段程序不是有好多段么,cs、ds、ss,是哪个段呢?答:com文件只有一个段,cs、ds、ss地地址都相同,所以不用指定。
参考代码如下:
assume cs:_text,ds:_text,ss:_text
_text segment
org 100h
begin:
jmp start
msg db "Hello,world!",13,10
lmsg equ $ - msg
start:
mov ah,40h
mov bx,1
mov dx,offset msg
mov cx,lmsg
int 21h
mov ax,4c00h
int 21h
_text ends
end begin
问题2:mbr程序中的org 7c00h是不是道理一样呢?
答:当然一样,系统自检后就是从7c00h处开始执行,你只要在偏移地址7c00h处有正确的代码,就可以继续启动。电脑自检完成后,加载mbr程序到内存,程序的段地址置入[0000],从偏移地址[7c00]处开始启动os代码。
问题3:类似的功能的伪指令还有么?
答:当然有,如even和align伪指令。