gpt4 book ai didi

c - Clang 中的内置函数不是那么内置的吗?

转载 作者:太空狗 更新时间:2023-10-29 16:53:24 27 4
gpt4 key购买 nike

如果我在 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 中的错误吗?我已经在包括 3.8 在内的多个版本的 clang 编译器中对其进行了测试。

编辑:这对我来说很重要的原因是我正在链接 -nostdlib,而 clang 编译版本给我一个链接错误,指出找不到 strlen。

clang

@> 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

海湾合作委员会

@> 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 -O0:

t.o:
(__TEXT,__text) section
_call_strlen:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 movq %rdi, -0x8(%rbp)
000000000000000c movq -0x8(%rbp), %rdi
0000000000000010 callq _strlen
0000000000000015 movl %eax, %ecx
0000000000000017 movl %ecx, %eax
0000000000000019 addq $0x10, %rsp
000000000000001d popq %rbp
000000000000001e retq

使用 clang -O3

t.o:
(__TEXT,__text) section
_call_strlen:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 popq %rbp
0000000000000005 jmp _strlen

现在,进入问题:

clang 文档声称 clang 支持所有 GCC 支持的内置函数。
然而,GCC documentation似乎将内置函数及其库等价物的名称视为同义词:

Both forms have the same type (including prototype), the same address (when their address is taken), and the same meaning as the C library functions [...].

此外,它也不能保证具有等效库的内置函数(如 strlen 的情况)确实得到优化:

Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function is emitted.

此外,clang internals manual仅提及一次 __builtin_strlen:

  • __builtin_strlen and strlen: These are constant folded as integer constant expressions if the argument is a string literal.

除此之外,他们似乎没有做出任何 promise 。

由于在您的情况下,__builtin_strlen 的参数不是字符串文字,并且由于 GCC 文档允许将对内置函数的调用转换为库函数调用,因此 clang 的行为似乎完全有效。

A "patch for review" on the clang developers mailing list还说:

[...] It will still fall back to runtime use of library strlen, if compile-time evaluation is not possible/required [...].

那是在 2012 年,但文本表明至少在那时,只支持编译时评估。

现在,我看到两个选项:

  • 如果您只需要自己编译程序然后使用和/或分发它,我建议您直接使用 gcc。
  • 如果您需要其他人能够在 gcc 和 clang 下编译您的代码,我建议添加一个 C 库作为静态链接的依赖项。

我强烈建议反对滚动你自己的标准库函数实现,即使是看似简单的情况(如果你不同意,尝试编写你自己的strlen实现,然后比较它到 the glibc one )。

关于c - Clang 中的内置函数不是那么内置的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38615091/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com