_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_入栈时的地址值。
上面的打印结果和我们理解的结果是一致的。
原文地址:https://blog.csdn.net/qq_30896803/article/details/142520413
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!