首页 > 编程语言 >X86汇编层面的方法调用。

X86汇编层面的方法调用。

时间:2022-08-20 23:36:01浏览次数:128  
标签:汇编 movl 调用 X86 int rbp eax test edx

本文主要描述了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

标签:汇编,movl,调用,X86,int,rbp,eax,test,edx
From: https://www.cnblogs.com/robsann/p/16608689.html

相关文章

  • jQuery_ajax调用的几种方法
    一、$.ajax()的基础使用 <buttonid="btn">发送请求</button><scriptsrc="/js/jquery.min.js"></script><script>varparams={name:'wangwu',age:300}$('#bt......
  • 系统调用
    操作系统:系统调用目录操作系统:系统调用什么是系统调用,有何作用?系统调用分类(按功能分类)系统调用与库函数的区别系统调用背后的过程什么是系统调用,有何作用?系统调用概念:“......
  • Spring Boot调用api patch接口
    SpringBoot调用apipatch接口示例:/***调用apipatch接口**@paramurl*@paramjsonObject*@returnjava.lang.String*@a......
  • Spring Boot调用api delete接口
     SpringBoot调用apidelete接口示例:/***调用apidelete接口**@paramurl*@authorli.zhm*@date2022/8/2014:07*@hist......
  • 深度学习 之 模型部署【4】-libtorch入门 - pytorch部署torchscript 以及 c++ libto
    pytorch部署torchscriptfromtorchvision.modelsimportresnet34importtorch.nn.functionalasFimporttorch.nnasnnimporttorchimportcv2#读取一张图片,......
  • Spring Boot调用api post接口
    SpringBoot调用apipost接口示例publicstaticStringsendPost(Stringurl,JSONObjectjsonObject){log.info("请求地址:{}",url);Stringbody......
  • 扩展 upost 方便统一调用
    //扩展upost方便统一调用//api.upost=function(conact,data){//returnnewPromise((resolve/,reject/)=>{////使用api.post//ap......
  • SpringBoot中调用Kafka
    Kafka实战——在SpringBoot中的应用官网文档链接1.pom引用 <dependency><groupId>org.springframework.kafka</groupId><artifactId>spri......
  • ModelScope初探:一行代码调用成熟AI模型
    简介: 如何用一行代码调用成熟AI模型?试试ModelScope,让AI开发者解放生产力!ModelScope是阿里推出的下一代开源的模型即服务共享平台,为泛AI开发者提供灵活、易用、低成本的......
  • Shell 调用 py 脚本,接收返回值
    1.py脚本的sys.exit([arg])直接调用exit(),注意是个函数要加括号,无参数默认返回码0,表示脚本运行成功。参数可以是整数也可以是其他对象,若是其他对象则返回码为1,如错误信......