__builtin_return_address函数

news2025/1/23 22:27:42

文章目录

  • 一、gcc 内置函数
  • 二、__builtin_return_address
    • 2.1 简介
    • 2.2 代码示例
  • 三、查看函数调用
  • 参考资料

一、gcc 内置函数

GCC 内置函数是指 GCC 编译器内置的一些函数,这些函数可以用于实现一些常用的操作,如数学运算、字符串处理、内存管理、调试等。这些函数与标准 C 库函数不同,它们通常具有更高的效率和更好的可移植性,因为它们是针对特定平台和编译器优化的。

GCC 内置函数可以分为以下几类:

(1)数学函数:包括常见的数学运算函数,如求平方根、求绝对值、求三角函数等。

(2)字符串函数:包括字符串操作函数,如字符串比较、字符串复制、字符串连接等。

(3)内存函数:包括内存操作函数,如内存填充、内存拷贝、内存分配、内存释放等。

(4)调试函数:包括用于调试和性能优化的函数,如获取函数调用栈、测量程序执行时间、预取数据到高速缓存等。

(5)其他函数:包括一些其他的常用函数,如比特位操作函数、字节序转换函数、原子操作函数等。

以下是一些常用的 GCC 内置函数:

__builtin_sqrt:求平方根函数。
__builtin_abs:求绝对值函数。
__builtin_strlen:求字符串长度函数。
__builtin_memset:内存填充函数。
__builtin_memcpy:内存拷贝函数。
__builtin_malloc:内存分配函数。
__builtin_free:内存释放函数。
__builtin_return_address:获取函数调用栈中的返回地址函数。
__builtin_prefetch:预取数据到高速缓存函数。
__builtin_bswap16、__builtin_bswap32、__builtin_bswap64:字节序转换函数。
__builtin_clz、__builtin_ctz、__builtin_popcount:比特位操作函数。

二、__builtin_return_address

2.1 简介

__builtin_return_address 是 GCC 内置函数之一,用于获取指定层数的函数调用栈中的返回地址。该函数接受一个整数参数 level,表示要获取的返回地址所在的函数调用栈层数。如果 level 等于 0,则返回当前函数调用的返回地址;如果 level 大于 0,则返回当前函数调用栈中第 level 层函数的返回地址。

比如:
0:返回当前函数的返回地址;
1:返回当前函数调用者的返回地址;
2:返回当前函数调用者的调用者的返回地址;

该函数的返回值类型是 void*,指向函数调用栈中的返回地址。需要注意的是,返回的地址是指向调用函数指令的地址,而不是指向函数返回值的地址。因此,如果需要获取函数返回值的地址,需要结合其他内置函数一起使用。

2.2 代码示例

(1)

#include <stdio.h>
#include <stddef.h>

void func1();
void func2();
void func3();

void func1() {
    printf("Function 1: %p\n", __builtin_return_address(0));
    printf("Function main: %p\n", __builtin_return_address(1));
    printf("\n");
    func2();
}

void func2() {
    printf("Function 2: %p\n", __builtin_return_address(0));
    printf("Function 1: %p\n", __builtin_return_address(1));
    printf("Function main: %p\n", __builtin_return_address(2));
    printf("\n");
    func3();
}

void func3() {
    printf("Function 3: %p\n", __builtin_return_address(0));
    printf("Function 2: %p\n", __builtin_return_address(1));
    printf("Function 1: %p\n", __builtin_return_address(2));
    printf("Function main: %p\n", __builtin_return_address(3));
}

int main() {
    printf("Function main: %p\n", __builtin_return_address(0));
    printf("\n");    
    func1();
    return 0;
}
# ./a.out
Function main: 0x7fdb571bd555

Function 1: 0x4006cf
Function main: 0x7fdb571bd555

Function 2: 0x4005c5
Function 1: 0x4006cf
Function main: 0x7fdb571bd555

Function 3: 0x40062c
Function 2: 0x4005c5
Function 1: 0x4006cf
Function main: 0x7fdb571bd555

使用 objdump 查看其汇编指令代码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以 func1 函数来说,调用 __builtin_return_address(1) ,就是获取 main函数调用 func1 函数的返回地址,该地址就是 main函数调用 func1 函数时的下一条指令的地址,main函数调用 call func1,先将调用 func1 函数时的下一条指令的地址压入栈中,然后在跳转到 func1 函数的地址。
call 指令等价于:

push address1(func1 next inst address)
jmp address2(func1 address)

address1和 address1不一样,address1是main函数调用 func1 函数时的下一条指令的地址,address2是func1 函数的地址。

(2)
接下来我们我们用 gdb 调试看一下,分别给上述的函数下断点:

(gdb) break main
Breakpoint 1 at 0x4006a5: file 2.c, line 31.
(gdb) rbreak ^func
Breakpoint 2 at 0x400581: file 2.c, line 9.
void func1();
Breakpoint 3 at 0x4005cb: file 2.c, line 16.
void func2();
Breakpoint 4 at 0x400632: file 2.c, line 24.
void func3();
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000004006a5 in main at 2.c:31
2       breakpoint     keep y   0x0000000000400581 in func1 at 2.c:9
3       breakpoint     keep y   0x00000000004005cb in func2 at 2.c:16
4       breakpoint     keep y   0x0000000000400632 in func3 at 2.c:24
(gdb) run
Starting program: a.out

在这里插入图片描述
在这里插入图片描述
可以看到和 __builtin_return_address 函数获取到的值是一样的。

(3)
接下来我们看看 func1 、func2 和 func3调用 ret 指令时寄存器的值,调用 ret 指令时,先把 栈帧中 pop出 上一个函数压入栈中的返回地址,然后跳转到该返回地址,ret 指令等价于:

pop address
jmp address

这两个地址都是一样的,比如 main函数,调用func1时,将调用 func1 函数时的下一条指令的地址 address 压入栈中,然后在跳转到 func1 函数的地址,然后再 func1 函数执行 ret 指令时,就 pop address ,然后跳转到 address ,回到 main 函数执行 func1 函数时的下一条指令的地址 address 的指令。

在这里插入图片描述
使用 gdb在 func1返回前停住,反汇编用,查看对应寄存器下状态。0x0x4006c就是 main函数中调用func1时的下一条指令的地址。
对应的 func2、func3:
在这里插入图片描述
在这里插入图片描述

三、查看函数调用

我们还可以通过 __builtin_return_address 查看函数被哪个函数调用:
通过__builtin_return_address()获取函数地址后,再到到函数表中根据函数地址查找到对应的函数名即可:

info symbol address

在这里插入图片描述

参考资料

https://cloud.tencent.com/developer/article/1646414
https://blog.csdn.net/dinghuiyang/article/details/124245875
https://blog.csdn.net/zhaixuebuluo/article/details/86663338

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/767624.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何创作小红书化妆品文案,技巧分析!

小红书拥有众多女性用户群。美妆自然成为里面最大的板块&#xff0c;所以不管是护肤品牌&#xff0c;还是相关达人都会进行化妆品类的文案创作。今天从两个方案来探讨下如何创作小红书化妆品文案&#xff0c;技巧分析&#xff01; 一、对品牌输出文案的重点 1. 强调产品特点 向…

牛客周赛 Round 3

游游的7的倍数 思路分析 添加一个数让其为7的倍数。倍数&#xff0c;每7个中必有一个是7的倍数&#xff0c;在末尾添加一个数即可.遍历0-6&#xff0c;满足既可。 时间复杂度 O&#xff08;1&#xff09; 代码 #include<bits/stdc.h> using namespace std; using ll…

毫秒级的 Unix 时间戳,将其转换为日期时间格式,报错,“将 expression 转换为数据类型 int 时出现算术溢出错误”

如果您有一个时间戳值为 1689217823000&#xff0c;表示毫秒级的 Unix 时间戳&#xff0c;您可以将其转换为日期时间格式。在 SQL Server 中&#xff0c;可以使用 DATEADD 和 CONVERT 函数来进行转换。 以下是将该时间戳值转换为日期时间格式的步骤&#xff1a; DECLARE timest…

从零开始学习 Java:简单易懂的入门指南(一)

Java基础语法 1. 人机交互1.1 什么是cmd&#xff1f;1.2 如何打开CMD窗口&#xff1f;1.3 常用CMD命令1.4 CMD练习1.5 环境变量 2. Java概述1.1 Java是什么&#xff1f;1.2下载和安装1.2.1 下载1.2.2 安装1.2.3 JDK的安装目录介绍 1.3 HelloWorld小案例1.3.1 Java程序开发运行…

【矩阵的基本操作】——MatLab基础

目录索引 矩阵的基本操作&#xff1a;转置&#xff1a;矩阵的拼接&#xff1a;*横拼&#xff1a;**竖拼&#xff1a;* 矩阵的索引&#xff1a;取元素&#xff1a;*end():* 取区域&#xff1a;逻辑判断&#xff1a;逻辑取值&#xff1a;find()&#xff1a; 矩阵的基本操作&#…

基于net core2.2的redis秒杀+数据持久化+数据恢复系列(2)

第一篇我们总结了秒杀的整个流程&#xff0c;本篇我们详细介绍下redis的秒杀实现&#xff0c;基于.net core2.2开发。 首先&#xff0c;需要安装redis&#xff0c;因为我在本地测试的&#xff0c;所以安装的windows版本的redis。redis分为服务端和客户端&#xff0c;这个redis…

了解Azido TAT,使用铜催化的叠氮化物反应修饰Tat肽,以下内容查看详细信息!

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ 【产品描述】 Azido-TAT中Tat肽已被证明具有优异的细胞穿透性&#xff0c;可以增强对特异性靶向疾病的诊断和 寡核苷酸的吸收。寡核苷酸通过点击化学与Tat&#xff08;一种生物学上重要的细胞穿透肽&#xff09;的共价连接…

❤ npm install 时报Error: spawn git ENOENT

❤ npm install 时报Error: spawn git ENOENT 原因&#xff1a; 主要是因为由于 git 的环境变量未设置导致&#xff0c;所以安装一下git 的环境变量就O了&#xff0c;步骤如下&#xff1a; 设置 >> 系统 >> 高级系统设置 >> 高级 >> 环境变量 >&g…

编写软件测试用例的方法,你知道多少种

1、等价类划分法 适用场景&#xff1a; 有数据输入的地方&#xff0c;就可以使用等价类划分法。如&#xff1a;输入框 测试思想&#xff1a; 从大量数据中划分范围&#xff08;等价类&#xff09;&#xff0c;然后从每个范围中挑选代表数据&#xff0c;这些代表数据要能反应…

株洲科能冲刺上市:计划募资约6亿元,实控人为赵科峰、唐燕夫妇

7月17日&#xff0c;上海证券交易所披露的信息显示&#xff0c;已对株洲科能新材料股份有限公司&#xff08;下称“株洲科能”&#xff09;发出问询函。据贝多财经了解&#xff0c;株洲科能于2023年6月21日递交招股书&#xff0c;准备在科创板上市。 本次冲刺科创板上市&#x…

springboot+mybatis-plus实现自动建表

好长时间没输出了&#xff0c;最近工作上也是太多事&#xff0c;领导动不动就拍脑门&#xff0c;那叫一个酸爽~ 工作能力的提现不但是技术或解决问题的能力上&#xff0c;还体现在要能立刻满足领导的各种需求&#xff0c;不管是哪方面的需求&#xff0c;这样才能够拍上马屁&…

IDDR和ODDR

IDDR D&#xff1a;输入双倍速率数据&#xff08;IOB输入&#xff0c;且数据在时钟的上升沿和下降沿都会发生切换&#xff0c;即一个时钟周期发送2bit数据&#xff09; CE&#xff1a;时钟使能信号&#xff08;高有效&#xff09; C&#xff1a;时钟信号 S&#xff0c;R&#x…

STM32F4_串口 IAP

目录 前言 1. IAP简介 2. APP程序起始地址设置方法 3. 中断向量表的偏移量设置 4. 如何在MDK中生成 .BIN 文件 5. APP程序生成步骤 前言 IAP&#xff0c;即在应用编程。 1. IAP简介 IAP&#xff08;In Application Programming&#xff09;即 在应用编程&#xff0c;IAP…

Apache RocketMQ5.x-消息队列体验

Apache RocketMQ5.x-消息队列体验 Apache RocketMQ 是一款低延迟、高并发、高可用、高可靠的分布式消息中间件&#xff0c;由阿里开源&#xff0c;后由阿里捐赠给Apache基金会。 本次体验的目的是从技术角度验证一下在微服架构中&#xff0c;用Apache RocketMQ做为消息队列&am…

MQTT 订阅标识符详解

为什么需要订阅标识符 在大部分 MQTT 客户端的实现中&#xff0c;都会通过回调机制来实现对新到达消息的处理。 但是在回调函数中&#xff0c;我们只能知道消息的主题名是什么。如果是非通配符订阅&#xff0c;订阅时使用的主题过滤器将和消息中的主题名完全一致&#xff0c;…

chatglm微调

chatGML 看到 【【官方教程】ChatGLM-6B 微调&#xff1a;P-Tuning&#xff0c;LoRA&#xff0c;Full parameter】 【精准空降到 15:27】 https://www.bilibili.com/video/BV1fd4y1Z7Y5/?share_sourcecopy_web&vd_sourceaa8c13cff97f0454ee41e1f609a655f1&t927 记得看…

Java Mybatis02+oracle拓展

0目录 Mybatis 02Oracle 拓展 1.Mybatis 02 创建数据库和表 创建工程 实体类 util工具类 接口方法 Resource Mapper xml文件 配置文件 测试 加入模糊查询&#xff08;根据姓名&#xff09; 测试结果 2.ParameterType语法 实战 参数为对象 参数为…

Bean 作用域与生命周期

Bean 作用域与生命周期 ​ 对于 Spring 来说&#xff0c;核心操作对象就是存和取 Bean &#xff0c;接下来就 Bean 的作用域与生命周期进行探讨。 文章目录 Bean 作用域与生命周期一、作用域的定义1.1、Bean 的6种作用域1.2、Bean作用域设置方法 二、Bean 的生命周期2.1、Bean…

【Java】Java实现微信小程序发送服务通知

文章目录 前言一、文档来源二、JAR包引入三、后端工作四、编写配置文件配置一&#xff1a;WxConfig配置二&#xff1a;WxProperties 五、代码编写 前言 在上个月接到一个需求&#xff0c;大概是需要计算一条数据的最大办理时间从而发送任务超期的微信小程序服务通知&#xff0…

怎么进行流程图制作?分享几种绘制方法

怎么进行流程图制作&#xff1f;流程图是一种图形化表示流程的图表&#xff0c;通常用于描述业务、计划或工作流程。它可以帮助人们更好地理解复杂的流程&#xff0c;并且提供了一种清晰的方法来记录和共享流程信息。下面介绍一些绘制流程图的方法&#xff0c;可以帮助我们快速…