汇编中函数调用过程中,栈到底是怎样变化的?call、ret、指令分别有什么样的作用?

您所在的位置:网站首页 call指令长度 汇编中函数调用过程中,栈到底是怎样变化的?call、ret、指令分别有什么样的作用?

汇编中函数调用过程中,栈到底是怎样变化的?call、ret、指令分别有什么样的作用?

2023-11-22 11:23| 来源: 网络整理| 查看: 265

1、栈帧的结构:栈帧主要包括三个部分:被保存的%bp,被保存的寄存器、本地变量等,参数区域 2、call指令的作用:

将程序下一条指令的位置的IP压入堆栈中;转移到调用的子程序

3、ret指令的作用:

pop PC,即将栈中%rsp的8个字节数据保存到程序计数器中,并且rsp -= 8(64位机器中)

4、leaveq指令的作用:用来关闭栈帧

mov rbp, rsp:令rsp = rbppop rbp:恢复之前的rbq

4、实际举例:

//test2.c #include int addNum(int a, int b){ int x = a * 10; int y = b *5; int z = x * y; return z; } void foo(int a, int b) { int x = a + 2; int y = b + 1; int z = x * y; addNum(a, b); } int main() { int x = 1, y = 2; foo(x, y); return 0; }

编译并反汇编

gcc -g -o test2 test2.c objdump -S test2 > test2.asm

反汇编文件:

//test2.asm 0000000000001129 : #include int addNum(int a, int b){ 1129: f3 0f 1e fa endbr64 112d: 55 push %rbp 112e: 48 89 e5 mov %rsp,%rbp 1131: 89 7d ec mov %edi,-0x14(%rbp) 1134: 89 75 e8 mov %esi,-0x18(%rbp) int x = a * 10; 1137: 8b 55 ec mov -0x14(%rbp),%edx 113a: 89 d0 mov %edx,%eax 113c: c1 e0 02 shl $0x2,%eax 113f: 01 d0 add %edx,%eax 1141: 01 c0 add %eax,%eax 1143: 89 45 f4 mov %eax,-0xc(%rbp) int y = b *5; 1146: 8b 55 e8 mov -0x18(%rbp),%edx 1149: 89 d0 mov %edx,%eax 114b: c1 e0 02 shl $0x2,%eax 114e: 01 d0 add %edx,%eax 1150: 89 45 f8 mov %eax,-0x8(%rbp) int z = x * y; 1153: 8b 45 f4 mov -0xc(%rbp),%eax 1156: 0f af 45 f8 imul -0x8(%rbp),%eax 115a: 89 45 fc mov %eax,-0x4(%rbp) return z; 115d: 8b 45 fc mov -0x4(%rbp),%eax } 1160: 5d pop %rbp 1161: c3 retq 0000000000001162 : void foo(int a, int b) { 1162: f3 0f 1e fa endbr64 1166: 55 push %rbp 1167: 48 89 e5 mov %rsp,%rbp 116a: 48 83 ec 18 sub $0x18,%rsp 116e: 89 7d ec mov %edi,-0x14(%rbp) 1171: 89 75 e8 mov %esi,-0x18(%rbp) int x = a + 2; 1174: 8b 45 ec mov -0x14(%rbp),%eax 1177: 83 c0 02 add $0x2,%eax 117a: 89 45 f4 mov %eax,-0xc(%rbp) int y = b + 1; 117d: 8b 45 e8 mov -0x18(%rbp),%eax 1180: 83 c0 01 add $0x1,%eax 1183: 89 45 f8 mov %eax,-0x8(%rbp) int z = x * y; 1186: 8b 45 f4 mov -0xc(%rbp),%eax 1189: 0f af 45 f8 imul -0x8(%rbp),%eax 118d: 89 45 fc mov %eax,-0x4(%rbp) addNum(a, b); 1190: 8b 55 e8 mov -0x18(%rbp),%edx 1193: 8b 45 ec mov -0x14(%rbp),%eax 1196: 89 d6 mov %edx,%esi 1198: 89 c7 mov %eax,%edi 119a: e8 8a ff ff ff callq 1129 } 119f: 90 nop 11a0: c9 leaveq 11a1: c3 retq 00000000000011a2 : int main() { c: f3 0f 1e fa endbr64 # rsp = 0x7fffffffdf28 11a6: 55 push %rbp # rsp = 0x7fffffffdf20,rbp=0x0 11a7: 48 89 e5 mov %rsp,%rbp 11aa: 48 83 ec 10 sub $0x10,%rsp # rsp = 0x7fffffffdf10 int x = 1, y = 2; 11ae: c7 45 f8 01 00 00 00 movl $0x1,-0x8(%rbp) 11b5: c7 45 fc 02 00 00 00 movl $0x2,-0x4(%rbp) foo(x, y); 11bc: 8b 55 fc mov -0x4(%rbp),%edx 11bf: 8b 45 f8 mov -0x8(%rbp),%eax 11c2: 89 d6 mov %edx,%esi 11c4: 89 c7 mov %eax,%edi 11c6: e8 97 ff ff ff callq 1162 return 0; 11cb: b8 00 00 00 00 mov $0x0,%eax } 11d0: c9 leaveq 11d1: c3 retq 11d2: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 11d9: 00 00 00 11dc: 0f 1f 40 00 nopl 0x0(%rax)

接着打印关键节点的栈帧情况:

1、11a2: mian函数还没开始运行之前

%rsp = 0x7fffffffdf28 0x7fffffffdf28: 0x00007ffff7dbe0b3 0x0000000000000050 0x7fffffffdf38: 0x00007fffffffe018 0x00000001f7f827a0 0x7fffffffdf48: 0x00005555555551a2 0x00005555555551e0 0x7fffffffdf58: 0x81bfdda5e3d667e4 0x0000555555555040 0x7fffffffdf68: 0x00007fffffffe010 0x0000000000000000

2、11c4: main.c中进入foo函数之前,即callq 1162 之前

0x7fffffffdf10: 0x00007fffffffe010 0x0000000200000001 0x7fffffffdf20: 0x0000000000000000 0x00007ffff7dbe0b3 0x7fffffffdf30: 0x0000000000000050 0x00007fffffffe018 0x7fffffffdf40: 0x00000001f7f827a0 0x00005555555551a2 0x7fffffffdf50: 0x00005555555551e0 0x81bfdda5e3d667e4

3、1162: 刚进入foo函数:由于call指令,将call指令的下一条指令地址压入栈中即0x00005555555551cb

0x7fffffffdf08: 0x00005555555551cb 0x00007fffffffe010 0x7fffffffdf18: 0x0000000200000001 0x0000000000000000 0x7fffffffdf28: 0x00007ffff7dbe0b3 0x0000000000000050 0x7fffffffdf38: 0x00007fffffffe018 0x00000001f7f827a0 0x7fffffffdf48: 0x00005555555551a2 0x00005555555551e0

4、119a: 进入add函数之前:

0x7fffffffdee8: 0x0000000100000002 0x00000003f7f8b2e8 0x7fffffffdef8: 0x0000000900000003 0x00007fffffffdf20 0x7fffffffdf08: 0x00005555555551cb 0x00007fffffffe010 0x7fffffffdf18: 0x0000000200000001 0x0000000000000000 0x7fffffffdf28: 0x00007ffff7dbe0b3 0x0000000000000050

5、1160: pop之前:

0x7fffffffded8: 0x00007fffffffdf00 0x000055555555519f//原来的rbp, 返回地址 0x7fffffffdee8: 0x0000000100000002 0x00000003f7f8b2e8 0x7fffffffdef8: 0x0000000900000003 0x00007fffffffdf20 0x7fffffffdf08: 0x00005555555551cb 0x00007fffffffe010 0x7fffffffdf18: 0x0000000200000001 0x0000000000000000

6、1161: pop之后,ret之前:将8byte数据弹出

0x7fffffffdee0: 0x000055555555519f 0x0000000100000002 0x7fffffffdef0: 0x00000003f7f8b2e8 0x0000000900000003 0x7fffffffdf00: 0x00007fffffffdf20 0x00005555555551cb 0x7fffffffdf10: 0x00007fffffffe010 0x0000000200000001 0x7fffffffdf20: 0x0000000000000000 0x00007ffff7dbe0b3

7、119f: ret之后,程序由addNum函数返回到foo函数

0x7fffffffdee8: 0x0000000100000002 0x00000003f7f8b2e8 0x7fffffffdef8: 0x0000000900000003 0x00007fffffffdf20 0x7fffffffdf08: 0x00005555555551cb 0x00007fffffffe010 0x7fffffffdf18: 0x0000000200000001 0x0000000000000000 0x7fffffffdf28: 0x00007ffff7dbe0b3 0x0000000000000050

8、11d0: leaveq之后:

0x7fffffffdf08: 0x00005555555551cb 0x00007fffffffe010 0x7fffffffdf18: 0x0000000200000001 0x0000000000000000 0x7fffffffdf28: 0x00007ffff7dbe0b3 0x0000000000000050 0x7fffffffdf38: 0x00007fffffffe018 0x00000001f7f827a0 0x7fffffffdf48: 0x00005555555551a2 0x00005555555551e0

9、11cb: foo函数返回之后:

0x7fffffffdf10: 0x00007fffffffe010 0x0000000200000001 0x7fffffffdf20: 0x0000000000000000 0x00007ffff7dbe0b3 0x7fffffffdf30: 0x0000000000000050 0x00007fffffffe018 0x7fffffffdf40: 0x00000001f7f827a0 0x00005555555551a2 0x7fffffffdf50: 0x00005555555551e0 0x60c5e5ac768c82ff


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3