1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| # 默认是gnu风格汇编,这里改成intel风格 objdump -M intel -d test
# 这里只列出了关键的与c代码匹配的汇编,其他段暂时不相关 0000000000001149 <sum>: 1149: f3 0f 1e fa endbr64
# 保存上个栈帧的起始地址 114d: 55 push rbp
# 新建栈帧 114e: 48 89 e5 mov rbp,rsp
# 把第一个参数拷贝到栈上 # 细心的人,起始会发现一个问题,这里少移动rsp的动作,还没分配栈空间,就写入数据?其实这里利用了 x86_64 ABI 的 红区(Red Zone) 特性 # 因为sum函数中,没有调用其他函数,所以被称为叶子函数,所以栈顶下面的128字节是安全区,内核和信号处理不会破环,编译器为了少一条指令,所以去掉了分配的动作 1151: 89 7d fc mov DWORD PTR [rbp-0x4],edi # 把第二个参数拷贝到栈上 1154: 89 75 f8 mov DWORD PTR [rbp-0x8],esi 1157: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] 115a: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8] # eax=eax+edx # 按规范,eax被用作函数返回值 115d: 01 d0 add eax,edx
# 切回到上个栈帧 115f: 5d pop rbp
# ret是call的逆操作 # ret指令相当于如下操作: # pop rip ; 弹出返回地址,跳回 main # 相当于 # 1. rip=rsp # 2. rsp=rsp-0x8 这行就是把1185的call指令保存的rip的位置释放掉 1160: c3 ret
0000000000001161 <main>: # 没球用 1161: f3 0f 1e fa endbr64
# 把rbp压栈,rbp保存的是当前栈帧的起始地址, # 当内核加载完程序后,因为main函数并不是第一个被调用的函数,所以也是要返回到上层栈帧的,所以要先保存rbp的值到栈顶。 1165: 55 push rbp
# 把rsp保存到rbp中,相当于创建新栈帧 1166: 48 89 e5 mov rbp,rsp
# rsp=rsp-0x10, 在栈上分配16字节 # 因为栈底在高地址,所以rsp向下移动,表示分配栈空间 1169: 48 83 ec 10 sub rsp,0x10
# 给[rbp-0xc]块内存写入0xa,占用大小为4字节,DWORD(即double word),即a=10 116d: c7 45 f4 0a 00 00 00 mov DWORD PTR [rbp-0xc],0xa
# 给[rbp-0x8]块内存写入0x14, 即a=20 1174: c7 45 f8 14 00 00 00 mov DWORD PTR [rbp-0x8],0x14
# 让edx=0x14 117b: 8b 55 f8 mov edx,DWORD PTR [rbp-0x8] # 让eax=0xa 117e: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc] # 前面4条指令,都是废话,起始可以直接给esi和edi赋值的 # 之所以要给这俩寄存器赋值,是为了要为函数调用传参,edi是第一个参数,esi是第二个参数 # 让esi=0x14 1181: 89 d6 mov esi,edx # 让edi=0xa 1183: 89 c7 mov edi,eax
# 终于调用到sum函数了 # 这里的call指令相当于如下两个步骤 # push rip ; 压入返回地址 # jmp sum ; 跳转到 sum # 这里是跳转到1149,1149是相对地址 # info proc mappings 可以查看基地址, 或者在gdb调试时,可以看到call 0x555555555149, 0x555555555149=0x555555554000+1149 1185: e8 bf ff ff ff call 1149 <sum>
# 把eax返回值,写入到栈上 118a: 89 45 fc mov DWORD PTR [rbp-0x4],eax 118d: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
# 下面是调用printf函数 # 把eax做为第二个参数 1190: 89 c6 mov esi,eax
# 计算一个地址,放入eax 1192: 48 8d 05 6b 0e 00 00 lea rax,[rip+0xe6b] # 2004 <_IO_stdin_used+0x4> # 把填入rdi,作为第一个参数 1199: 48 89 c7 mov rdi,rax # eax=0x0 119c: b8 00 00 00 00 mov eax,0x0
# 调用printf 11a1: e8 aa fe ff ff call 1050 <printf@plt> # 把main函数的返回值设为0 11a6: b8 00 00 00 00 mov eax,0x0
# ? 11ab: c9 leave
# main函数返回,与sum函数退栈帧没区别 11ac: c3 ret
|