【X86_64】函数调用栈原理

398 阅读2分钟

一、源代码

#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 0x1,0x4(400510:c745f802000000movl0x1,-0x4(%rbp)<br> 400510: c7 45 f8 02 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位寄存器

1664位寄存器分别是:%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 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值

2.%rip表示执行到这条指令时pc的值,也就是当前指令地址

五、X86_64 AT&T汇编指令语法

www.cnblogs.com/ym65536/p/4…