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