gcc/g++ inine Function Attributes

function attributes的写法是:写在函数声明的后面,或者写在函数定义的前面。

比如放在声明后面:

int foo() __attribute__((noinline));
int foo() {return 1;}

或者放在定义前面:

__attribute__((noinline)) int foo() {return 1;}

1)先看一段程序示例:

#include <stdio.h>

int foo() {return 1;}

int foo2() {return 2;}

int main(void)
{
    foo();
    foo2();

    return 0;
}

开启-O2优化编译,gcc -O2 -o inline inline.cpp

gdb查看汇编:

(gdb) disass main
Dump of assembler code for function main:
   0x00000000004004f0 <+0>:     xor    %eax,%eax
   0x00000000004004f2 <+2>:     retq
End of assembler dump.
(gdb)

可见,foo与foo2都没有实际调用,被编译器优化掉了。

2)通过添加function attribute防止inline:

#include <stdio.h>

__attribute__((noinline)) int foo() {return 1;}

int foo2() {return 2;}

int main(void)
{
    foo();
    foo2();

    return 0;
}

-O2编译: gcc -O2 -o inline inline.cpp

gdb查看:

(gdb) disass main
Dump of assembler code for function main:
   0x00000000004004f0 <+0>:     xor    %eax,%eax
   0x00000000004004f2 <+2>:     retq
End of assembler dump.
(gdb)

结果foo与foo2仍然被优化掉了,没有实际调用。

原因是虽然inline被禁止了,但是编译器优化会决定此处仍然不需要调用函数,因为foo与foo2的结果没有被使用,所以继续修改程序如下:

3)添加function attributes,并且使用函数返回值进行赋值

#include <stdio.h>

__attribute__((noinline)) int foo() {return 1;}

int foo2() {return 2;}

int main(void)
{
    int ret1 = foo();
    int ret2 = foo2();

    return 0;
}

结果gdb查看仍然没有发生函数调用:

(gdb) disass main
Dump of assembler code for function main:
   0x00000000004004f0 <+0>:     xor    %eax,%eax
   0x00000000004004f2 <+2>:     retq
End of assembler dump.

因为返回值ret1与ret2并没有实际使用,所以继续修改程序如下:

4)添加function attributes,并且真实使用函数返回值

#include <stdio.h>

__attribute__((noinline)) int foo() {return 1;}

int foo2() {return 2;}

int main(void)
{
    int ret1 = foo();
    int ret2 = foo2();

    printf("ret1=[%d], ret2=[%d]", ret1, ret2);

    return 0;
}

gdb查看编译结果:

(gdb) disass main
Dump of assembler code for function main:
   0x0000000000400540 <+0>:     sub    $0x8,%rsp
   0x0000000000400544 <+4>:     callq  0x400520 <_Z3foov>
   0x0000000000400549 <+9>:     mov    $0x2,%edx
   0x000000000040054e <+14>:    mov    %eax,%esi
   0x0000000000400550 <+16>:    mov    $0x40065c,%edi
   0x0000000000400555 <+21>:    xor    %eax,%eax
   0x0000000000400557 <+23>:    callq  0x4003a0 <printf@plt>
   0x000000000040055c <+28>:    xor    %eax,%eax
   0x000000000040055e <+30>:    add    $0x8,%rsp
   0x0000000000400562 <+34>:    retq
End of assembler dump.

发现只有foo被实际调用了,foo2被inline了:

 0x0000000000400549 <+9>:     mov    $0x2,%edx

5)把foo2也加上function attribues如下:

#include <stdio.h>

__attribute__((noinline)) int foo() {return 1;}

int foo2() __attribute__((noinline));
int foo2() {return 2;}

int main(void)
{
    int ret1 = foo();
    int ret2 = foo2();

    printf("ret1=[%d], ret2=[%d]", ret1, ret2);

    return 0;
}

gdb查看编译结果:

(gdb) disass main
Dump of assembler code for function main:
   0x0000000000400540 <+0>:     push   %rbx
   0x0000000000400541 <+1>:     callq  0x400520 <_Z3foov>
   0x0000000000400546 <+6>:     mov    %eax,%ebx
   0x0000000000400548 <+8>:     callq  0x400530 <_Z4foo2v>
   0x000000000040054d <+13>:    mov    %ebx,%esi
   0x000000000040054f <+15>:    mov    %eax,%edx
   0x0000000000400551 <+17>:    mov    $0x40065c,%edi
   0x0000000000400556 <+22>:    xor    %eax,%eax
   0x0000000000400558 <+24>:    callq  0x4003a0 <printf@plt>
   0x000000000040055d <+29>:    xor    %eax,%eax
   0x000000000040055f <+31>:    pop    %rbx
   0x0000000000400560 <+32>:    retq
End of assembler dump.
(gdb)

可见,foo和foo2两个函数都被调用了。

6)如果函数返回值被使用,但是不加function attributes呢?程序如下:

#include <stdio.h>

int foo() {return 1;}

int foo2() {return 2;}

int main(void)
{
    int ret1 = foo();
    int ret2 = foo2();

    printf("ret1=[%d], ret2=[%d]", ret1, ret2);

    return 0;
}

gdb查看编译结果:

(gdb) disass main
Dump of assembler code for function main:
   0x0000000000400540 <+0>:     sub    $0x8,%rsp
   0x0000000000400544 <+4>:     mov    $0x2,%edx
   0x0000000000400549 <+9>:     mov    $0x1,%esi
   0x000000000040054e <+14>:    mov    $0x40065c,%edi
   0x0000000000400553 <+19>:    xor    %eax,%eax
   0x0000000000400555 <+21>:    callq  0x4003a0 <printf@plt>
   0x000000000040055a <+26>:    xor    %eax,%eax
   0x000000000040055c <+28>:    add    $0x8,%rsp
   0x0000000000400560 <+32>:    retq
End of assembler dump.

可见,没有实际的函数调用,foo和foo2都被编译器inline了。

针对上面 2)中函数返回值没有被使用,即使加了function attributes也没有发生实际调用的情况,有没有强制手段发生函数调用,避免被编译器优化掉呢,答案是可以。

看看noinline的介绍:

noinline

This function attribute prevents a function from being considered for inlining. If the function does not have side effects, there are optimizations other than inlining that cause function calls to be optimized away, although the function call is live. To keep such calls from being optimized away, put

asm ("");

因此,将上面的程序改造为:
 

#include <stdio.h>

__attribute__((noinline)) int foo() {asm (""); return 1;}

int foo2() {asm (""); return 2;}

int main(void)
{
    foo();
    foo2();

    return 0;
}

查看编译结果:

(gdb) disass main
Dump of assembler code for function main:
   0x00000000004004f0 <+0>:     callq  0x4004d0 <_Z3foov>
   0x00000000004004f5 <+5>:     xor    %eax,%eax
   0x00000000004004f7 <+7>:     retq
End of assembler dump.
(gdb)

可见,foo同时添加了function attribute以及asm(""), 所以不管怎么优化,函数都会发生调用。而foo2仅仅添加了asm(""),没有发生函数调用。

参考:

https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值