_stdcall 与 _cdecl

以前用过WINAPI,后来做dll也总是习惯于_stdcall,虽然知道C里面用_cdecl的挺多的,还以为只是种习惯声明,直到最近用C#导入C++的dll才发现这两种在原理上实质还是有一定的差别的,又扫盲了。。。

 

_stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。

 

汇编:

push

call

a1    proc   ; stdcall
    push    ebp
    mov     ebp, esp
    mov     eax, dword ptr [ptr+8]
    pop     ebp
    ret     4    ; 
a1    endp
 

_cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。_cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。

目前看到_cdecl的用处在于参数是变长的声明,由于内部无法获知长度,所以只能由调用者做堆栈平衡。_stdcall的优点是少了个指令,节省了空间

汇编:

push

call

a2    proc   ; cdecl方式
    push    ebp    ; 记下上一个栈帧地址
    mov     ebp, esp
    mov     eax, dword ptr [ptr+8]  ; 取第一个参数 
    pop     ebp    ; 恢复栈帧为调用者,但这时候堆栈还未平衡
    ret
a2    endp

add     esp, 4

关于堆栈平衡,对于做开发的人而言,有个惯性思维,堆就是new出来的,栈就是在{}中自动管理的内存,所以认为它的概念是分开的。而真正的概念是 堆是动态划分的内存,而栈是遵从LIFO对堆的一种特殊使用形态,仔细想想是不是如此?任何内存的使用对于操作系统而言都是动态分配的,所以堆栈其实表达的是一个东西。ESP即是这个堆栈栈顶指针寄存器,在CALL之前,首先将要传入的参数PUSH进去,ESP自然就会增长,CALL之后,首先会将当前栈针PUSH进去,ESP同样会增长,栈针(EBP)的作用是通过偏移来使用传入参数以及堆栈中的数据。所以在执行完毕前,首先POP恢复栈针,但此时的传入参数还没有POP,堆栈平衡的意思其实也就是等同于执行n次POP,使其堆栈(ESP)恢复到执行前的状态。。。

这还有个需要记录的地方是,对于栈的增长,内存地址是由高到低的,所以最后恢复是add sdp,4。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值