pop是什么意思c语言(C++|从汇编的角度理解函数调用与参数传递)

调用者调用被调用者,编译器要考虑它们的独立性和相互联系。

一方面,通过传递参数(值或地址)和函数返回(值或地址),建立两段代码之间的联系。地址传输也会产生副作用。

(C++)的引用参数也是一种寻址,只不过编译器会自动对值进行寻址和解引用。)

另一方面,调用函数和被调用函数框架都有自己的函数栈框架,但是它们之间的地址空是透明的(调用函数可以通过被调用函数栈框架上的地址间接访问被调用函数栈框架上的空)。

调用函数调用被调用函数时,会有对参数的压栈操作,无论是值传递还是地址传递。但是值压和地址压的操作略有不同(后面会从组装的角度来分析)。参数堆栈后,调用的函数体对参数的操作就是stack pressing 空之间的引用。当然,解析成assembly后对值和地址的引用会有所不同,后者会增加。

演示:

# include & ltstdio.h & gt int _ _ cdeclcallee (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 =被调用方(&a,b,d);//函数被调用时会寻址或寻址,参数通过堆栈形成复制机制 printf(& # 34;% dn & # 34,c); } int main() // main被操作系统调用,在调用其他函数之前不会执行其他函数。 // main函数通常作为被调用的函数 /main函数中定义的变量也是局部变量 {[/h getchar(); 返回0; } demo中的主调用函数是caller,被调用的函数是callee。

1通话约定

调用协议主要定义了主调用函数和被调用函数对于堆栈平衡的分工,以及参数堆栈顺序的规定。

2.调用方栈框架空的建立

9: void caller() 10: { 00401090 push ebp// ebp压栈,届时局部变量会压在ebp之上(低地址方向,栈往低地址方向增长) 00401091 mov ebp,esp 00401093 sub esp,50h// 局部变量使用的空间,编译器会计算局部变量的需求(适当增加)而不同 00401096 push ebx// 为保持寄存器状态而额外使用的栈空间(50h以外) 00401097 push esi 00401098 push edi 00401099 lea edi,[ebp-50h] 0040109C mov ecx,14h 004010A1 mov eax,0CCCCCCCCh// debug模式时,会将50h的空间全部置0ch 004010A6 rep stos dword ptr [edi]


9:void caller() 10:{ 00401090推EBP//ebp栈,那么局部变量会压在EBP上面(低位地址方向,栈会往低位地址方向增长) 00401091局部变量使用的MOVEBP,ESP 50h/空编译器会计算局部变量的需求(适当增加),这和 00401096推ebp不同

3.主音函数的呼叫者局部变量堆栈

11: int a=3,b=4,d=2; 004010A8 mov dword ptr [ebp-4],3// 局部变量地址以ebp为基准,向低地址方向增长 004010AF mov dword ptr [ebp-8],4 004010B6 mov dword ptr [ebp-0Ch],2


11: int a=3,b=4,d = 2; 004010 A8 MovDword ptr[ebp-4],3//局部变量的地址以ebp为基准,向低位地址增长 004010 afmovdword ptr[EBP-8],4 004010B6 MovDword ptr [EBP]

4函数调用(参数堆栈)和返回

12: int c =被调用者(&a,b,d);//函数调用时会寻址或寻址,参数通过过压栈形成复制机制 004010 BD moveax,DWORPTR [EBP-0CH]//d赋给eax寄存器,注意这是MOV,值赋值(或值传递) 004010 c0 push eax//d push stack 004010 C1 lea ecx,[ebp-8] // b的地址赋给ECE 地址分配(或地址转移) 004010C4推送ecx/& b堆栈 004010c5alea EDX,将[ebp-4] // a的地址分配给edx 004010C8推送EDX/& a堆栈 004010C9 Call @ ILT+20(被调用者)(00401019)//这里需要输入函数调用 004 0Ch //函数在调用完成后返回这里。根据__cdecl协议,主调函数的平衡参数account空 004010 D1 movdword ptr[EBP-10h],eax//的返回值存放在寄存器eax中。c返回到主调优函数注意到,上面的引用地址和指针地址是相同的。



对于可以存储在寄存器中的返回值,通常通过eax返回;对于浮点数,通常通过浮点栈的寄存器返回;对于复合类型,主调优函数的local 空之间会规划一个block 空来存储返回值,这个block 空的第一个地址会在压完参数后压在堆栈框架上。

调用函数名

推送返回地址(EIP)+jmp函数地址

(EIP指向下一条指令)

(1)将程序当前执行位置IP的下一个地址压入堆栈;

(2)转移到被调用的子程序。

pop是什么意思

5呼叫者呼叫呼叫者

@ILT+5(?被调用者@ @ yahpahah @ z): 0040100a JMP被调用者(00401030)编译器将堆栈返回地址004010CE,此时堆栈帧空为:



6调用函数栈frame 空

2: int __cdecl callee(int *a, int &b, int d) // __cdecl是函数调用约定,是略写时的默认调用约定 3: { 00401030 push ebp 00401031 mov ebp,esp 00401033 sub esp,44h 00401036 push ebx 00401037 push esi 00401038 push edi 00401039 lea edi,[ebp-44h] 0040103C mov ecx,11h 00401041 mov eax,0CCCCCCCCh 00401046 rep stos dword ptr [edi]


2: int _ _ cdeclcallee (int * a,int&b,int d)/___ cdecl是函数调用约定,缩写为 时默认调用约定3:{ 00401030 push ebp 00401031 movebp。esp 00401033 sub esp,44h 00401036 push ebx 00401037 push ESI 00401038 push EDI 00401039 lea EDI,[ebp-44h] 0040103C mov ecx,11h 00401041 mov eax,001

7被调用方函数体对参数的引用

4:int t = * a; 00401048 movax,dword ptr[EBP+8] 0040104 B mov CX,Dword ptr[eax]//取消引用并给A赋值 040104d movdord ptr [EBP-4],ecc 00401050 MOVEDX,Dword ptr[EBP+0CH] 00401053 MOVEAX,Dword 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],EDX 7: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,Dwptr [EDX] 8:}注意上述程序集中的值的直接引用。对于通过引用和指针传递的变量,先引用地址,再通过地址解引用。



8被调用函数负责的部分的栈平衡。

0401075 POPEDI 00401076 pope si 00401077 pope bx 00401078 EBP MOVESP 0040107 a pope BP//相当于C语言中的ebp = * espEsp += 4 0040107B ret //相当于pop EIP

-结束-

您可以还会对下面的文章感兴趣

使用微信扫描二维码后

点击右上角发送给好友