这里写目录标题
__builtin_return_address() 指向函数地址
#include<stdio.h>
void fun1();
void fun2();
void fun1()
{
int *p;
p = __builtin_return_address(0);
printf("%p\n",p);
p = __builtin_return_address(1);
printf("%p\n\n",p);
fun2();
}
void fun2()
{
int *p;
p = __builtin_return_address(0);
printf("%p\n",p);
p = __builtin_return_address(1);
printf("%p\n",p);
p = __builtin_return_address(2);
printf("%p\n\n",p);
}
void main(void)
{
int *p;
p = __builtin_return_address(0);
printf("%p\n\n",p);
fun1();
}
__builtin_return_address(0)返回当前函数地址
__builtin_return_address(1)返回上一个函数地址
$ ./build.o
0x7f69aa291c87
0x5603bdabd74b
0x7f69aa291c87
0x5603bdabd6a0
0x5603bdabd74b
0x7f69aa291c87
__builtin_frame_address() 栈帧地址
#include<stdio.h>
void fun1();
void fun2();
void fun1()
{
int *p;
p = __builtin_frame_address(0);
printf("%p\n",p);
p = __builtin_frame_address(1);
printf("%p\n\n",p);
fun2();
}
void fun2()
{
int *p;
p = __builtin_frame_address(0);
printf("%p\n",p);
p = __builtin_frame_address(1);
printf("%p\n",p);
p = __builtin_frame_address(2);
printf("%p\n\n",p);
}
void fun3(){
int *p;
p = __builtin_frame_address(0);
printf("%p\n",p);
p = __builtin_frame_address(1);
printf("%p\n\n",p);
}
void main(void)
{
int *p;
p = __builtin_frame_address(0);
printf("%p\n\n",p);
fun1();
fun3();
}
在c语言中每个函数在调用其他函数时,他本身就会被放在一个单独的栈。
$ ./build.o
0x7fffc1cc7500
0x7fffc1cc74e0
0x7fffc1cc7500
0x7fffc1cc74c0
0x7fffc1cc74e0
0x7fffc1cc7500
0x7fffc1cc74e0
0x7fffc1cc7500
栈帧就是栈最高位的地址(栈是由高地址向低地址扩展)
从fun3()函数可以看出来,他被放在fun1()之前的地址,栈的地址是来回使用的。
__builtin_constant_p(n) 判断n是否为常量
__builtin_expect(exp,c) 分支预测(缓存命中率)
现代 CPU 内部,都有 cache 这个缓存器件。CPU 的运行速度很高,而外部 RAM 的速度相对来说就低了不少,所以当 CPU 从内存 RAM 读写数据时就会有一定的性能瓶颈。为了提高程序执行效率,CPU 都会通过 cache 这个 CPU 内部缓冲区来缓存一定的指令或数据。CPU 读写内存 RAM 中的数据时,会先到 cache 里面去看看能不能找到。找到的话就直接进行读写;找不到的话,cache 会重新缓存一部分内存数据进来。CPU 读写 cache 的速度远远大于内存 RAM,所以通过这种方式,可以提高系统的性能。
#include<stdio.h>
#define likely(x) __builtin_expect(!!(x),1)
#define unlikely(x) __builtin_expect(!!(x),0)
int main(void)
{
int a;
scanf("%d",&a);
if(unlikely(a == 0))
{
printf("%d",1);
printf("%d",2);
printf("\n");
}
else
{
printf("%d",5);
printf("%d",6);
printf("\n");
}
return 0;
}
$ gcc -g -O2 __builtin_expect.c -o __builtin_expect.o
$ objdump -S __builtin_expect.o -j .text
在编译时需要使用O2优化,使用反编译可以看到
printf(“%d”,5);
printf(“%d”,6);
被提前了
0000000000000680 <main>:
#include<stdio.h>
#define likely(x) __builtin_expect(!!(x),1)
#define unlikely(x) __builtin_expect(!!(x),0)
int main(void)
{
680: 48 83 ec 18 sub $0x18,%rsp
int a;
scanf("%d",&a);
684: 48 8d 3d 39 02 00 00 lea 0x239(%rip),%rdi # 8c4 <_IO_stdin_used+0x4>
{
68b: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
692: 00 00
694: 48 89 44 24 08 mov %rax,0x8(%rsp)
699: 31 c0 xor %eax,%eax
scanf("%d",&a);
69b: 48 8d 74 24 04 lea 0x4(%rsp),%rsi
6a0: e8 bb ff ff ff callq 660 <__isoc99_scanf@plt>
if(unlikely(a == 0))
6a5: 8b 44 24 04 mov 0x4(%rsp),%eax
6a9: 85 c0 test %eax,%eax
6ab: 74 51 je 6fe <main+0x7e>
}
__fortify_function int
printf (const char *__restrict __fmt, ...)
{
return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
6ad: 48 8d 35 10 02 00 00 lea 0x210(%rip),%rsi # 8c4 <_IO_stdin_used+0x4>
6b4: ba 05 00 00 00 mov $0x5,%edx
6b9: bf 01 00 00 00 mov $0x1,%edi
6be: 31 c0 xor %eax,%eax
6c0: e8 8b ff ff ff callq 650 <__printf_chk@plt>
6c5: ba 06 00 00 00 mov $0x6,%edx
6ca: 48 8d 35 f3 01 00 00 lea 0x1f3(%rip),%rsi # 8c4 <_IO_stdin_used+0x4>
6d1: bf 01 00 00 00 mov $0x1,%edi
6d6: 31 c0 xor %eax,%eax
6d8: e8 73 ff ff ff callq 650 <__printf_chk@plt>
6dd: bf 0a 00 00 00 mov $0xa,%edi
6e2: e8 49 ff ff ff callq 630 <putchar@plt>
printf("%d",5);
printf("%d",6);
printf("\n");
}
return 0;
}
6e7: 31 c0 xor %eax,%eax
6e9: 48 8b 4c 24 08 mov 0x8(%rsp),%rcx
6ee: 64 48 33 0c 25 28 00 xor %fs:0x28,%rcx
6f5: 00 00
6f7: 75 24 jne 71d <main+0x9d>
6f9: 48 83 c4 18 add $0x18,%rsp
6fd: c3 retq
6fe: 48 8d 35 bf 01 00 00 lea 0x1bf(%rip),%rsi # 8c4 <_IO_stdin_used+0x4>
705: ba 01 00 00 00 mov $0x1,%edx
70a: bf 01 00 00 00 mov $0x1,%edi
70f: 31 c0 xor %eax,%eax
711: e8 3a ff ff ff callq 650 <__printf_chk@plt>
716: ba 02 00 00 00 mov $0x2,%edx
71b: eb ad jmp 6ca <main+0x4a>
71d: e8 1e ff ff ff callq 640 <__stack_chk_fail@plt>
722: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
729: 00 00 00
72c: 0f 1f 40 00 nopl 0x0(%rax)