From 66434562e7cdb4671821cbe50ec8c15fe5fff078 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 5 May 2016 19:41:49 +0000 Subject: [PATCH] Fix copy relocations in pie. We were creating the copy relocations just fine, but then thinking that the .bss position could be preempted and creating a dynamic relocation to it, which would crash at runtime since that memory is read only. llvm-svn: 268668 --- lld/ELF/Symbols.cpp | 6 ++-- lld/ELF/Writer.cpp | 7 ++--- lld/test/ELF/Inputs/copy-rel-pie.s | 9 ++++++ lld/test/ELF/copy-rel-pie.s | 44 ++++++++++++++++++++++++++++++ lld/test/ELF/mips-got-and-copy.s | 18 ++++++++---- lld/test/ELF/relro.s | 2 +- 6 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 lld/test/ELF/Inputs/copy-rel-pie.s create mode 100644 lld/test/ELF/copy-rel-pie.s diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 2768f1865a2d..798e8c6d17a3 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -113,9 +113,11 @@ bool SymbolBody::isPreemptible() const { if (isLocal()) return false; - // Shared symbols resolve to the definition in the DSO. + // Shared symbols resolve to the definition in the DSO. The exceptions are + // symbols with copy relocations (which resolve to .bss) or preempt plt + // entries (which resolve to that plt entry). if (isShared()) - return true; + return !NeedsCopyOrPltAddr; // That's all that can be preempted in a non-DSO. if (!Config->Shared) diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 6937dd59f88c..dfb99d4b8b46 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -606,13 +606,10 @@ void Writer::scanRelocs(InputSectionBase &C, ArrayRef Rels) { if (Offset == (uintX_t)-1) continue; + bool Preemptible = Body.isPreemptible(); Expr = adjustExpr(Body, IsWrite, Expr, Type); if (HasError) continue; - bool Preemptible = Body.isPreemptible(); - if (auto *B = dyn_cast>(&Body)) - if (B->needsCopy()) - Preemptible = false; // This relocation does not require got entry, but it is relative to got and // needs it to be created. Here we request for that. @@ -711,7 +708,7 @@ void Writer::scanRelocs(InputSectionBase &C, ArrayRef Rels) { continue; } - if (Preemptible) { + if (Body.isPreemptible()) { // We don't know anything about the finaly symbol. Just ask the dynamic // linker to handle the relocation for us. AddDyn({Target->getDynRel(Type), C.OutSec, Offset, false, &Body, Addend}); diff --git a/lld/test/ELF/Inputs/copy-rel-pie.s b/lld/test/ELF/Inputs/copy-rel-pie.s new file mode 100644 index 000000000000..6cd681fcecb4 --- /dev/null +++ b/lld/test/ELF/Inputs/copy-rel-pie.s @@ -0,0 +1,9 @@ +.global foo +.type foo, @object +.size foo, 4 +foo: +.long 0 + +.global bar +.type bar, @function +bar: diff --git a/lld/test/ELF/copy-rel-pie.s b/lld/test/ELF/copy-rel-pie.s new file mode 100644 index 000000000000..be7d5acaeba9 --- /dev/null +++ b/lld/test/ELF/copy-rel-pie.s @@ -0,0 +1,44 @@ +// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux +// RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux +// RUN: ld.lld %t2.o -o %t2.so -shared +// RUN: ld.lld %t.o %t2.so -o %t.exe -pie +// RUN: llvm-readobj -s -r %t.exe | FileCheck %s +// RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASM %s + +.global _start +_start: + call bar + call foo + +// CHECK: Name: .plt +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_EXECINSTR +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x1010 + +// CHECK: Name: .bss +// CHECK-NEXT: Type: SHT_NOBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x3020 + +// CHECK: Relocations [ +// CHECK-NEXT: Section (4) .rela.dyn { +// CHECK-NEXT: 0x3020 R_X86_64_COPY foo 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: Section (5) .rela.plt { +// CHECK-NEXT: 0x3018 R_X86_64_JUMP_SLOT bar 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: ] + +// (0x1010 + 0x10) - 0x1005 = 27 +// 0x3020 - 0x100a = 8214 + +// DISASM: Disassembly of section .text: +// DISASM-NEXT: _start: +// DISASM-NEXT: 1000: e8 1b 00 00 00 callq 27 +// DISASM-NEXT: 1005: e8 16 20 00 00 callq 8214 diff --git a/lld/test/ELF/mips-got-and-copy.s b/lld/test/ELF/mips-got-and-copy.s index 8501bd623e60..846bc245bc08 100644 --- a/lld/test/ELF/mips-got-and-copy.s +++ b/lld/test/ELF/mips-got-and-copy.s @@ -23,15 +23,21 @@ # CHECK-NEXT: Reserved entries [ # CHECK: ] # CHECK-NEXT: Local entries [ +# CHECK-NEXT: Entry { +# CHECK-NEXT: Address: 0x30008 +# CHECK-NEXT: Access: -32744 +# CHECK-NEXT: Initial: 0x40010 +# CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Global entries [ # CHECK-NEXT: Entry { -# CHECK: Section: .bss -# CHECK-NEXT: Name: data0 -# CHECK-NEXT: } -# CHECK-NEXT: Entry { -# CHECK: Section: .bss -# CHECK-NEXT: Name: data1 +# CHECK-NEXT: Address: 0x3000C +# CHECK-NEXT: Access: -32740 +# CHECK-NEXT: Initial: 0x40010 +# CHECK-NEXT: Value: 0x40010 +# CHECK-NEXT: Type: Object (0x1) +# CHECK-NEXT: Section: .bss (0xC) +# CHECK-NEXT: Name: data1@ (7) # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Number of TLS and multi-GOT entries: 0 diff --git a/lld/test/ELF/relro.s b/lld/test/ELF/relro.s index 692d6b271cf8..d35548740001 100644 --- a/lld/test/ELF/relro.s +++ b/lld/test/ELF/relro.s @@ -232,7 +232,7 @@ .global _start _start: .long bar - jmp *bar@GOTPCREL(%rip) + jmp *bar2@GOTPCREL(%rip) .section .data,"aw" .quad 0