【发布时间】:2016-12-01 14:09:32
【问题描述】:
如果我在strlen.c 中有以下内容:
int call_strlen(char *s) {
return __builtin_strlen(s);
}
然后像这样用 gcc 和 clang 编译它:
gcc -c -o strlen-gcc.o strlen.c
clang -c -o strlen-clang.o strlen.c
我很惊讶地看到 strlen-clang.o 包含对“strlen”的引用,而 gcc 预期内联了该函数并且没有这样的引用。 (参见下面的 objdumps)。这是clang中的错误吗?我已经在多个版本的 clang 编译器中对其进行了测试,包括 3.8。
编辑:这对我来说很重要的原因是我正在与-nostdlib 链接,而clang 编译的版本给了我一个找不到strlen 的链接错误。
叮当
@> objdump -d strlen-clang.o
strlen-clang.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <call_strlen>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 48 89 7d f8 mov %rdi,-0x8(%rbp)
c: 48 8b 7d f8 mov -0x8(%rbp),%rdi
10: e8 00 00 00 00 callq 15 <call_strlen+0x15>
15: 89 c1 mov %eax,%ecx
17: 89 c8 mov %ecx,%eax
19: 48 83 c4 10 add $0x10,%rsp
1d: 5d pop %rbp
1e: c3 retq
@> objdump -t strlen-clang.o
strlen-clang.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 strlen.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 g F .text 000000000000001f call_strlen
0000000000000000 *UND* 0000000000000000 strlen
GCC
@> objdump -d strlen-gcc.o
strlen-gcc.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <call_strlen>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 89 7d f8 mov %rdi,-0x8(%rbp)
8: 48 8b 45 f8 mov -0x8(%rbp),%rax
c: 48 c7 c1 ff ff ff ff mov $0xffffffffffffffff,%rcx
13: 48 89 c2 mov %rax,%rdx
16: b8 00 00 00 00 mov $0x0,%eax
1b: 48 89 d7 mov %rdx,%rdi
1e: f2 ae repnz scas %es:(%rdi),%al
20: 48 89 c8 mov %rcx,%rax
23: 48 f7 d0 not %rax
26: 48 83 e8 01 sub $0x1,%rax
2a: 5d pop %rbp
2b: c3 retq
@> objdump -t strlen-gcc.o
strlen-gcc.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 strlen.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 g F .text 000000000000002c call_strlen
【问题讨论】:
-
您没有将编译器设置为优化,所以 clang 没有优化。令人震惊。
-
@EOF 这有什么关系?当然,如果被告知使用内置函数,它应该使用内置函数 - 而不是“在更优化的模式下使用内置函数,也许,如果你能被打扰的话”。
builtin只是像inline这样的可选请求吗?如果是这样,您能否将我们链接到 Clang 文档中指定的那个位? -
@EOF 仅供参考,我使用
-O3编译,程序集要短得多,但仍然包含jmp _strlen。 -
@Siguza:我的 gcc 4.8.4 仅在未优化 (
-O0) 时为调用strlen()和__builtin_strlen()创建不同的代码,在所有其他优化级别它为两者生成相同的代码。有时它内联(-O1,-Os),有时它调用库(-O2,-O3)。 -
@EOF,我不认为这是关于优化,而是关于 GCC 内置函数的文档,其中提到“GCC 内置函数总是内联扩展”。诚然,我找不到任何与 Clang 等效的语言,但我认为在没有文档的情况下,否则 clang 在功能上应该与 GCC 等效。