锵产生崩溃code。与-nostdlib [英] Clang produces crashing code with -nostdlib

查看:215
本文介绍了锵产生崩溃code。与-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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆