关于函数的默认格式

函数名:

push   ebp

mov    ebp, esp

sub    esp, xx

.

.

.

leave

ret

 

第一,前3句虽然可以用enter x,0来替代,但enter指令的开销比较大,没有这几个指令的效率高,而且enter指令中的嵌套我们是用不到的。

第二,leave指令就是 mov  esp,ebp ; pop ebp 这个条指令,这个指令一条就有两条指令的功能,效率要高一点,少了取指令的时间。

第三,函数不保存寄存器里的值,退出也不恢复,有需要调用者有义务自己保存;

第四,参数由函数弹出,如果调用者需要查看参数的变化,请记住参数已在堆栈指针之上。调用者有义务保证函数的参数个数的正确性。

第五,函数默认为远调用,在对参数的读取上采取的是远调用的方法。

 

其中 第三行指令为开避局部存储空间,即局部变量。注意,xx为4的倍数,以便数据对齐。

 

低位> |--------|

         |    0    |

         |    0    |

         |  局部  |< esp

         |  变量  |

         |  ebp  |< ebp

         |  eip   |

         |   cs    |

         |  参数  |

高位> |--------|

 

取参数为 dword [ebp+12+x*4] ,x 为参数序号,以0开始,最后的参数先入栈,第一个参数最后入栈。

取局部变量为 dword [ebp-4-x*4],x 为局部变量序号,以0开始。

在读取参数与局部变量时,可以在函数开始处定义宏,返回前取消宏定义,以方便阅读。

如:

%define   _$InC01  dword  [ebp+12]   ; 定义为第一个参数

%define   _$Loc01  dword  [ebp-4]      ; 定义为第一个局部变量

在ret前

%undef    _$InC01

%undef    _$Loc01

 

以上的默认格式在实际运用过程中发现有些问题,改为


;###########################################################################################
; 子程序,此代码适用于中汇或nasm
;###########################################################################################
; 参数  :
; 返回值:
;------------------------------------------------------------------------------------------
%macro  @pro    1
        push    %1
        call    _@pro
        add     esp, 4
%endmacro
;------------------------------------------------------------------------------------------
align   4
_@pro:
        pushad
        mov     ebp, esp
        %define     _#@参数1 [ebp+36]
        ; 局部变量定义
        ; sub   esp, 4
        ; %define     _#@变量1 [ebp-4]
        ;----------------------------------------------------------------------------------
        ; 代码从这里开始


        ;----------------------------------------------------------------------------------
    .end:
        %undef      _#@参数1
        ; %undef      _#@变量1
        ; mov     [ebp+36], eax     ; 返回值
        mov     esp, ebp
        popad
        ret
;===========================================================================================

首先定义一个宏,方便函数的调用,同时也兼容C语言的调用,在函数体内的pushad、popad是保证了各寄存器的正常使用与恢复,而上面用到的

push ebp

mov ebp, esp

...

leave

则被改为

mov ebp, esp

...

mov esp, ebp

是因为在pushad中已经将ebp入栈,不需再入一次,同时减少一个指令,可以提高代码运行的效率,所以在函数体内ebp是不得修改的,只用于参数与局部变量的提取。

 

PS: 由于pushad 的执行效率问题,C语言没有使用,就是因为堆栈的开销太大了,而且每次需要入栈8个寄存器,所以不用。看到以前上面写的东西觉得自己好傻好天真。呵呵!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值