我试过这段代码:
#include <stdlib.h>
#include <stdio.h>
__attribute__((always_inline)) void dummy_fct(int *a){
float b[2] = {(float)a[0] / 42,(float)a[1] / 66};
a[0] = (int)b[0];
a[1] = (int)b[1];
}
int main(void){
int v[2] = {rand(),rand()};
dummy_fct(v);
printf("%d %d\n",v[0],v[1]);
return 0;
}
当我用gcc编译它时没有选项我得到这个警告(这是合乎逻辑的):
main.c:4:37: warning: always_inline function might not be inlinable [-Wattributes]
__attribute__((always_inline)) void dummy_fct(int *a){
但是当我读到生成的二进制程序集(使用objdump -d my_binary
)时,我得到了这个:
(...)
0000000000400550 <frame_dummy>:
400550: 55 push %rbp
400551: 48 89 e5 mov %rsp,%rbp
400554: 5d pop %rbp
400555: e9 36 ff ff ff jmpq 400490 <register_tm_clones>
40055a: 90 nop
40055b: 90 nop
000000000040055c <dummy_fct>:
40055c: 55 push %rbp
40055d: 48 89 e5 mov %rsp,%rbp
400560: 48 89 7d e8 mov %rdi,-0x18(%rbp)
400564: 48 8b 45 e8 mov -0x18(%rbp),%rax
400568: 8b 00 mov (%rax),%eax
40056a: f3 0f 2a c0 cvtsi2ss %eax,%xmm0
40056e: f3 0f 10 0d ea 01 00 movss 0x1ea(%rip),%xmm1 # 400760 <_IO_stdin_used+0xc>
400575: 00
400576: f3 0f 5e c1 divss %xmm1,%xmm0
40057a: f3 0f 11 45 f8 movss %xmm0,-0x8(%rbp)
40057f: 48 8b 45 e8 mov -0x18(%rbp),%rax
400583: 48 83 c0 04 add $0x4,%rax
400587: 8b 00 mov (%rax),%eax
400589: f3 0f 2a c0 cvtsi2ss %eax,%xmm0
40058d: f3 0f 10 0d cf 01 00 movss 0x1cf(%rip),%xmm1 # 400764 <_IO_stdin_used+0x10>
400594: 00
400595: f3 0f 5e c1 divss %xmm1,%xmm0
400599: f3 0f 11 45 fc movss %xmm0,-0x4(%rbp)
40059e: f3 0f 10 45 f8 movss -0x8(%rbp),%xmm0
4005a3: f3 0f 2c d0 cvttss2si %xmm0,%edx
4005a7: 48 8b 45 e8 mov -0x18(%rbp),%rax
4005ab: 89 10 mov %edx,(%rax)
4005ad: f3 0f 10 45 fc movss -0x4(%rbp),%xmm0
4005b2: 48 8b 45 e8 mov -0x18(%rbp),%rax
4005b6: 48 8d 50 04 lea 0x4(%rax),%rdx
4005ba: f3 0f 2c c0 cvttss2si %xmm0,%eax
4005be: 89 02 mov %eax,(%rdx)
4005c0: 90 nop
4005c1: 5d pop %rbp
4005c2: c3 retq
00000000004005c3 <main>:
4005c3: 55 push %rbp
4005c4: 48 89 e5 mov %rsp,%rbp
4005c7: 48 83 ec 20 sub $0x20,%rsp
4005cb: e8 28 fe ff ff callq 4003f8 <rand@plt>
4005d0: 89 45 f0 mov %eax,-0x10(%rbp)
4005d3: e8 20 fe ff ff callq 4003f8 <rand@plt>
4005d8: 89 45 f4 mov %eax,-0xc(%rbp)
4005db: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005df: 48 89 45 f8 mov %rax,-0x8(%rbp)
4005e3: 48 8b 45 f8 mov -0x8(%rbp),%rax
4005e7: 8b 00 mov (%rax),%eax
4005e9: f3 0f 2a c0 cvtsi2ss %eax,%xmm0
4005ed: f3 0f 10 0d 6b 01 00 movss 0x16b(%rip),%xmm1 # 400760 <_IO_stdin_used+0xc>
4005f4: 00
4005f5: f3 0f 5e c1 divss %xmm1,%xmm0
4005f9: f3 0f 11 45 e8 movss %xmm0,-0x18(%rbp)
4005fe: 48 8b 45 f8 mov -0x8(%rbp),%rax
400602: 48 83 c0 04 add $0x4,%rax
400606: 8b 00 mov (%rax),%eax
400608: f3 0f 2a c0 cvtsi2ss %eax,%xmm0
40060c: f3 0f 10 0d 50 01 00 movss 0x150(%rip),%xmm1 # 400764 <_IO_stdin_used+0x10>
400613: 00
400614: f3 0f 5e c1 divss %xmm1,%xmm0
400618: f3 0f 11 45 ec movss %xmm0,-0x14(%rbp)
40061d: f3 0f 10 45 e8 movss -0x18(%rbp),%xmm0
400622: f3 0f 2c d0 cvttss2si %xmm0,%edx
400626: 48 8b 45 f8 mov -0x8(%rbp),%rax
40062a: 89 10 mov %edx,(%rax)
40062c: f3 0f 10 45 ec movss -0x14(%rbp),%xmm0
400631: 48 8b 45 f8 mov -0x8(%rbp),%rax
400635: 48 8d 50 04 lea 0x4(%rax),%rdx
400639: f3 0f 2c c0 cvttss2si %xmm0,%eax
40063d: 89 02 mov %eax,(%rdx)
40063f: 8b 55 f4 mov -0xc(%rbp),%edx
400642: 8b 45 f0 mov -0x10(%rbp),%eax
400645: 89 c6 mov %eax,%esi
400647: bf 58 07 40 00 mov $0x400758,%edi
40064c: b8 00 00 00 00 mov $0x0,%eax
400651: e8 82 fd ff ff callq 4003d8 <printf@plt>
400656: b8 00 00 00 00 mov $0x0,%eax
40065b: c9 leaveq
40065c: c3 retq
40065d: 90 nop
40065e: 90 nop
40065f: 90 nop
(...)
当然,没有callq
到dummy_fct
但是我很惊讶地看到函数的代码不在main中,并且在二进制文件中存在于一个单独的部分中。
我的意思是内联已经添加了一些代码,因此二进制文件应该更大(如果内联代码被多次使用)。那么为什么函数的二进制仍然存在于main之外呢?所以二进制文件甚至更大...... 关于gcc的内联,我真的不明白这一点。
(这是一个哲学问题,这里没有更多的意义)
答案 0 :(得分:3)
由于您没有另外声明,dummy_fct
是一个外部函数,因此如果存在来自其他翻译单元的调用者,编译器必须为其生成代码。要删除此义务,请将dummy_fct
声明为static
。
进一步注意dummy_fct
实际上是内联的。您可以在main
:
4005db: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005df: 48 89 45 f8 mov %rax,-0x8(%rbp)
4005e3: 48 8b 45 f8 mov -0x8(%rbp),%rax
4005e7: 8b 00 mov (%rax),%eax
4005e9: f3 0f 2a c0 cvtsi2ss %eax,%xmm0
4005ed: f3 0f 10 0d 6b 01 00 movss 0x16b(%rip),%xmm1 # 400760 <_IO_stdin_used+0xc>
4005f4: 00
4005f5: f3 0f 5e c1 divss %xmm1,%xmm0
4005f9: f3 0f 11 45 e8 movss %xmm0,-0x18(%rbp)
4005fe: 48 8b 45 f8 mov -0x8(%rbp),%rax
400602: 48 83 c0 04 add $0x4,%rax
400606: 8b 00 mov (%rax),%eax
400608: f3 0f 2a c0 cvtsi2ss %eax,%xmm0
40060c: f3 0f 10 0d 50 01 00 movss 0x150(%rip),%xmm1 # 400764 <_IO_stdin_used+0x10>
400613: 00
400614: f3 0f 5e c1 divss %xmm1,%xmm0
400618: f3 0f 11 45 ec movss %xmm0,-0x14(%rbp)
40061d: f3 0f 10 45 e8 movss -0x18(%rbp),%xmm0
400622: f3 0f 2c d0 cvttss2si %xmm0,%edx
400626: 48 8b 45 f8 mov -0x8(%rbp),%rax
40062a: 89 10 mov %edx,(%rax)
40062c: f3 0f 10 45 ec movss -0x14(%rbp),%xmm0
400631: 48 8b 45 f8 mov -0x8(%rbp),%rax
400635: 48 8d 50 04 lea 0x4(%rax),%rdx
400639: f3 0f 2c c0 cvttss2si %xmm0,%eax
40063d: 89 02 mov %eax,(%rdx)
虽然由于缺乏优化而可能有点难以阅读此代码,但仔细阅读确认这确实是dummy_fct
所做的。
答案 1 :(得分:3)
你忘记了神奇的单词inline
。 inline __attribute((always inline))
!= __attribute((always inline))
即使您添加inline
,有时也会看到相同的附加代码。该代码实际上不会被链接,LTO会使用它。
因为有一些混乱。即使您不使用inline
关键字
__attribute__((always_inline))
向编译器显示它应该内联,即使它通常不会内联(例如-O0)。
添加C关键字inline
最终使函数内联,并使用属性使其始终内联。