• 函数调用参数传递


    在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
    ", 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
    "
            .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
     做为参数 放在%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
  • 相关阅读:
    Assembly 学习随笔——第一章
    实验 9 根据材料编程
    实验五 编写、调试具有多个段的程序
    汇编实验四 [bx]和loop的使用
    汇编实验 三 编程、编译、连接、跟踪
    汇编实验二 用机器指令和汇编指令编程
    实验一 查看CPU和内存,使用机器语言和汇编语言进行编程
    汇编第一章
    sqlmap的安装
    sql注入-输入’or 1=1#
  • 原文地址:https://www.cnblogs.com/taek/p/7492579.html
Copyright © 2020-2023  润新知