x86-64 下函数参数传递, 汇编层面分析

To pass parameters to the subroutine, we put up to six of them into registers (in order: rdi, rsi, rdx, rcx, r8, r9). If there are more than six parameters to the subroutine, then push the rest onto the stack in reverse order (i.e. last parameter first) – since the stack grows down, the first of the extra parameters (really the seventh parameter) parameter will be stored at the lowest address (this inversion of parameters was historically used to allow functions to be passed a variable number of parameters).


C main

int main(){
    int result = 0;
    result = testArgs(1,2,3,4,5,6,7,8);
    return 0;

Asm main

gcc -o main main.c

        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    $0, -4(%rbp) //result
        pushq   $8 // 最后一个参数
        pushq   $7 // 倒数第二个参数
        movl    $6, %r9d // 第六个参数
        movl    $5, %r8d // 第五个参数
        movl    $4, %ecx // 第四个参数
        movl    $3, %edx // 第三个参数
        movl    $2, %esi // 第二个参数
        movl    $1, %edi // 第一个参数
        call    testArgs(long, long, long, long, long, long, long, long)
        addq    $16, %rsp // 回收分配的栈空间
        movl    %eax, -4(%rbp)
        movl    $0, %eax

C testArgs

int testArgs(long a1,long a2,long a3,long a4,long a5,long a6,long a7,long a8){
    long sum = 0;
    sum = a1 + a2 + a3 + a4 +a5 + a6 + a7 + a8;
    return sum;

Asm testArgs

testArgs(long, long, long, long, long, long, long, long):
        pushq   %rbp
        movq    %rsp, %rbp
        movq    %rdi, -24(%rbp) ; a1  栈底
        movq    %rsi, -32(%rbp) ; a2
        movq    %rdx, -40(%rbp) ; a3
        movq    %rcx, -48(%rbp) ; a4
        movq    %r8, -56(%rbp)  ; a5
        movq    %r9, -64(%rbp)  ; a6
        movq    $0, -8(%rbp)    ; sum
        movq    -24(%rbp), %rdx ; a1
        movq    -32(%rbp), %rax ; a2
        addq    %rax, %rdx      ; rdx = a1 + a2
        movq    -40(%rbp), %rax ; a3
        addq    %rax, %rdx
        movq    -48(%rbp), %rax ; a4
        addq    %rax, %rdx
        movq    -56(%rbp), %rax ; a5
        addq    %rax, %rdx
        movq    -64(%rbp), %rax ; a6
        addq    %rax, %rdx
        movq    16(%rbp), %rax  ; a7,其实是到 main 的栈帧里取的
        addq    %rax, %rdx
        movq    24(%rbp), %rax  ; a8,其实是到 main 的栈帧里取的
        addq    %rdx, %rax
        movq    %rax, -8(%rbp)  ; sum = rax
        movq    -8(%rbp), %rax  ; rax = sum 也就是返回值
        popq    %rbp



x86-64-arguments-pass #(x86-64-arguments-pass)

上图是执行完 testArgs 前两句汇编的栈帧状态图. 分析: testArgs 中 movq 16(%rbp), %rax // 将 rbp + 16 地址处的数值(a7)复制到 rax rbp + 16 的原因是: 参数 a7 是 main 准备的, 属于 main 的栈帧. 16 Bytes 包括 8 Bytes 的 Return address 和 8 Bytes 的 main 的 rbp.


  1. callee-caller