一、源代码
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main(void)
{
int c, a = 1, b = 2;
c = add(a, b);
return c;
}
二、X86_64汇编指令
int add(int a, int b)
{
4004ed: 55 push %rbp
4004ee: 48 89 e5 mov %rsp,%rbp
4004f1: 89 7d fc mov %edi,-0x4(%rbp)
4004f4: 89 75 f8 mov %esi,-0x8(%rbp)
return a + b;
4004f7: 8b 45 f8 mov -0x8(%rbp),%eax
4004fa: 8b 55 fc mov -0x4(%rbp),%edx
4004fd: 01 d0 add %edx,%eax
}
4004ff: 5d pop %rbp
400500: c3 retq
0000000000400501 <main>:
int main(void)
{
400501: 55 push %rbp
400502: 48 89 e5 mov %rsp,%rbp
400505: 48 83 ec 10 sub $0x10,%rsp
int c, a = 1, b = 2;
400509: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
400510: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
c = add(a, b);
400517: 8b 55 f8 mov -0x8(%rbp),%edx
40051a: 8b 45 fc mov -0x4(%rbp),%eax
40051d: 89 d6 mov %edx,%esi
40051f: 89 c7 mov %eax,%edi
400521: e8 c7 ff ff ff callq 4004ed <add>
400526: 89 45 f4 mov %eax,-0xc(%rbp)
return c;
400529: 8b 45 f4 mov -0xc(%rbp),%eax
}
三、X86_64栈结构变化
int main(void)
{
// 将当前rbp(上一个函数的基址)的值压栈,rsp自减(因为是X86_64,rbp是64位的,所以会占8字节)
400501: 55 push %rbp
// 将rsp的值赋值给rbp
400502: 48 89 e5 mov %rsp,%rbp
// sp开栈空间16字节
400505: 48 83 ec 10 sub $0x10,%rsp
// 将1、2参数放到栈空间中<br>
400509: c7 45 fc 01 00 00 00 movl 0x2,-0x8(%rbp)
// 将1,2从栈空间赋值给edx和eax,再将edx和eax的值赋值给esi和edi寄存器<br>
400517: 8b 55 f8 mov -0x8(%rbp),%edx
40051a: 8b 45 fc mov -0x4(%rbp),%eax
40051d: 89 d6 mov %edx,%esi
40051f: 89 c7 mov %eax,%edi
// 调用add函数
400521: e8 c7 ff ff ff callq 4004ed
// 将add计算结果放入栈帧
400526: 89 45 f4 mov %eax,-0xc(%rbp)
// 将main函数的计算结果存入返回值寄存器eax中<br>
400529: 8b 45 f4 mov -0xc(%rbp),%eax
}
四、X86_64寄存器作用
1.X86-64有16个64位寄存器
16个64位寄存器分别是:%rax,%rbx,%rcx,%rdx,%rsi,%rdi,%rbp,%rsp,%r8,%r9,%r10,%r11,%r12,%r13,%r14,%r15
%rax 作为函数返回值使用。
%rsp 栈指针寄存器,指向栈顶
%rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数。。。
%rbx,%rbp,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改
%r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值