将高级语言中定义的函数,被编译位汇编代码执行时,会被编译为一堆指令的集合,用来实现特定的功能,并获得执行后的结果。如果不关注函数中的具体实现,就可以将一个函数看作一个整体,函数调用过程等同于执行了一个操作,只不过这个操作比较复杂而已。
汇编中实现一个函数可以使用JMP 和 CALL 指令完成。
函数是一堆完成特定功能的指令集,这些指令集同样需要按照顺序依次执行,所以只要知道函数执行的第一条指令的地址(函数的首地址),函数将会依次执行这些指令,完成函数。
我们使用C语言实现简单的加法函数
函数分为带参函数和无参函数,对于无参函数,直接使用CALL指令跳转到函数首地址然后开始执行即可,并且CALL指令会将下一行指令地址入栈保存,用于函数结束返回时跳回到原地址。
// 函数体 首地址 指令 00401019 ADD EAX, 4
0040101D RETN // 将栈中的地址 00401038 取出, 赋值给ESI,下次执行回到00401038地址处执行
... ... 00401034 CALL 00401019 // 将下一行指令地址 00401038存入栈空间,然后执行 00401019地址处的函数
00401038 ...
如果函数带参数,我们使用C语言实现简单的加法函数为例
int add(int x, int y) { int z = 0; z = x + y; return z; } void main() { int x = 1; int y = 2; int z; z = add(x, y) }
该函数执行时可以分为以下的步骤。
上面是执行过程,汇编代码为。
// 主程序入口 。。。 push 1 push 2 call 0040107D -- 调用函数 add esp, 8 -- 清楚堆栈中的参数值,恢复堆栈
-- 执行结果在eaxz中,需要使用时,获取即可 。。。
// 此处为函数首地址为 0040107D push ebp -- 堆栈提升,保存原ebp值,然后将esp赋值给esp mov ebp, esp sub esp, 40h push ebx push esi push edi mov eax, 0 add eax, ptr ds:[ebp+8] add eax, ptr ds:[ebp+c] pop edi pop esi pop ebx add esp, 40h cmp ebp esp -- 比较esp和ebp是否相同,清除栈信息后应该相,否则说明栈中的内容没有被清除。堆栈不平衡 pop ebp -- 从栈中取出原ebp值,存入ebp即恢复原ebp值 ret
函数执行过程中的堆栈空间是在函数执行时才分配的,这里发生了一次堆栈提升,所以我们总是说函数执行时有独立的栈空间,也是通过这种方式实现。函数执行前后始终需要保证堆栈平衡。
总结函数的执行过程
原文:https://www.cnblogs.com/k5210202/p/13368280.html