当前位置: 首页 > article >正文

_RET_IP_ 和_THIS_IP_ 作用

在Linux内核中,有两个罕见的宏定义_RET_IP_ 和_THIS_IP_。但是这两个宏在内核代码中又时不时的出现,那么它们到底是什么含义呢?

1、宏定义

我们先看它们的宏定义

include./linux/kernel.h

#define _RET_IP_		(unsigned long)__builtin_return_address(0)

#define _THIS_IP_  ({ __label__ __here; __here: (unsigned long)&&__here; })

我们先看_RET_IP_的含义:

#define _RET_IP_ (unsigned long)__builtin_return_address(0)

其中__builtin_return_address(0) 是gcc内建函数,返回函数的返回地址。所以_RET_IP_ 宏定义用于返回当前函数的返回地址(当前函数被调用处的地址)

在看看_THIS_IP_的含义:

#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })

__lable__ 是gcc对c语言的扩展,用于局部标签,__label__ __here; 声明了一个局部标签__here。

什么是局部标签?

GCC allows you to declare local labels(局部标签) in any nested block scope.A local label is just like an ordinary label, but you can only reference it (with a goto statement, or by taking its address) within the block in which it is declared.

一个局部标签只是一个标识符:可以使用通常的goto语句进行跳转或者获取其地址,但是只能在其所属的域内内。

A local label declaration looks like this:(局部标签定义如下:)

__label__ label;

or

__label__ label1, label2, /* … */;

You can get the address of a label defined in the current function (or a containing function) with the unary operator ‘&&’.The value has type void *.

我们可以通过'&&'符号来获取局部标签的地址(获取变量的地址是'&'),地址类型为void *.

#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })

先定义了一个局部标签 __here,后面是__here标签的内容,和我们使用goto语句时的标签的用法是一样的,  __here: (unsigned long)&&__here; 返回局部标签__here所在位置的地址。所以_THIS_IP_返回当前位置的地址(PC指针的值)

内核中有个专门返回当前代码段的地址的宏定义:

#define current_text_addr() ({ __label__ _l; _l: &&_l;})

和_THIS_IP_的宏定义是一样的。

2、测试

下面我们写个简单的程序测试下

#include <stdio.h>
#include <stdlib.h>

#define _RET_IP_	(unsigned long)__builtin_return_address(0)

#define _THIS_IP_  	({ __label__ __here; __here: (unsigned long)&&__here; })

void bar(void)
{
    /*This is bar (400551,40052a) */
    printf("This is bar (%x,%x) \012",_RET_IP_,_THIS_IP_);
    return ;
}

int main()
{
    bar();

    return 0;
}

上面程序输出结果是:This is bar (400551,40052a)

我们将上面程序反汇编结果如下:

0000000000400526 <bar>:

400526: 55 push %rbp

400527: 48 89 e5 mov %rsp,%rbp

40052a: ba 2a 05 40 00 mov $0x40052a,%edx

40052f: 48 8b 45 08 mov 0x8(%rbp),%rax

400533: 48 89 c6 mov %rax,%rsi

400536: bf e4 05 40 00 mov $0x4005e4,%edi

40053b: b8 00 00 00 00 mov $0x0,%eax

400540: e8 bb fe ff ff callq 400400 <printf@plt>

400545: 90 nop

400546: 5d pop %rbp

400547: c3 retq

0000000000400548 <main>:

400548: 55 push %rbp

400549: 48 89 e5 mov %rsp,%rbp

40054c: e8 d5 ff ff ff callq 400526 <bar>

400551: b8 00 00 00 00 mov $0x0,%eax

400556: 5d pop %rbp

400557: c3 retq

400558: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)

40055f: 00

_RET_IP_的打印结果是400551,但是调用bar函数的地址是40054c。由于流水线的原因,取指完成后PC=PC+4,所以_RET_IP_的值为400551.

_THIS_IP_的打印结果是40052a,该地址是printf打印中_THIS_IP_入栈时的地址值。

上面的打印结果和我们理解的结果是一致的。


http://www.kler.cn/news/323934.html

相关文章:

  • cesium的学习过程和使用案例
  • 闲盒支持的组网方式和注意事项
  • gitlab使用小结
  • 原宝,四周年快乐!
  • leetcode621. 任务调度器
  • Linux系统使用iptables配置入站端口
  • 教师工作量|基于springBoot的教师工作量管理系统设计与实现(附项目源码+论文+数据库)
  • shell脚本定时任务通知到钉钉
  • 使用yum为centos系统安装软件以及使用(包含阿里云yum源配置)
  • React封装登录逻辑
  • python的逻辑控制
  • JAVA打造全球商品集散地国际版多商户商城系统小程序源码
  • 1. go 环境与命令
  • python 获取当前git的repo地址
  • electron 设置界面右下角打开
  • 浅谈java异常[Exception]
  • JAVA红娘婚恋相亲交友系统源码全面解析
  • python 实现gradient boosting regressor梯度增强回归器算法
  • 车间调度问题数学建模与CPLEX优化
  • conda安装包离线安装环境
  • SO-ELM预测 | MATLAB实现SO-ELM蛇群算法优化极限学习机多输入单输出
  • Elasticsearch导出导入数据
  • GraphQL规范
  • C++动态内存管理
  • 基于大数据的亚健康人群数据分析及可视化系统
  • GEE 教程:如何在谷歌地球引擎中使用克里金插值?
  • ArcGIS Pro高级地图可视化—双变量符号地图
  • 极品飞车14热力追踪原始版高清重制版MOD分享
  • QT开发:深入详解Qt 核心类QTimer的概念及应用
  • Linux网络之UDP与TCP协议详解