函数调用参数传递

时间:2022-03-05 01:04:22

在64位机下, 函数的前6个参数都是保存在寄存器中,后面的参数才保存在栈中,那可变参数是不是也这样呢?

参考 这里

gdb 调试汇编 参考这里 还有这里

 

ebp 栈底   高地址

esp 栈顶   低地址

 

push %ebp   保存栈底

push %esp %ebp  上一个帧的%esp ,就是本栈的栈底%ebp

....

push %ebp %esp   恢复

pop %ebp

 

#include <stdio.h>
#include <stdlib.h>
int add(int a, int b, int c, int d, int e, int f, int g, int h) { // 8 个参数相加

  int sum = a + b + c + d + e + f + g + h;
  return sum;
}

int main(void) {
  int i = 10;
  int j = 20;
  int k = i + j;
  int sum = add(11, 22,33, 44, 55, 66, 77, 88);
  int m = k; // 为了观察 %rax Caller Save 寄存器的恢复

  return 0;
}

 

 

 

gcc -S print2.c 得到汇编

        .text
.globl add
        .type   add, @function
add:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -20(%rbp)
        movl    %esi, -24(%rbp)
        movl    %edx, -28(%rbp)
        movl    %ecx, -32(%rbp)
        movl    %r8d, -36(%rbp)
        movl    %r9d, -40(%rbp)
        movl    -24(%rbp), %eax
        movl    -20(%rbp), %edx
        leal    (%rdx,%rax), %eax
        addl    -28(%rbp), %eax
        addl    -32(%rbp), %eax
        addl    -36(%rbp), %eax
        addl    -40(%rbp), %eax
        addl    16(%rbp), %eax
        addl    24(%rbp), %eax
        movl    %eax, -4(%rbp)
        movl    -4(%rbp), %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   add, .-add
.globl main
        .type   main, @function
main:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $48, %rsp
        movl    $10, -20(%rbp)
        movl    $20, -16(%rbp)
        movl    -16(%rbp), %eax      //-16(%rbp)的值放到%eax中,即%rdx的低32位中
        movl    -20(%rbp), %edx      //-20(%rbp的值放到%edx中,即%rdx的低32位中
        leal    (%rdx,%rax), %eax    //这里是将 %rdx+%rax的值 放到%eax中
        movl    %eax, -12(%rbp)       //将i+j=k的值 放到-12(%rbp)中
        movl    $88, 8(%rsp) 
        movl    $77, (%rsp)
        movl    $66, %r9d
        movl    $55, %r8d
        movl    $44, %ecx
        movl    $33, %edx
        movl    $22, %esi
        movl    $11, %edi
        call    add
        movl    %eax, -8(%rbp)
        movl    -12(%rbp), %eax
        movl    %eax, -4(%rbp)
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-18)"
        .section        .note.GNU-stack,"",@progbits

 

 

会发现 函数中局部变量的顺序与其在栈中的顺序相反, 

 int i 在栈中的位置是 movl $10, -20(%rbp)

 int j在栈中的位置 是 movl $20, -16(%rbp)

即在栈中先是j, 然后是i

 

再看下可变参数

#include <stdio.h>
#include <stdlib.h>


int test(int a, int b){
        int a2=a;
        int b2=b;
        int c = a2+b2;
        return c;
}
int main(){
        int a=1;
        int b=2;
        int res = test(a, b);
        printf("%d\n", res);
        return 0;

}    

 

其汇编为

        .text
.globl test
        .type   test, @function
test:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -20(%rbp)
        movl    %esi, -24(%rbp)
        movl    -20(%rbp), %eax
        movl    %eax, -12(%rbp)
        movl    -24(%rbp), %eax
        movl    %eax, -8(%rbp)
        movl    -8(%rbp), %eax
        movl    -12(%rbp), %edx
        leal    (%rdx,%rax), %eax //做加法
        movl    %eax, -4(%rbp)
        movl    -4(%rbp), %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   test, .-test
        .section        .rodata
.LC0:
        .string "%d\n"
        .text
.globl main
        .type   main, @function
main:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    $1, -12(%rbp)
        movl    $2, -8(%rbp)
        movl    -8(%rbp), %edx
        movl    -12(%rbp), %eax
        movl    %edx, %esi
        movl    %eax, %edi
        call    test
        movl    %eax, -4(%rbp) //将test函数返回值 存储在-4(%rbp)中
        movl    $.LC0, %eax
        movl    -4(%rbp), %edx
        movl    %edx, %esi     //test函数返回值,即res,做为参数先放到%esi中
        movq    %rax, %rdi     //%rax应该是%d\n 做为参数 放在%rdi中
        movl    $0, %eax
        call    printf         //调用printf函数,说明printf中的前6个参数也是优先放在寄存器中的
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-18)"
        .section        .note.GNU-stack,"",@progbits