在8086汇编中,在masm5.0下link的时候出现warning L4021: no stack segment是习以为常的现象。
如,针对下面的程序:
assume cs:codesg,ds:datasg
datasg segment
dw 1,2,3,4,5
datasg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov ax,4c00h
int 21h
codesg ends
end start
编译和连接的结果是:
对此的解释是:程序中没有安排堆栈段。这个警告可以忽略,程序能够运行,并且得到正确的结果。
好吧!那在在程序中加上栈段,警告就该没有了吧?
写下面的程序:
assume cs:codesg,ds:datasg, ss:stacksg
datasg segment
dw 1,2,3,4,5
datasg ends
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
codesg segment
start: mov ax, stacksg
mov ss, ax
mov sp, 16
mov ax, datasg
mov ds, ax
mov bx, 0
mov ax,4c00h
int 21h
codesg ends
end start
程序中,定义了“stacksg segment
”,也assume
了“ss:stacksg
”。然而,编译并连接的结果:
学生问我这个事情时,我意识到自己好像也观察到了,却没有顾上理会。
我将程序用debug装入内存,发现SS的值不对啊!
从图中可以看出,装载进内存的程序起始物理地址在075A0H(DS=075AH),跨过100H的程序段前缀PSP,datasg段该开始于076A0。这一段尽管只有10个字节,但由于下面的stacksg的段起始地址应该是16(10H)的倍数,stacksg段的起始地址该是076B0H才对。然则,SS的值是0769H纯粹没有道理。
只能说明一个事实,人家没有把村长当干部!在连接过程中,并未因为有“stacksg segment
”,和assume
了“ss:stacksg
”就认为设置了堆栈段。
怎样做才能被承认呢?
找度娘,说是将段定义写成下面的形式:
stacksg segment stack
……
stacksg ends
按指点修改程序,写为:
assume cs:codesg,ds:datasg, ss:stacksg
datasg segment
dw 1,2,3,4,5
datasg ends
stacksg segment stack
dw 0,0,0,0,0,0,0,0
stacksg ends
codesg segment
start: mov ax, stacksg
mov ss, ax
mov sp, 16
mov ax, datasg
mov ds, ax
mov bx, 0
mov ax,4c00h
int 21h
codesg ends
end start
编译和连接结果:
完美消除warning!
再debug连接好的可执行文件:
SS=076BH是对的!居然还有SP=0010H!这是在还没有执行程序中任何指令的情况下发生的事情!是连接程序自动地发现定义的堆栈段大小就是10H!
那,这是为什么呢?
查阅汇编程序中段的定义语法,完整的是:
segname SEGMENT [align_type][combine_type][user_type]['class']
...
segname ENDS
其中的组合类型(combine_type)可以是:
STACK:指定该段在运行时为堆栈段的一部分。
这些选项的含义不解释了。要解释通可能还需要再补充不少其他知识。我们先明白,stacksg segment stack
中最后的stack
让连接程序将定义的堆栈段当堆栈段用了。
最后多说一句是,要真正说清楚这件事,得谈多个.obj是如何link为一个.exe的。眼下先学现在要紧的。