簡體   English   中英

Clang使用-nostdlib生成崩潰代碼

[英]Clang produces crashing code with -nostdlib

我正在為可執行文件設置我自己的運行時環境,我不能得到clang(v3.4-1ubuntu1,target: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指針?

編輯 :我想這個問題歸結為clang產生的代碼假定%rsp將是16字節對齊的事實。 這是一個有效的假設嗎? 為什么在這個例子中不正確?

編輯:找到解決方案 - 跳過以下看...


首先,確保堆棧( %rsp )是16字節對齊的:

pushq  %rbp
movq   %rsp, %rbp
andq   $-0x10, %rsp  ; rsp = rsp & 0xffffffffffffff0

這是有問題的,因為通常調用者有責任確保%rsp是16字節對齊的,因為%rbp + 16.n可能不在16字節邊界上。 因此,也許movq %rsp, %rbp應該對齊后出現%rsp

sub $0xf0, %rsp分配堆棧空間的0xf0字節; 0xf0是(16)的倍數。 如果%rsp movaps %xmm7, -0xd0(%rbp)不是16字節對齊,則movaps %xmm7, -0xd0(%rbp) => movaps %xmm7, 0x20(%rsp) 換句話說,SSE寄存器存儲在%rsp + 32 如果不對齊,則會引發“一般保護異常”,即段錯誤。

您可能遇到的另一個問題是對-0x170(%rbp) =>的讀/寫是-0x170(%rbp) -0x80(%rsp) ,它是紅色區域的邊界(或者過去?我可能在我的偏移中)。 由於這是一個葉子函數,你可以自由使用它,但不能寫過它。

注意:如果調用了函數,則應從%rsp減去另外的(8)個字節以確保16字節對齊。 這將反過來影響(%ebp)的偏移。

我不是在這里檢查ABI標准,我可能犯了一些錯誤; 因此最好檢查x86-64 SysV ABI (3.2節)。


解決方案:使用-mstackrealign標志編譯上述函數,顯式地將%rsp -mstackrealign與16字節邊界對齊。 我在OS X上使用了clang,它與調用約定和對齊要求的x86-64 SysV(x86-64 ELF / Linux)基本相同:

clang -nostdlib -mstackrealign -c crt1.c

0000000000000000        pushq   %rbp
0000000000000001        movq    %rsp, %rbp
0000000000000004        andq    $0xfffffffffffffff0, %rsp
000000000000000b        subq    $0x170, %rsp
0000000000000012        testb   %al, %al
...

順便說一句 - 這可以通過使所有加載/存儲相對於%rsp完全避免%rbp問題。 因此,沒有使用紅色區域 - 至少使用Apple的基於LLVM 3.3的clang。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM