我正在尝试为可执行文件设置自己的运行时环境,但无法使用 clang(v3.4-1ubuntu1,目标:x86_64-pc-linux-gnu)来生成没有段错误的可执行文件。我已将问题简化为以下内容:
如果我有一个文件 crt1.c,除了满足 _start 符号的链接器要求之外什么也不做:
void
_start(char *arguments, ...)
{
}
然后我编译它clang -nostdlib crt1.c
,它生成以下可执行文件(来自objdump -d a.out
):
a.out: file format elf64-x86-64
Disassembly of section .text:
0000000000400150 <_start>:
400150: 55 push %rbp
400151: 48 89 e5 mov %rsp,%rbp
400154: 48 81 ec f0 00 00 00 sub $0xf0,%rsp
40015b: 84 c0 test %al,%al
40015d: 0f 29 bd 30 ff ff ff movaps %xmm7,-0xd0(%rbp)
400164: 0f 29 b5 20 ff ff ff movaps %xmm6,-0xe0(%rbp)
40016b: 0f 29 ad 10 ff ff ff movaps %xmm5,-0xf0(%rbp)
400172: 0f 29 a5 00 ff ff ff movaps %xmm4,-0x100(%rbp)
400179: 0f 29 9d f0 fe ff ff movaps %xmm3,-0x110(%rbp)
400180: 0f 29 95 e0 fe ff ff movaps %xmm2,-0x120(%rbp)
400187: 0f 29 8d d0 fe ff ff movaps %xmm1,-0x130(%rbp)
40018e: 0f 29 85 c0 fe ff ff movaps %xmm0,-0x140(%rbp)
400195: 48 89 bd b8 fe ff ff mov %rdi,-0x148(%rbp)
40019c: 4c 89 8d b0 fe ff ff mov %r9,-0x150(%rbp)
4001a3: 4c 89 85 a8 fe ff ff mov %r8,-0x158(%rbp)
4001aa: 48 89 8d a0 fe ff ff mov %rcx,-0x160(%rbp)
4001b1: 48 89 95 98 fe ff ff mov %rdx,-0x168(%rbp)
4001b8: 48 89 b5 90 fe ff ff mov %rsi,-0x170(%rbp)
4001bf: 0f 84 5b 00 00 00 je 400220 <_start+0xd0>
4001c5: 0f 28 85 c0 fe ff ff movaps -0x140(%rbp),%xmm0
4001cc: 0f 29 85 70 ff ff ff movaps %xmm0,-0x90(%rbp)
4001d3: 0f 28 8d d0 fe ff ff movaps -0x130(%rbp),%xmm1
4001da: 0f 29 4d 80 movaps %xmm1,-0x80(%rbp)
4001de: 0f 28 95 e0 fe ff ff movaps -0x120(%rbp),%xmm2
4001e5: 0f 29 55 90 movaps %xmm2,-0x70(%rbp)
4001e9: 0f 28 9d f0 fe ff ff movaps -0x110(%rbp),%xmm3
4001f0: 0f 29 5d a0 movaps %xmm3,-0x60(%rbp)
4001f4: 0f 28 a5 00 ff ff ff movaps -0x100(%rbp),%xmm4
4001fb: 0f 29 65 b0 movaps %xmm4,-0x50(%rbp)
4001ff: 0f 28 ad 10 ff ff ff movaps -0xf0(%rbp),%xmm5
400206: 0f 29 6d c0 movaps %xmm5,-0x40(%rbp)
40020a: 0f 28 b5 20 ff ff ff movaps -0xe0(%rbp),%xmm6
400211: 0f 29 75 d0 movaps %xmm6,-0x30(%rbp)
400215: 0f 28 bd 30 ff ff ff movaps -0xd0(%rbp),%xmm7
40021c: 0f 29 7d e0 movaps %xmm7,-0x20(%rbp)
400220: 48 8b 85 b0 fe ff ff mov -0x150(%rbp),%rax
400227: 48 89 85 68 ff ff ff mov %rax,-0x98(%rbp)
40022e: 48 8b 8d a8 fe ff ff mov -0x158(%rbp),%rcx
400235: 48 89 8d 60 ff ff ff mov %rcx,-0xa0(%rbp)
40023c: 48 8b 95 a0 fe ff ff mov -0x160(%rbp),%rdx
400243: 48 89 95 58 ff ff ff mov %rdx,-0xa8(%rbp)
40024a: 48 8b b5 98 fe ff ff mov -0x168(%rbp),%rsi
400251: 48 89 b5 50 ff ff ff mov %rsi,-0xb0(%rbp)
400258: 48 8b bd 90 fe ff ff mov -0x170(%rbp),%rdi
40025f: 48 89 bd 48 ff ff ff mov %rdi,-0xb8(%rbp)
400266: 4c 8b 85 b8 fe ff ff mov -0x148(%rbp),%r8
40026d: 4c 89 45 f8 mov %r8,-0x8(%rbp)
400271: 48 81 c4 f0 00 00 00 add $0xf0,%rsp
400278: 5d pop %rbp
400279: c3 retq
可执行文件因地址 40015d 处的指令(保存 %xmm7 的指令)处的分段错误而崩溃。我不知道为什么 clang 要把这些保存起来,gcc 没有产生这样的指令。
%rbp 中传递的值是 7fffffffe588,它不是 16 字节对齐的,我想这在某种意义上解释了分段错误。但我该如何让它发挥作用呢?让它抑制那些保存指令?让它以某种方式对齐 rbp 指针?
EDIT:我猜这个问题归结为 clang 生成的代码假设 %rsp 将是 16 字节对齐的。这是一个有效的假设吗?为什么这个例子中的情况不正确呢?