锵产生崩溃code。与-nostdlib [英] Clang produces crashing code with -nostdlib
问题描述
我跟一个可执行建立我自己的运行环境玩弄了,我不能让铛(v3.4-1ubuntu1,目标:x86_64的-PC-Linux的GNU),以产生不可执行段错误。我已经减少该问题为以下:
I am playing around with setting up my own runtime environment for an executable, and I can't get clang (v3.4-1ubuntu1, target: x86_64-pc-linux-gnu) to produce an executable that doesn't segfault. I have reduced the problem to the following:
如果我有一个文件crt1.c,什么也不做,除了满足对_start符号链接要求:
If I have a file crt1.c that does nothing except satisfy the linker requirement for a _start symbol:
void
_start(char *arguments, ...)
{
}
然后我用铛-nostdlib crt1.c
,它产生以下可执行文件(从 objdump的-d的a.out $编译C $ C>)
Then I compile it with clang -nostdlib crt1.c
, it produces the following executable (from 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之一。我不知道为什么铛是节约这些东西拿走,GCC产生没有这样的说明。
The executable crashes with a segmentation fault at the instruction at address 40015d--the one that saves away %xmm7. I don't know why clang is saving these away, gcc produces no such instructions.
在%RBP传递的值7fffffffe588,这不是16字节对齐,这我想在某种意义上解释了分段错误。不过,我将如何得到这个工作?得到它燮preSS那些保存指令?得到它以某种方式对齐RBP指针?
The value passed in %rbp is 7fffffffe588, which is not 16-byte aligned, which I guess in some sense explains the segmentation fault. But how would I get this to work? Get it to suppress those save instructions? Get it to align the rbp pointer somehow?
修改:我想这个问题归结为一个事实,即code,它是哗生产假设%RSP将是16字节对齐。那是一个有效的假设做什么呢?为什么不是真的在这个例子吗?
EDIT: I guess this problem comes down to the fact that the code that clang is producing assumes that %rsp is going to be 16-byte aligned. Is that a valid assumption to make? Why is it not true in this example?
推荐答案
编辑:找到了解决方案 - 跳到见下文...
found a solution - skip to see below...
首先,确保栈(%RSP
)是16字节对齐:
First, ensure that stack (%rsp
) is 16-byte aligned:
pushq %rbp
movq %rsp, %rbp
andq $-0x10, %rsp ; rsp = rsp & 0xffffffffffffff0
这是有问题的,因为它通常调用者的责任,以确保%RSP
对齐,如%RBP + 16.n <16字节/ code>可能不是一个16字节的边界上。因此,也许
MOVQ%RSP,RBP%
应的排列%RSP
之后出现。
This is problematic, as it's normally the caller's responsibility to ensure %rsp
is 16-byte aligned, as %rbp + 16.n
might not be on a 16-byte boundary. So perhaps movq %rsp, %rbp
should appear after the alignment of %rsp
.
子$ 0XF0,RSP%
分配0XF0的堆栈空间字节; 0XF0为(16)的倍数。如果%RSP
未对齐16字节, MOVAPS%XMM7,-0xd0(RBP%)
=> MOVAPS%XMM7,为0x20(%RSP)
。换句话说,上证所寄存器保存在%RSP + 32
。如果没有对齐,这就提出了一个一般保护性异常',即段错误。
sub $0xf0, %rsp
allocates 0xf0 byte of stack space; 0xf0 being a multiple of (16). If %rsp
is not 16-byte aligned, movaps %xmm7, -0xd0(%rbp)
=> movaps %xmm7, 0x20(%rsp)
. In other words, the SSE register is stored at %rsp + 32
. If not aligned, this raises a 'general protection exception', i.e., a segfault.
您可能会遇到的另一个问题是读取/写入 -0x170(RBP%)
=>这是 -0x80(%RSP)
,可以是(或过去?我会在我的抵消掉)的<一个边界href=\"http://stackoverflow.com/questions/8337783/why-does-gcc-subtract-the-wrong-value-to-the-stack-pointer-when-allocating-a-big\">red区 。由于这是一个叶函数,你可以自由地使用它,但不写过去吧。
Another issue you might encounter are reads/writes to -0x170(%rbp)
=> that's -0x80(%rsp)
, which is either on (or past? I might be out in my offsets) the boundary of the red zone. As this is a leaf function, you are free to use it, but not write past it.
注意:如果你的函数是的名为的,你应该减去另一个(8)%RSP
字节来确保16字节对齐。这将反过来影响偏移量(%EBP)
。
Note: if your function was called, you should subtract another (8) bytes from %rsp
to ensure 16-byte alignment. This will in turn affect the offsets for (%ebp)
.
我不是这里的事实与ABI标准检查,我可能犯了一些错误;所以它可能是最好的检查与 X86-64 SysV的ABI (3.2节)。
I'm not fact checking with the ABI standard here, I may have made some mistakes; so it might be best to check with the x86-64 SysV ABI (section 3.2).
解决方案:编译上面的 -mstackrealign
标记对齐明确功能%RSP
到16字节边界。我使用铛在OS X上,这是基本相同的x86-64的SysV(x86-64的ELF / Linux)的相对于调用约定和对齐要求:
SOLUTION: compiling the function above with the -mstackrealign
flag explicitly aligns %rsp
to a 16-byte boundary. I'm using clang on OS X, which is basically the same as x86-64 SysV (x86-64 ELF / Linux) with respect to calling conventions and alignment requirements:
铛-nostdlib -mstackrealign -c crt1.c
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 andq $0xfffffffffffffff0, %rsp
000000000000000b subq $0x170, %rsp
0000000000000012 testb %al, %al
...
BTW - 这通过相对所有负载/存储以%RSP 完全避免了
%RBP
问题code>。因此,没有采用红色区域 - 至少与苹果的LLVM 3.3基于铛
BTW - this avoids the %rbp
issue entirely by making all loads/stores relative to %rsp
. Consequently, there is no use of the red zone - at least with Apple's LLVM 3.3 based clang.
这篇关于锵产生崩溃code。与-nostdlib的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!