NASM汇编器和MASM汇编器一样,都可以生成适用于Win32平台的coff文件格式,这种文件格式可以被MS 的link.exe连接器连接成PE文件。通常,我们知道MASM可以通过includelib伪指令将导入库的名称传给连接器link.exe,告知它该从哪个库中导入所需外部符号,而NASM汇编器在这方面的能力却是有过之而无不及,它可以通过info段,将更多的连接参数传递给link.exe,下面的两段代码展示了两者之间的用法和差异:
;
;cmd> nasm -fcoff -Xvc sayhellon.asm
;cmd> link sayhellon.obj
extern _MessageBoxA@16 ;in user32.dll
extern _ExitProcess@4 ;in kernel32.dll
global SayHello
global _WinMain
[SECTION .drectve info align=8]
db " /subsystem:windows"
db " /out:sayhellon.exe"
db " /defaultlib:kernel32.lib"
db " /defaultlib:user32.lib"
db " /export:SayHello"
db " /entry:WinMain"
db " /merge:.rdata=.text",0
[SECTION .text USE32 align=16]
szTitle:
db "SayHello",0
szMsg:
db "Hello World!", 0
SayHello:
push 0 ;uType
push dword szTitle ;lpCaption
push dword szMsg ;lpText
push 0 ;hWnd
call _MessageBoxA@16
ret 16
_WinMain:
call SayHello
push 0
call _ExitProcess@4
如上述代码所示,我基本上把link.exe连接器所需要的参数都写在源代码的.drectve段中了,注意:.drectve段由info标志,info是一种特殊的段,这个段只在coff文件中存在,link.exe连接器从这个段中读取控制指令参数,但是不会把这个段的内容写到生成的PE文件中。对info段的使用,MASM也用到了,只不过比较间接,比如对includelib的使用间接地使用info段,代码如下:
;cmd> ml /c /coff /nologo sayhellom.asm
;cmd> link /subsystem:windows /libpath:\masm32\lib
; /merge:.rdata=.text /export:SayHello /out:sayhellom.exe sayhellom.obj
;
.586
.model flat, stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib
public c SayHello
.code
szTitle:
db "SayHello",0
szMsg:
db "Hello World!", 0
SayHello PROC C
push MB_OK ;uType
push offset szTitle ;lpCaption
push offset szMsg ;lpText
push 0 ;hWnd
call [MessageBoxA]
ret 16
SayHello ENDP
start:
call SayHello
push 0
call [ExitProcess]
end start
上述两种方法生成的EXE程序都是1kb大小,虽然效果相同,但NASM将参数写在源代码中,比较便于管理和生成,虽然可以通过Makefile文件管理生成步骤,但仍然会多一个Makefile文件,还要多用一个make.exe或nmake.exe,呵呵,这只是我的个人之见,毕竟MASM社区众多,资源丰富,譬如头文件、现成的宏定义等比较丰富,不过,有兴趣的读者仍然可以尝试一下NASM的这一特性。
NASM还有一种更加方便的外部库函数导入方法,就是import伪指令,import伪指令可以直接使用函数名,而不用给函数名加上'_'前缀和'@number'后缀,但import伪指令仅适合于OMF(borland obj)格式输出,OMF格式是MS在16位下操作系统的目标文件格式,borland仍然使用这种格式,并将格式进行了扩展,使得可以在Win32环境下使用,NASM支持这种扩展的OMF格式,但必须显式指定生成32位的obj。由于import伪指令需要OMF格式的支持,而MS的link.exe连接器会在连接时自动将OMF格式转换成COFF格式,从而无法完成导入外部标志的操作,因此,需要一个直接支持连接OMF格式的连接器,这里推荐开源连接器alink.exe。alink.exe连接器将根据import伪指令生成的连接信息,找到所需动态库,并自动导入外部函数符号,代码如下:
;cmd> nasm -fobj -Xvc sayhello.asm
;cmd> alink -oPE -subsys windows sayhello.obj
import MessageBoxA user32.dll
extern MessageBoxA
import ExitProcess kernel32.dll
extern ExitProcess
global SayHello
export SayHello
[SECTION CODE USE32 CLASS=CODE]
szTitle:
db "SayHello",0
szMsg:
db "Hello World!", 0
SayHello:
push 0 ;uType
push dword szTitle ;lpCaption
push dword szMsg ;lpText
push 0 ;hWnd
call [MessageBoxA]
ret 16
..start:
call SayHello
push 0
call [ExitProcess]
上述代码段中的..start也是NASM针对OMF格式设计的程序入口简化标志,export伪指令生成的导出指令也将由alink.exe来执行。注意:alink.exe不支持段合并(至少我不知道如何使用alink.exe进行段合并>_<),因此,连接生成的EXE程序稍大一些,为2.51kb,有3个段,而上述另两种操作生成的EXE文件只有一个.text段。