c语言内建函数

__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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值