NASM、MASM浅谈

     NASM汇编器和MASM汇编器一样,都可以生成适用于Win32平台的coff文件格式,这种文件格式可以被MS 的link.exe连接器连接成PE文件。通常,我们知道MASM可以通过includelib伪指令将导入库的名称传给连接器link.exe,告知它该从哪个库中导入所需外部符号,而NASM汇编器在这方面的能力却是有过之而无不及,它可以通过info段,将更多的连接参数传递给link.exe,下面的两段代码展示了两者之间的用法和差异:

; filename: sayhellon.asm
;
;
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段,代码如下:

; filename:sayhellom.asm
;
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伪指令生成的连接信息,找到所需动态库,并自动导入外部函数符号,代码如下:

; filename:sayhello.asm
;
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段。

你可能感兴趣的:(ASM)