0
点赞
收藏
分享

微信扫一扫

stdcall _cedel _fastcall函数调用


首先看一下堆栈框架,是这样的:

;**********************************************
TITLE 两个数的加法(堆栈传递参数)
;**********************************************


;**********************************************
;程序运行平台
.386
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE
;**********************************************


;**********************************************
;文件包含
INCLUDE Irvine32.inc
;**********************************************

;**********************************************
;数据段定义
.DATA
val1 dword 5;
val2 dword 11;
;**********************************************

;**********************************************
;代码段定义
.CODE
;+++++++++++++++++++++++++++++++++++++++++++++
;函数描述:通过堆栈传递参数
;返回值:操作结果放在eax当中
addTwo proc
push ebp;
mov ebp,esp
xor eax,eax
xor ebx,ebx
mov eax,[esp+8]
mov ebx,[esp+12]
add eax,ebx
pop ebp
ret
addTwo endp
;+++++++++++++++++++++++++++++++++++++++++++++

main proc
push val1;
push val2;
call addTwo;
call DumpRegs
exit
main endp
end main
;**********************************************

PS:函数调用时会遵循这样的顺序,

1.首先是实参入栈,

2是函数返回值,(其含义就是函数调用完毕之后的下一条指令的地址)

3是函数ebp

也就是说,如果想要获得传递进来的参数的话,第一个参数应该在[esp+8]的位置上,[esp]中的数据是ebp,[esp+4]是函数的返回值,[esp+8]则是第一个参数,或者说是最后

一个压入堆栈的参数,然后进行操作完成之后,pop ebp;然后则是ret指令,一般其后面的参数应该是堆栈中实参的长度,即 ret 8

这样其上的就是

(IP)=((ss)*16+(sp))

(sp)=(sp)+2

在32位保护模式下则应该是(sp)=(sp)+4

当然这是ret不带操作数时的解读,当是ret 8时则是说明当ip中的地址已经被堆栈中函数返回值更新之后,废除堆栈中的8个字节

好了,这是完整的堆栈框架

现在呢看看三种函数调用

_cdecl函数调用,会将函数名称是这样更换的  _函数名称,这样就完了,因为我们看到没有函数参数长度,所以也就无法将堆栈清理掉,因而堆栈的清理工作只能放在调用该函

数的调用者上

_stdcall函数调用,首先会将函数名称修改为 _函数名称+@+参数长度,这样我们就看到了,这里面有了函数参数长度,因而,堆栈清理工作可以在被调用的函数当中了

_fastcall,该函数声明方式,会将函数名称为 @函数名称+@参数长度,您也许会问,这样一来_stdcall和_fastcall除了函数名称的变化,还有什么区别呢?其含义就是该函数的

第一个参数和第二个参数是在ecx和edx当中的,参数长度减去了ecx和edx中的

还有一项就是ebp和esp的值,我们知道在函数执行过程中有一个函数基址的问题,当前函数的基址就是调用该函数的经过实参压栈和压入函数返回值之后的堆栈地址,我们表

示函数基址的是ebp,而在调用函数中ebp也是做此作用的,我们要先将ebp保护起来,即push ebp,然后使用当前的esp作为ebp,来进行操作

函数执行完毕之后在将ebp的值恢复即可

;**********************************************
TITLE 两个数的加法(堆栈传递参数)
;**********************************************


;**********************************************
;程序运行平台
.386
.MODEL FLAT,STDCALL
OPTION CASEMAP:NONE
;**********************************************


;**********************************************
;文件包含
INCLUDE Irvine32.inc
;**********************************************

;**********************************************
;数据段定义
.DATA
val1 dword 5;
val2 dword 11;
;**********************************************

;**********************************************
;代码段定义
.CODE
;+++++++++++++++++++++++++++++++++++++++++++++
;函数描述:通过堆栈传递参数
;返回值:操作结果放在eax当中
addTwo proc uses ecx edx
push ebp;
mov ebp,esp
xor eax,eax
xor ebx,ebx
mov eax,[esp+16]
mov ebx,[esp+12]
add eax,ebx
pop ebp
ret
addTwo endp
;+++++++++++++++++++++++++++++++++++++++++++++

main proc
push val1;
push val2;
call addTwo;
call DumpRegs
exit
main endp
end main
;**********************************************
PS


uses 伪指令会将 edx和ecx也压入堆栈,但是这样一来 想要获得第一个参数,就不那么容易了,或者说[esp+8]就不对了,因为ecx,edx这次也压入了堆栈,所以要使用

[esp+16]来进行获得,值得注意的是使用uses ecx edx 的时候压入堆栈的顺序是自右向左的,这点要注意

举报

相关推荐

0 条评论