总结一下X86和AArch64架构下C语言中直接函数调用和间接函数调用的底层调用方式。主要是想记录一下在机器码这个层面直接函数调用和间接函数调用如何获取目标函数的地址。

1.直接函数调用

话不多说,先上C代码

// test.c
#include <stdio.h>
void foo() {printf("function foo\n");
}
int main(int argc, char **argv)
{foo();return 0;
}

编译

gcc -O0 -o ex test.c

反汇编

objdump -d ex &> out.txt

1.1 X86

X86的反汇编代码

红框选中的就是直接函数调用的反汇编代码。直接函数调用通过相对偏移来寻址,e8代表callq指令,d6ffffff表示跳转的地址,intel采用小端寻址,所以d6ffffff表示的值是0xffffffd6,计算机内负数通过补码表示,补码表示的绝对值是取反加一,所以0xffffffd6表示的绝对值是0x2a,0x2a正好是函数foo的第一条指令的地址4004b2和callq的下一条指令的地址4004dc之间的差。所以x86结构下,直接函数调用的寻址方式是目标函数的第一条指令的地址与callq指令下一条指令的地址之间的相对偏移。

1.2 AArch64

AArch64的反汇编代码

ARM AArch64的指令都是4字节对齐,bl指令的的前6位是操作码,后26位是立即数地址,红框中指令中立即数为0x3fffff4,0x3fffff4表示的绝对值为0xc,ARM AArch64通过该立即数x4表示寻址的地址,0xc x 4 = 0x30,是目标函数foo的第一条指令的地址4005a4和当前bl指令的地址4005d4之间的差。所以ARM AArch64结构下,直接函数调用的寻址方式是目标函数的第一条指令的地址与bl指令的地址之间的相对偏移。

2.间接函数调用

C代码

// test.c
#include <stdio.h>
void foo() {printf("function foo\n");
}
int main(int argc, char **argv)
{void (*fp)() = foo;fp();return 0;
}

编译

gcc -O0 -o ex test.c

反汇编

objdump -d ex &> out.txt

2.1 X86

X86的反汇编代码

X86结构下的间接函数调用通过绝对地址直接寻址。第一个红框中的指令将目标函数foo的第一条指令的地址4004b2写入栈中,即赋值给函数指针变量fp。第二个红框中的第一条mov指令将存放在函数指针fp中的目标函数第一条指令的地址读入寄存器rdx中,然后callq指令通过存放在寄存器rdx中的绝对地址跳转到目标函数运行。

2.2 AArch64

ARM AArch64的反汇编代码

ARM AArch64结构下的间接函数调用也是通过绝对地址直接寻址。第一个红框中的指令首先通过程序空间起始地址400000和目标函数foo第一条指令相对起始地址的偏移5a4相加得到目标函数第一条指令的地址4005a4,然后将该地址写入栈中,即赋值给函数指针变量fp。第二个红框中的第一条mov指令将存放在函数指针fp中的目标函数第一条指令的地址读入寄存器x0中,然后blr指令通过存放在寄存器x0中的绝对地址跳转到目标函数运行。

3.总结

直接函数调用都是通过相对偏移寻址,X86和ARM AArch64的区别在于:X86的偏移是目标函数的首地址与call指令下一条指令地址之间的相对偏移,而ARM AArch64的偏移是目标函数的首地址与call指令本身地址之间的相对偏移。
间接函数调用都是通过绝对地址直接寻址,X86和ARM AArch64相同。

C语言中直接函数调用和间接函数调用的底层调用方式 X86 AArch64相关推荐

  1. c语言中的自己写的.h文件如何调用注意事项

    c语言中的自己写的.h文件如何调用注意事项 需要建立一个项目project,并把相关的.h .c .cpp文件建在这个项目下面. 需要注意引用时不同,例如 #include<stdio.h> ...

  2. java 与或_Java 语言中的逻辑与 () 和逻辑或 (||) 运算采用 方式进行运算。_学小易找答案...

    [单选题]明清时期,"龙门账"按经济业务性质进行分门别类的登记在账簿"进"."缴"."存"和"()" ...

  3. 输入三角形的三c语言程序,请问c语言中 从键盘输入三角形的3边 调用三角形面积公式求面积 并输.,C语言编写程序,从键盘输入三角形三条边长(实数),计算并输出...

    导航:网站首页 > 请问c语言中 从键盘输入三角形的3边 调用三角形面积公式求面积 并输.,C语言编写程序,从键盘输入三角形三条边长(实数),计算并输出 请问c语言中 从键盘输入三角形的3边 调 ...

  4. C语言中执行python代码或源程序文件(高级嵌入方式)

    环境:Fedora12 + Python2.6 + C 1. 建立python源代码文件(del.py): #!/usr/bin/env pythondef calculate(expression) ...

  5. c语言中合法语句但有bug语句,安全处理方式

    所谓合法语句,但是有bug语句,请看下面这段代码示例一: #include <stdio.h> #include <stdint.h>int init = 4; int mai ...

  6. c语言中主函数创建链表,主函数怎么调用函数(数据结构,创建链表)

    主函数怎么调用函数(数据结构,创建链表)0 rnxm44602018.09.29浏览179次分享举报 #include#include"stdlib.h"typedefintEle ...

  7. Delphi开发中增删改查操作以及存储过程的调用方式

    1.SQL实现增删改 tryif not DTM.Conn.InTransaction thenDTM.Conn.StartTransaction;//插入制式机型Init;A('insert int ...

  8. C语言中的输入输出流和缓冲区(重点)详解

    导读: C语言中我们用到的最频繁的输入输出方式就是scanf()与printf(). scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中. printf(): 将指定的文字/字符串输 ...

  9. c语言中或者怎么打,c语言中的或怎么打出来

    快速导读: Q1:c语言中表示"或"的两条竖线怎么打出来啊 在C语言中,或有两种.2113 1 逻辑运算5261中的或运算.题目中提到的就4102是这一运算. 标识符为1653|| ...

最新文章

  1. 如何快速搭建开放、多租户的电商云平台
  2. 【C/C++高质量编程 笔记】
  3. php redis 集合返回多条,详解PHP多个进程配合redis的有序集合实现大文件去重
  4. Linux(Centos7)下安装Redis(redis-5.0.8)
  5. swoole/php-cp 安装
  6. 假如苹果构建了一个搜索引擎
  7. [九度][何海涛] 二叉树中和为某一值的路径
  8. Redis.conf 详解
  9. 计算机基础考试题附答案——《第陆篇》
  10. 免安装版MySQL的配置——详细教程
  11. python表格数据对比_python入门之对比两份excel表格数据
  12. 数据结构——BF算法
  13. citra黑屏_3ds模拟器最新版Citra下载_3ds模拟器Citra2019最新版下载_游戏堡
  14. 17位行业影响力者的数字藏品2022年趋势研判!丨巴比特数字藏品高峰论坛金句实录...
  15. 10个java调试技巧
  16. sonarqube连mysql_sonarqube接入mysql数据库实例
  17. 51单片机可以用来做什么?单片机可以做的小产品
  18. 网络工程师常见面试问题
  19. Windows桌面鼠标右键菜单清理
  20. 功能对等四个原则_功能对等理论的简要介绍及其原则

热门文章

  1. lldb断点framework中方法
  2. 盈利模式不清晰 本身是个伪需求 共享充电宝不过是场资本游戏
  3. 【实战技能】关于开发者的沟通技能
  4. 【Docker】四、使用Docker下载镜像文件
  5. 非物质文化遗产的法律保护模式(九)
  6. caffe fine-tune策略
  7. Python numba 的使用
  8. jre配置环境变量及无法保存设置的Path变量值
  9. 产品分享:Qt+Arm基于RV1126平台的内窥镜软硬整套解决方案(实时影像、冻结、拍照、录像、背光调整、硬件光源调整,其他产品也可使用该平台,如视频监控,物联网产品等等)
  10. POI 生成百万行Excel防止OOM