汇编语言.MODEL伪指令:确定程序的特性
16 位和 32 位模式中,MASM 使用 .MODEL 伪指令确定若干重要的程序特性:内存模式类型、过程命名模式以及参数传递规则。若汇编代码被其他编程语言程序调用,那么后两者就尤其重要。
.MODEL 伪指令的语法如下:
32 位程序使用平坦内存模式,其偏移量为 32 位,代码和数据最大可达 4GB。比如,Irvine32.inc 文件包含了如下 .MODEL 伪指令:
最后,STDCALL 通过将输出(公共)过程名保存为如下格式来修改这些名称:
Microsoft 链接器是区分大小写的,因此 _MYSUB@8 和 _MySub@8 是两个不同的名称。要查看 OBJ 文件中所有的过程名,使用 Visual Studio 中的 DUMPBIN 工具,选项为 /SYMBOLS。
.MODEL 伪指令的语法如下:
.MODEL memorymodel [,modeloptions]
MemoryModel
下表列出了 memorymodel 字段可选择的模式。除了平坦模式之外,其他所有模式都可以用于 16 位实地址编程。模式 | 说明 |
---|---|
微模式 | 一个既包含代码又包含数据的段。文件扩展名为 .com 的程序使用该模式 |
小模式 | 一个代码段和一个数据段。默认情况下,所有代码和数据都为近属性 |
中模式 | 多个代码段,一个数据段 |
紧凑模式 | 一个代码段,多个数据段 |
大模式 | 多个代码段和数据段 |
巨模式 | 与大模式相同,但是各个数据项可以大于单个段 |
平坦模式 | 保护模式。代码与数据使用 32 位偏移量。所有的数据和代码(包括系统资源)都在一个 32 位段内 |
32 位程序使用平坦内存模式,其偏移量为 32 位,代码和数据最大可达 4GB。比如,Irvine32.inc 文件包含了如下 .MODEL 伪指令:
.model flat, STDCALL
ModelOptions
.MODEL 伪指令中的 ModelOptions 字段可以包含一个语言说明符和一个栈距离。语言说明符指定过程与公共符号的调用和命名规范。栈距离可以是 NEARSTACK(默认值)或者 FARSTACK。1) 语言说明符
伪指令 .MODEL 有几种不同的可选语言说明符,其中的一些很少使用(比如 BASIC、FORTRAN 和 PASCAL)。反之,C 和 STDCALL 则十分常见。结合平坦内存模式,示例如下:
.model flat, C
.model flat, STDCALL
2) STDCALL
STDCALL 语言说明符将子程序参数按逆序(从后往前)压入堆栈。为了便于说明,首先用高级语言编写如下函数调用:AddTwo(5, 6);
若 STDCALL 被选为语言说明符,则等效的汇编语言代码如下:
push 6
push 5
call AddTwo
AddTwo PROC
push ebp
mov ebp,esp
mov eax, [ebp + 12] ;第二个参数
add eax, [ebp + 8] ;第一个参数
pod ebp
ret 8 ;清除堆栈
AddTwo ENDPP
最后,STDCALL 通过将输出(公共)过程名保存为如下格式来修改这些名称:
_name@nn
前导下划线添加到过程名,@ 符号后面的整数指定了过程参数的字节数(向上舍入到 4 的倍数)。例如,假设过程 AddTwo 带有两个双字参数,那么汇编器传递给链接器的名称就为 _AddTwo@8。Microsoft 链接器是区分大小写的,因此 _MYSUB@8 和 _MySub@8 是两个不同的名称。要查看 OBJ 文件中所有的过程名,使用 Visual Studio 中的 DUMPBIN 工具,选项为 /SYMBOLS。
3) C 说明符
和 STDCALL 一样,C 语言说明符也要求将过程参数按从后往前的顺序压入堆栈。对于过程调用后从堆栈中移除参数的问题,C 语言说明符将这个责任留给了主调方。在主调程序中,ESP 与一个常数相加,将其再次设置为参数入栈之前的位置:
push 6 ;第二个参数
push 5 ;第一个参数
call AddTwo
add esp,8 ;清除堆栈
_AddTwo