diff options
| author | Jordan Rupprecht <rupprecht@google.com> | 2018-08-02 18:13:40 +0000 |
|---|---|---|
| committer | Jordan Rupprecht <rupprecht@google.com> | 2018-08-02 18:13:40 +0000 |
| commit | 0f6d31812e1dabe689ab45113675da79438a00ca (patch) | |
| tree | 8d82040529951b26f8387b97bda8919565e2315b | |
| parent | d03fa9903f054de2c55e82012c9bdf198a17cbc8 (diff) | |
| download | bcm5719-llvm-0f6d31812e1dabe689ab45113675da79438a00ca.tar.gz bcm5719-llvm-0f6d31812e1dabe689ab45113675da79438a00ca.zip | |
[LLD] Update split stack support to handle more generic prologues. Improve error handling. Add test file for better code-coverage. Update tests to be more complete.
Submitting patch on behalf of saugustine.
Differential Revision: https://reviews.llvm.org/D49926
llvm-svn: 338750
| -rw-r--r-- | lld/ELF/Arch/X86_64.cpp | 23 | ||||
| -rw-r--r-- | lld/ELF/InputSection.cpp | 34 | ||||
| -rw-r--r-- | lld/test/ELF/Inputs/x86-64-split-stack-extra.s | 10 | ||||
| -rw-r--r-- | lld/test/ELF/x86-64-split-stack-prologue-adjust-fail.s | 10 | ||||
| -rw-r--r-- | lld/test/ELF/x86-64-split-stack-prologue-adjust-silent.s | 2 | ||||
| -rw-r--r-- | lld/test/ELF/x86-64-split-stack-prologue-adjust-success.s | 35 |
6 files changed, 66 insertions, 48 deletions
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index d4bdb3730c5..795de8d7c73 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -482,22 +482,25 @@ namespace { template <> bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End) const { + if (Loc + 8 >= End) + return false; + // Replace "cmp %fs:0x70,%rsp" and subsequent branch // with "stc, nopl 0x0(%rax,%rax,1)" - if (Loc + 8 < End && memcmp(Loc, "\x64\x48\x3b\x24\x25", 4) == 0) { + if (memcmp(Loc, "\x64\x48\x3b\x24\x25", 5) == 0) { memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8); return true; } - // Adjust "lea -0x200(%rsp),%r10" to lea "-0x4200(%rsp),%r10" - if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x94\x24\x00\xfe\xff", 7) == 0) { - memcpy(Loc, "\x4c\x8d\x94\x24\x00\xbe\xff", 7); - return true; - } - - // Adjust "lea -0x200(%rsp),%r11" to lea "-0x4200(%rsp),%r11" - if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x9c\x24\x00\xfe\xff", 7) == 0) { - memcpy(Loc, "\x4c\x8d\x9c\x24\x00\xbe\xff", 7); + // Adjust "lea X(%rsp),%rYY" to lea "(X - 0x4000)(%rsp),%rYY" where rYY could + // be r10 or r11. The lea instruction feeds a subsequent compare which checks + // if there is X available stack space. Making X larger effectively reserves + // that much additional space. The stack grows downward so subtract the value. + if (memcmp(Loc, "\x4c\x8d\x94\x24", 4) == 0 || + memcmp(Loc, "\x4c\x8d\x9c\x24", 4) == 0) { + // The offset bytes are encoded four bytes after the start of the + // instruction. + write32le(Loc + 4, read32le(Loc + 4) - 0x4000); return true; } return false; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 600a0bef151..597e8227217 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -838,6 +838,11 @@ static void switchMorestackCallsToMorestackNonSplit( // __morestack inside that function should be switched to // __morestack_non_split. Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split"); + if (!MoreStackNonSplit) { + error("Mixing split-stack objects requires a definition of " + "__morestack_non_split"); + return; + } // Sort both collections to compare addresses efficiently. llvm::sort(MorestackCalls.begin(), MorestackCalls.end(), @@ -862,8 +867,8 @@ static void switchMorestackCallsToMorestackNonSplit( } } -static bool enclosingPrologueAdjusted(uint64_t Offset, - const DenseSet<Defined *> &Prologues) { +static bool enclosingPrologueAttempted(uint64_t Offset, + const DenseSet<Defined *> &Prologues) { for (Defined *F : Prologues) if (F->Value <= Offset && Offset < F->Value + F->Size) return true; @@ -879,7 +884,7 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End) { if (!getFile<ELFT>()->SplitStack) return; - DenseSet<Defined *> AdjustedPrologues; + DenseSet<Defined *> Prologues; std::vector<Relocation *> MorestackCalls; for (Relocation &Rel : Relocations) { @@ -902,21 +907,26 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf, if (D->Type != STT_FUNC) continue; - if (enclosingPrologueAdjusted(Rel.Offset, AdjustedPrologues)) + // If the callee's-file was compiled with split stack, nothing to do. + auto *IS = cast_or_null<InputSection>(D->Section); + if (!IS || IS->getFile<ELFT>()->SplitStack) + continue; + + if (enclosingPrologueAttempted(Rel.Offset, Prologues)) continue; if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) { - if (Target->adjustPrologueForCrossSplitStack(Buf + F->Value, End)) { - AdjustedPrologues.insert(F); + Prologues.insert(F); + if (Target->adjustPrologueForCrossSplitStack(Buf + getOffset(F->Value), + End)) continue; - } + if (!getFile<ELFT>()->SomeNoSplitStack) + error(lld::toString(this) + ": " + F->getName() + + " (with -fsplit-stack) calls " + D->getName() + + " (without -fsplit-stack), but couldn't adjust its prologue"); } - if (!getFile<ELFT>()->SomeNoSplitStack) - error("function call at " + getErrorLocation(Buf + Rel.Offset) + - "crosses a split-stack boundary, but unable " + - "to adjust the enclosing function's prologue"); } - switchMorestackCallsToMorestackNonSplit(AdjustedPrologues, MorestackCalls); + switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls); } template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { diff --git a/lld/test/ELF/Inputs/x86-64-split-stack-extra.s b/lld/test/ELF/Inputs/x86-64-split-stack-extra.s new file mode 100644 index 00000000000..29c42185caa --- /dev/null +++ b/lld/test/ELF/Inputs/x86-64-split-stack-extra.s @@ -0,0 +1,10 @@ +# This file is split out to provide better code coverage. + .global split + .type split,@function +split: + retq + + .size split,. - split + + .section .note.GNU-stack,"",@progbits + .section .note.GNU-split-stack,"",@progbits diff --git a/lld/test/ELF/x86-64-split-stack-prologue-adjust-fail.s b/lld/test/ELF/x86-64-split-stack-prologue-adjust-fail.s index 0ae3de5ea61..f3d09243711 100644 --- a/lld/test/ELF/x86-64-split-stack-prologue-adjust-fail.s +++ b/lld/test/ELF/x86-64-split-stack-prologue-adjust-fail.s @@ -1,15 +1,19 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-extra.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t3.o -# RUN: not ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld --defsym __morestack=0x100 --defsym __more_stack_nonsplit=0x200 %t1.o %t2.o %t3.o -o %t 2>&1 | FileCheck %s # An unknown prologue gives a match failure -# CHECK: unable to adjust the enclosing function's +# CHECK: error: {{.*}}.o:(.text): unknown_prologue (with -fsplit-stack) calls non_split (without -fsplit-stack), but couldn't adjust its prologue # RUN: not ld.lld -r --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s -check-prefix=RELOCATABLE # RELOCATABLE: Cannot mix split-stack and non-split-stack in a relocatable link +# RUN: not ld.lld --defsym __morestack=0x100 --defsym _start=0x300 %t1.o %t2.o %t3.o -o %t 2>&1 | FileCheck %s -check-prefix=ERROR +# ERROR: Mixing split-stack objects requires a definition of __morestack_non_split + .text .global unknown_prologue diff --git a/lld/test/ELF/x86-64-split-stack-prologue-adjust-silent.s b/lld/test/ELF/x86-64-split-stack-prologue-adjust-silent.s index 353eabef0de..0c82943f8dd 100644 --- a/lld/test/ELF/x86-64-split-stack-prologue-adjust-silent.s +++ b/lld/test/ELF/x86-64-split-stack-prologue-adjust-silent.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o -# RUN: ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t +# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o -o %t # RUN: llvm-objdump -d %t 2>&1 | FileCheck %s # An unknown prologue ordinarily gives a match failure, except that this diff --git a/lld/test/ELF/x86-64-split-stack-prologue-adjust-success.s b/lld/test/ELF/x86-64-split-stack-prologue-adjust-success.s index bad26677f3f..fb3493f2c3e 100644 --- a/lld/test/ELF/x86-64-split-stack-prologue-adjust-success.s +++ b/lld/test/ELF/x86-64-split-stack-prologue-adjust-success.s @@ -1,8 +1,9 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-extra.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t3.o -# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o -o %t -z notext +# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o %t3.o -o %t -z notext # RUN: llvm-objdump -d %t | FileCheck %s # Avoid duplicating the prologue for every test via macros. @@ -25,11 +26,11 @@ prologue1_calls_\function_to_call: .size prologue1_calls_\function_to_call,. - prologue1_calls_\function_to_call .endm -.macro prologue2 function_to_call register +.macro prologue2 function_to_call register compare_amount .global prologue2_calls_\function_to_call\register .type prologue2_calls_\function_to_call\register,@function prologue2_calls_\function_to_call\register: - lea -0x200(%rsp),%\register + lea -\compare_amount(%rsp),%\register cmp %fs:0x70,%\register jae 1f callq __morestack @@ -65,20 +66,20 @@ prologue1 split # calls plain __morestack, that any raw bytes written to the prologue # make sense, and that the register number is preserved. # CHECK: prologue2_calls_splitr10: -# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r10 +# CHECK-NEXT: lea{{.*}} -512(%rsp),{{.*}}%r10 # CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}} # CHECK: jae{{.*}} # CHECK-NEXT: callq{{.*}}<__morestack> -prologue2 split r10 +prologue2 split r10 0x200 # CHECK: prologue2_calls_splitr11: -# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r11 +# CHECK-NEXT: lea{{.*}} -256(%rsp),{{.*}}%r11 # CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}} # CHECK: jae{{.*}} # CHECK-NEXT: callq{{.*}}<__morestack> -prologue2 split r11 +prologue2 split r11 0x100 # For split-stack code calling non-split-stack code, ensure prologue v1 # calls __morestack_non_split, and that any raw bytes written to the prologue @@ -95,30 +96,20 @@ prologue1 non_split # calls __morestack_non_split, that any raw bytes written to the prologue # make sense, and that the register number is preserved # CHECK: prologue2_calls_non_splitr10: -# CHECK-NEXT: lea{{.*$}} +# CHECK-NEXT: lea{{.*}} -16640(%rsp),{{.*}}%r10 # CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r10 # CHECK: jae{{.*$}} # CHECK-NEXT: callq{{.*}}<__morestack_non_split> -prologue2 non_split r10 +prologue2 non_split r10 0x100 # CHECK: prologue2_calls_non_splitr11: -# CHECK-NEXT: lea{{.*$}} +# CHECK-NEXT: lea{{.*}} -16896(%rsp),{{.*}}%r11 # CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r11 # CHECK: jae{{.*$}} # CHECK-NEXT: callq{{.*}}<__morestack_non_split> -prologue2 non_split r11 -# call foo@plt # for code-coverage. - - - - .global split - .type split,@function -split: - retq - - .size split,. - split +prologue2 non_split r11 0x200 .section .note.GNU-stack,"",@progbits .section .note.GNU-split-stack,"",@progbits |

