gpt4 book ai didi

c - GCC 优化器在 nostdlib 代码中生成错误

转载 作者:行者123 更新时间:2023-12-02 19:59:30 25 4
gpt4 key购买 nike

我有以下代码:

void cp(void *a, const void *b, int n) {
for (int i = 0; i < n; ++i) {
((char *) a)[i] = ((const char *) b)[i];
}
}

void _start(void) {
char buf[20];

const char m[] = "123456789012345";
cp(buf, m, 15);

register int rax __asm__ ("rax") = 60; // exit
register int rdi __asm__ ("rdi") = 0; // status

__asm__ volatile (
"syscall" :: "r" (rax), "r" (rdi) : "cc", "rcx", "r11"
);

__builtin_unreachable();
}

如果我用 gcc -nostdlib -O1 "./a.c" -o "./a" 编译它,我会得到一个正常运行的程序,但如果我用 -O2 编译它,我会得到一个生成段错误的程序。

这是使用 -O1 生成的代码:

0000000000001000 <cp>:
1000: b8 00 00 00 00 mov $0x0,%eax
1005: 0f b6 14 06 movzbl (%rsi,%rax,1),%edx
1009: 88 14 07 mov %dl,(%rdi,%rax,1)
100c: 48 83 c0 01 add $0x1,%rax
1010: 48 83 f8 0f cmp $0xf,%rax
1014: 75 ef jne 1005 <cp+0x5>
1016: c3 retq

0000000000001017 <_start>:
1017: 48 83 ec 30 sub $0x30,%rsp
101b: 48 b8 31 32 33 34 35 movabs $0x3837363534333231,%rax
1022: 36 37 38
1025: 48 ba 39 30 31 32 33 movabs $0x35343332313039,%rdx
102c: 34 35 00
102f: 48 89 04 24 mov %rax,(%rsp)
1033: 48 89 54 24 08 mov %rdx,0x8(%rsp)
1038: 48 89 e6 mov %rsp,%rsi
103b: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
1040: ba 0f 00 00 00 mov $0xf,%edx
1045: e8 b6 ff ff ff callq 1000 <cp>
104a: b8 3c 00 00 00 mov $0x3c,%eax
104f: bf 00 00 00 00 mov $0x0,%edi
1054: 0f 05 syscall

这是使用 -O2 生成的代码:

0000000000001000 <cp>:
1000: 31 c0 xor %eax,%eax
1002: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
1008: 0f b6 14 06 movzbl (%rsi,%rax,1),%edx
100c: 88 14 07 mov %dl,(%rdi,%rax,1)
100f: 48 83 c0 01 add $0x1,%rax
1013: 48 83 f8 0f cmp $0xf,%rax
1017: 75 ef jne 1008 <cp+0x8>
1019: c3 retq
101a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)

0000000000001020 <_start>:
1020: 48 8d 44 24 d8 lea -0x28(%rsp),%rax
1025: 48 8d 54 24 c9 lea -0x37(%rsp),%rdx
102a: b9 31 00 00 00 mov $0x31,%ecx
102f: 66 0f 6f 05 c9 0f 00 movdqa 0xfc9(%rip),%xmm0 # 2000 <_start+0xfe0>
1036: 00
1037: 48 8d 70 0f lea 0xf(%rax),%rsi
103b: 0f 29 44 24 c8 movaps %xmm0,-0x38(%rsp)
1040: eb 0d jmp 104f <_start+0x2f>
1042: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
1048: 0f b6 0a movzbl (%rdx),%ecx
104b: 48 83 c2 01 add $0x1,%rdx
104f: 88 08 mov %cl,(%rax)
1051: 48 83 c0 01 add $0x1,%rax
1055: 48 39 f0 cmp %rsi,%rax
1058: 75 ee jne 1048 <_start+0x28>
105a: b8 3c 00 00 00 mov $0x3c,%eax
105f: 31 ff xor %edi,%edi
1061: 0f 05 syscall

崩溃发生在 103b 指令 movaps %xmm0,-0x38(%rsp) 处。

我注意到,如果 m 包含的字符少于 15 个,则生成的代码会有所不同,并且不会发生崩溃。

我做错了什么?

最佳答案

_start 不是一个函数。它不会被任何东西调用,并且在进入时堆栈是 16 字节对齐的与 16 字节对齐不相距 8 个字节(按照 ABI 的要求)。

(ABI 要求在 call 之前进行 16 字节对齐,并且 call 推送 8 字节返回地址。因此函数入口 RSP-8 和 RSP+8 16 字节对齐。)

<小时/>

-O2处,GCC使用需要对齐的16字节指令来实现cp()完成的复制,复制“123456789012345”从静态存储到堆栈。

-O1 处,GCC 仅使用两个 mov r64, imm64 指令将字节获取到 8 字节存储的整数寄存器中。这些不需要对齐。

<小时/>

解决方法

如果你想让一切正常工作,只需像普通人一样用 C 语言编写一个 main 即可。

或者,如果您尝试对 asm 中的轻量级内容进行微基准测试,您可以使用 gcc -nostdlib -O3 -mincoming-stack-boundary=3 ( docs ) 告诉 GCC 函数不能假设它们是使用超过 8 字节对齐方式调用的。与 -mpreferred-stack-boundary=3 不同,在进行进一步调用之前,它仍会按 16 对齐。因此,如果您有其他非叶函数,您可能只想在 hacky C _start() 上使用属性,而不是影响整个文件。

<小时/>

更糟糕、更黑客的方法是尝试 put
asm("push %rax"); 位于 _start 的最顶部,将 RSP 修改为 8,GCC 希望在对堆栈执行任何其他操作之前运行它。 GNU C Basic asm 语句是隐式 volatile 的,因此您不需要 asm volatile ,尽管这不会有什么坏处。

您需要 100% 依靠自己,并负责通过使用适用于您所使用的任何优化级别的内联汇编来正确欺骗编译器。

<小时/>

另一种更安全的方法是编写自己的轻量级_start来调用main:

// at global scope:
asm(
".globl _start \n"
"_start: \n"
" mov (%rsp), %rdi \n" // argc
" lea 8(%rsp), %rsi \n" // argv
" lea 8(%rsi, %rdi, 8), %rdx \n" // envp
" call main \n"
// NOT DONE: stdio cleanup or other atexit stuff
// DO NOT USE WITH GLIBC; use libc's CRT code if you use libc
" mov %eax, %edi \n"
" mov $231, %eax \n"
" syscall" // exit_group( main() )
);

int main(int argc, char**argv, char**envp) {
... your code here
return 0;
}

如果您不希望 main 返回,您只需 pop %rdi; mov %rsp, %rsi ; jmp main 为其提供 argc 和 argv,但不带返回地址。

然后 main 可以通过内联 asm 退出,或者通过调用 exit()_exit()(如果链接 libc)。 (但是如果链接 libc,通常应该使用它的 _start。)

另请参阅:How Get arguments value using inline assembly in C without Glibc? 了解其他手卷 _start 版本;这很像 @zwol 在那里。

关于c - GCC 优化器在 nostdlib 代码中生成错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58806696/

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