https://m.toutiao.com/is/89vUoUv/?=C++ 主调函数(caller)调用被调函数(callee),编译器要考虑两者的相互独立和相互联系。 一方面通过传递参数(值或址)和函数返回(值或址)来在两段代码之间建立联系。传址还可以形成副作用。 (C++的引用参数也是一种传址,只是编译器做了自动取址和解引用取值的动作。) 另一方面主调函数和被调函数都有各自的函数栈帧(function frame),但两者的地址空间是透明的(主调函数可以通过被调函数栈帧上的地址来间接访问被调函数栈帧上的空间)。 主调函数调用被调函数时,对于参数,不管是传值还是传址,都会有一个压栈操作,但压值和压址的操作稍有不同(后续会从汇编的角度分析),参数压栈后,被调函数体对参数的操作就是对压栈空间的引用,当然,对值的引用和址的引用在解析成汇编后也会不同,后者会增加一个解引用(从地址取值)的动作。 demo: #include <stdio.h>int __cdecl callee(int *a, int &b, int d) // __cdecl是函数调用约定,是略写时的默认调用约定{ int t = *a; *a = b*d; b = t*d; return *a*b;}void caller(){ int a=3,b=4,d=2; int c = callee(&a,b,d); // 函数调用时会传址或传址,参数会通过压栈而形成副本机制 printf('%d\n',c);}int main() // main由操作系统调用而被执行,其它函数要由另外的函数去调用才会被执行, // main函数通常充当被调函数的作用 // main函数内定义的变量也是局部变量{ caller(); getchar(); return 0;} demo中的主调函数是caller,被调函数是callee。 1 调用约定 调用约定主要定义主调函数和被调函数对于堆栈平衡的分工,参数压栈顺序规定等。 2 主调函数caller栈帧空间的建立
3 主调函数caller局部变量压栈 11: int a=3,b=4,d=2;004010A8 mov dword ptr [ebp-4],3// 局部变量地址以ebp为基准,向低地址方向增长004010AF mov dword ptr [ebp-8],4004010B6 mov dword ptr [ebp-0Ch],2 4 函数调用(实参压栈)和返回
注意上述引用传址和指针传址使用了相同的汇编代码。 对于一个寄存器可以存下的返回值,通常通过eax返回,对于浮点数,一般通过浮点栈的寄存器返回,对于复合类型,会在主调函数的局部空间规划出一块空间用来存放返回值,这块空间的首地址会在压完参数后压在栈帧上。
5 caller call caller @ILT+5(?callee@@YAHPAHAAHH@Z):0040100A jmp callee (00401030) 编译器会将返回地址004010CE压栈,此时的栈帧空间是: 6 被调函数栈帧空间建立
7 callee函数体对实参的引用 4: int t = *a;00401048 mov eax,dword ptr [ebp+8]0040104B mov ecx,dword ptr [eax] // 对a的解引用并赋值0040104D mov dword ptr [ebp-4],ecx5: *a = b*d;00401050 mov edx,dword ptr [ebp+0Ch]00401053 mov eax,dword ptr [edx] // 对b的解引用并赋值00401055 imul eax,dword ptr [ebp+10h] // 对b的值的直接引用00401059 mov ecx,dword ptr [ebp+8]0040105C mov dword ptr [ecx],eax6: b = t*d;0040105E mov edx,dword ptr [ebp-4]00401061 imul edx,dword ptr [ebp+10h]00401065 mov eax,dword ptr [ebp+0Ch]00401068 mov dword ptr [eax],edx7: return *a*b;0040106A mov ecx,dword ptr [ebp+8]0040106D mov edx,dword ptr [ebp+0Ch]00401070 mov eax,dword ptr [ecx]00401072 imul eax,dword ptr [edx]8: } 注意以上汇编对值的直接引用,对引用传递和指针传递的变量先是引用地址,然后通过地址来解引用。 8 被调函数负责的自己部分的堆栈平衡
-End- |
|
来自: 山峰云绕 > 《c加加c井号面向对象》