X86汇编层面的方法调用。


本文主要描述了X64下的汇编层面的方法调用。具体来说就是一个C语言的方法被另外一个方法调用,是如果在汇编语言X64的规范中实现的。

1.假设有如下C语言文件 “test.c”

点击查看代码
int sumNine(int one, int two, int three, int four, int five, 
          int six, int seven, int eight, int nine) 
{ 
    int x;  
	x = one + two + three + four + five + six + seven + 
	eight + nine; 
    return x; 
}


int main(void) 
{ 
    int total; 
    int a = 1; 
    int b = 2; 
    int c = 3; 
    int d = 4; 
    int e = 5; 
    int f = 6; 
    int g = 7; 
    int h = 8; 
    int i = 9; 
    total = sumNine(a, b, c, d, e, f, g, h, i); 
    return 0; 
}

2.通过GCC 命令 “gcc -o test.s -fverbose-asm -S -O0 -g test.c” 查看生成的汇编语言

点击查看代码
main:
        endbr64
        pushq   %rbp    #
        movq    %rsp, %rbp      #,
        subq    $48, %rsp       #,
# test.c:14:     int a = 1;
        movl    $1, -40(%rbp)   #, a
# test.c:15:     int b = 2;
        movl    $2, -36(%rbp)   #, b
# test.c:16:     int c = 3;
        movl    $3, -32(%rbp)   #, c
# test.c:17:     int d = 4;
        movl    $4, -28(%rbp)   #, d
# test.c:18:     int e = 5;
        movl    $5, -24(%rbp)   #, e
# test.c:19:     int f = 6;
        movl    $6, -20(%rbp)   #, f
# test.c:20:     int g = 7;
        movl    $7, -16(%rbp)   #, g
# test.c:21:     int h = 8;
        movl    $8, -12(%rbp)   #, h
# test.c:22:     int i = 9;
        movl    $9, -8(%rbp)    #, i
# test.c:23:     total = sumNine(a, b, c, d, e, f, g, h, i);
        movl    -20(%rbp), %r9d # f, tmp84
        movl    -24(%rbp), %r8d # e, tmp85
        movl    -28(%rbp), %ecx # d, tmp86
        movl    -32(%rbp), %edx # c, tmp87
        movl    -36(%rbp), %esi # b, tmp88
        movl    -40(%rbp), %eax # a, tmp89

		pushq   %rdi    # tmp90
        movl    -12(%rbp), %edi # h, tmp91
        pushq   %rdi    # tmp91
        movl    -16(%rbp), %edi # g, tmp92
        pushq   %rdi    # tmp92
        movl    %eax, %edi      # tmp89,
        call    sumNine #

        addq    $24, %rsp       #,
        movl    %eax, -4(%rbp)  # tmp93, total
# test.c:24:     return 0;
        movl    $0, %eax        #, _13
# test.c:25: }
        leave
        ret

sumNine: 
        pushq  %rbp 
        movq  %rsp, %rbp 
        subq  $48, %rsp 
        movl  %edi, -20(%rbp)  # save one 
        movl  %esi, -24(%rbp)  # save two 
        movl  %edx, -28(%rbp)  # save three 
        movl  %ecx, -32(%rbp)  # save four 
        movl  %r8d, -36(%rbp)  # save five 
        movl  %r9d, -40(%rbp)  # save six 
        movl  -24(%rbp), %eax  # load two 
        movl  -20(%rbp), %edx  # load one, subtotal 
        addl  %eax, %edx       # add two to subtotal 
        movl  -28(%rbp), %eax  # load three 
        addl  %eax, %edx       # add to subtotal 
        movl  -32(%rbp), %eax  # load four 
        addl  %eax, %edx       # add to subtotal 
        movl  -36(%rbp), %eax  # load five 
        addl  %eax, %edx       # add to subtotal 
        movl  -40(%rbp), %eax  # load six 
        addl  %eax, %edx       # add to subtotal 
        movl  16(%rbp), %eax   # load seven 
        addl  %eax, %edx       # add to subtotal 
        movl  24(%rbp), %eax   # load eight 
        addl  %eax, %edx       # add to subtotal 
        movl  32(%rbp), %eax   # load nine 
        addl  %edx, %eax       # add to subtotal 
        movl  %eax, -4(%rbp)   # x <- total
        movl  $.LC0, %edi 
        call  puts 
        movl  -4(%rbp), %eax 
        leave 
        ret 


Main函数中allocate了48个字节作为local variable的空间。
在调用sumNine的时候,前面6个需要传输的参数通过设置指定的Register来传输数据[2],多余的3个参数通过插入当前stack的形式来传输数据。(但是这边很奇怪的是48 + 3 * 8 = 72字节,stack pointer (rsp) 并没有16字节对齐,有知道的小伙伴告诉我一下为啥没有16字节对齐也能work)。在被调用的函数中前面6个传输通过register中获取,后面3个参数通过stack来获取。在调用sumNine的时候的Stack如下图所示。所有的参数都是通过8字节传输,并且在最后在stack中插入返回地址。
image
当调用到sumNine里面的时候, stack的样子设置如下。可以通过(rbp+16)拿到传入到函数中的参数,注意stack中包含了Return Address 和 Caller’s rbp,所以需要加16才能拿到数据。
image

Summary

方法间的调用的时候,是通过Register和Stack传输数据的。并且需要返回的地址也会在调用函数的时候被插入。在调用其他函数之前 rbp 和 rsp 之间的数据存放着local variable 和 需要调用其他函数的参数。

Reference

[1] https://bob.cs.sonoma.edu/IntroCompOrg-x64/bookch11.html#x31-13800011

[2]image
[3]image

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/281375.html

(0)
上一篇 2022年8月21日
下一篇 2022年8月21日

相关推荐

发表回复

登录后才能评论