NASM 与 MASM 在函数编写上的区别

NASM 与 MASM 在函数编写上的区别

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;C/CPP 程序 demo.cpp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include

#ifdef __cplusplus
extern "C"
{
#endif
 
 extern void _stdcall _nasm(int *val);
 extern void _stdcall _masm(int *val);
 
#ifdef __cplusplus
};
#endif

int main(int argc, char* argv[])
{
 int val = 1;

 _nasm(&val);
 printf("nasm: %d/n",val);

 _masm(&val);
 printf("masm: %d/n",val);

 return 0;
}

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;nasm.asm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
cpu 386
[section .data]
$var1 db 1

[section .text]
 global __nasm@4 ;函数声明,只有声明后函数才是公有的这样在C/CPP中才能访问才可被链接器识别

__nasm@4:
    push ebp
    mov ebp,esp

 mov edi,[esp+8]
 mov eax,[$var1]
 mov [edi],eax     ; 写到edi所指向的地址内(通过[]寻址方式)

 leave
 ret 4

;=============================================================================
;注:
;若使用stdcall调用约定,则需要手工加上__原函数名@参数长度,否则链接程序无法识别此函数(C调用约定则不需要)
;=============================================================================

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;masm.asm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none

_masm PROTO,PVal:PTR DWORD;函数声明,只有声明后函数才是公有的这样在C/CPP中才能访问,才可被链接器识别

.data
 var1 dd 2
.code
_masm PROC PVal:PTR DWORD
; 编译器自动加上:
;   push ebp
;   mov ebp,esp
;   对于内存变量(全局变量和局部变量),无论是否时确用[],MASM都会隐式加上[内存变量/局部变量]内存寻址方式
;   只有offset 全局变量 / lea 局部变量 才可以返回内存地址

 mov edi,[PVal]; 与 mov edi,PVal 结果一样
 mov eax,[var1]; 与 mov eax,var1 结果一样
 mov [edi],eax  ; 写到edi所指向的地址内内(通过[]寻址方式)
 ret    
;  ret 自动变为
;  leave
;  ret 4

_masm ENDP

end

;=============================================================================
;注:
; MASM 的 Proc 定义
; 起始:编译器自动加上
; push ebp
; mov ebp,esp
; 结束:编译器在ret语句前,自动加上leave,如果调用约定中规定由函数调整堆栈指针,则自动在ret后加上参数的总字节长度
; leave   
; ret n
; 使用stdcall调用约定时,编译器隐式将函数名改为 _原函数名@参数长度,所有不需要手工加上(加上反而错)
; 默认情况下MASM的PROC 定义为公有的,可以在PROC 后直接跟上范围限制的标记如PRIVATE
;=============================================================================

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;汇编后代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;demo.cpp
22:       _nasm(&val);
0040103F   lea         eax,[ebp-4]
00401042   push        eax
00401043   call        __nasm@4 (004010a0)

;nasm.asm
__nasm@4:
004010A0   push        ebp
004010A1   mov         ebp,esp
004010A3   mov         edi,dword ptr [esp+8]
004010A7   mov         eax,[___xt_z+104h (00424a30)] ; 全局变量
004010AC   mov         dword ptr [edi],eax
004010AE   leave
004010AF   ret         4

--------------------------------------------------------------------------------

;demo.cpp
25:       _masm(&val);
00401059   lea         edx,[ebp-4]
0040105C   push        edx
0040105D   call        @ILT+0(__masm@4) (00401005)

@ILT+0(__masm@4):
00401005   jmp         __masm@4 (004010b8)

;masm.asm
__masm@4:
004010B8   push        ebp
004010B9   mov         ebp,esp
004010BB   mov         edi,dword ptr [ebp+8]
004010BE   mov         eax,[___xt_z+108h (00424a34)] ; 全局变量
004010C3   mov         dword ptr [edi],eax
004010C5   leave
004010C6   ret         4

总结:
用Nasm编写的汇编程序最接近编译后的程序,因为MASM的汇编器虽然在源码上方便了程序的代码编写操作,但隐藏太多底层的细节

 

你可能感兴趣的:(ASM)