From 3d044f57d490c225064b272359bb3ae845c55362 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Mon, 19 Mar 2018 06:52:51 +0000 Subject: [PATCH] [ELF] Recommit 327248 with Arm using the .got for _GLOBAL_OFFSET_TABLE_ This is the same as 327248 except Arm defining _GLOBAL_OFFSET_TABLE_ to be the base of the .got section as some existing code is relying upon it. For most Targets the _GLOBAL_OFFSET_TABLE_ symbol is expected to be at the start of the .got.plt section so that _GLOBAL_OFFSET_TABLE_[0] = reserved value that is by convention the address of the dynamic section. Previously we had defined _GLOBAL_OFFSET_TABLE_ as either the start or end of the .got section with the intention that the .got.plt section would follow the .got. However this does not always hold with the current default section ordering so _GLOBAL_OFFSET_TABLE_[0] may not be consistent with the reserved first entry of the .got.plt. X86, X86_64 and AArch64 will use the .got.plt. Arm, Mips and Power use .got Fixes PR36555 Differential Revision: https://reviews.llvm.org/D44259 llvm-svn: 327823 --- lld/ELF/Arch/ARM.cpp | 1 + lld/ELF/Arch/Mips.cpp | 1 + lld/ELF/Arch/PPC.cpp | 7 ++++- lld/ELF/Arch/X86.cpp | 1 - lld/ELF/Arch/X86_64.cpp | 1 - lld/ELF/SyntheticSections.cpp | 13 +++++++-- lld/ELF/SyntheticSections.h | 2 +- lld/ELF/Target.h | 5 ++-- lld/ELF/Writer.cpp | 11 ++++---- lld/test/ELF/dynamic-got.s | 27 +++++++++++++++---- .../global-offset-table-position-aarch64.s | 4 +-- .../ELF/global-offset-table-position-i386.s | 7 ++--- lld/test/ELF/global-offset-table-position.s | 7 ++--- lld/test/ELF/global_offset_table_shared.s | 4 +-- lld/test/ELF/got32x-i386.s | 6 ++--- lld/test/ELF/i386-gotpc.s | 14 +++++++--- 16 files changed, 77 insertions(+), 34 deletions(-) diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp index b9f551e4b3be..08091a629ad1 100644 --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -55,6 +55,7 @@ ARM::ARM() { TlsGotRel = R_ARM_TLS_TPOFF32; TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; TlsOffsetRel = R_ARM_TLS_DTPOFF32; + GotBaseSymInGotPlt = false; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index fcf5affb09ea..d8631b574c3b 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -50,6 +50,7 @@ template MIPS::MIPS() { DefaultMaxPageSize = 65536; GotEntrySize = sizeof(typename ELFT::uint); GotPltEntrySize = sizeof(typename ELFT::uint); + GotBaseSymInGotPlt = false; PltEntrySize = 16; PltHeaderSize = 32; CopyRel = R_MIPS_COPY; diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp index 6af0df331df6..20cae0e59cf4 100644 --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -21,13 +21,18 @@ using namespace lld::elf; namespace { class PPC final : public TargetInfo { public: - PPC() { GotBaseSymOff = 0x8000; } + PPC(); void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; }; } // namespace +PPC::PPC() { + GotBaseSymOff = 0x8000; + GotBaseSymInGotPlt = false; +} + RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp index bbaa3419a666..e638feb259d6 100644 --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -46,7 +46,6 @@ public: } // namespace X86::X86() { - GotBaseSymOff = -1; CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index f6f5038d87ce..512b1ffdf38d 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -51,7 +51,6 @@ private: } // namespace template X86_64::X86_64() { - GotBaseSymOff = -1; CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index f5fa0731e6b3..ef7944c81002 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -626,8 +626,9 @@ void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } bool GotSection::empty() const { // We need to emit a GOT even if it's empty if there's a relocation that is // relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT - // (i.e. _GLOBAL_OFFSET_TABLE_). - return NumEntries == 0 && !HasGotOffRel && !ElfSym::GlobalOffsetTable; + // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got. + return NumEntries == 0 && !HasGotOffRel && + !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt); } void GotSection::writeTo(uint8_t *Buf) { @@ -898,6 +899,14 @@ void GotPltSection::writeTo(uint8_t *Buf) { } } +bool GotPltSection::empty() const { + // We need to emit a GOT.PLT even if it's empty if there's a symbol that + // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol + // relative to the .got.plt section. + return Entries.empty() && + !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt); +} + // On ARM the IgotPltSection is part of the GotSection, on other Targets it is // part of the .got.plt IgotPltSection::IgotPltSection() diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 7f23d8282b61..23deb03c9ee3 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -270,7 +270,7 @@ public: void addEntry(Symbol &Sym); size_t getSize() const override; void writeTo(uint8_t *Buf) override; - bool empty() const override { return Entries.empty(); } + bool empty() const override; private: std::vector Entries; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index e29c9f4250cf..b0970097ee84 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -75,9 +75,10 @@ public: uint64_t getImageBase(); - // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for - // end of .got + // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got or .got.plt section. uint64_t GotBaseSymOff = 0; + // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. + bool GotBaseSymInGotPlt = true; // On systems with range extensions we place collections of Thunks at // regular spacings that enable the majority of branches reach the Thunks. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index a088cc5eb68d..2490d1d5aec7 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -869,11 +869,12 @@ void Writer::forEachRelSec(std::function Fn) { // defining these symbols explicitly in the linker script. template void Writer::setReservedSymbolSections() { if (ElfSym::GlobalOffsetTable) { - // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to - // be at some offset from the base of the .got section, usually 0 or the end - // of the .got - InputSection *GotSection = InX::MipsGot ? cast(InX::MipsGot) - : cast(InX::Got); + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually + // to the start of the .got or .got.plt section. + InputSection *GotSection = InX::GotPlt; + if (!Target->GotBaseSymInGotPlt) + GotSection = InX::MipsGot ? cast(InX::MipsGot) + : cast(InX::Got); ElfSym::GlobalOffsetTable->Section = GotSection; } diff --git a/lld/test/ELF/dynamic-got.s b/lld/test/ELF/dynamic-got.s index 385394b9d342..844e4f48b3f7 100644 --- a/lld/test/ELF/dynamic-got.s +++ b/lld/test/ELF/dynamic-got.s @@ -3,6 +3,23 @@ // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared // RUN: llvm-readobj -s -l -section-data -r %t.so | FileCheck %s +// CHECK: Name: .got.plt +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: +// CHECK-NEXT: Link: +// CHECK-NEXT: Info: +// CHECK-NEXT: AddressAlignment: +// CHECK-NEXT: EntrySize: +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 00300000 00000000 00000000 +// CHECK-NEXT: ) + // CHECK: Name: .got // CHECK-NEXT: Type: SHT_PROGBITS // CHECK-NEXT: Flags [ @@ -17,19 +34,19 @@ // CHECK-NEXT: AddressAlignment: // CHECK-NEXT: EntrySize: // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00200000 | +// CHECK-NEXT: 0000: 00300000 // CHECK-NEXT: ) // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rel.dyn { -// CHECK-NEXT: 0x2050 R_386_RELATIVE - 0x0 +// CHECK-NEXT: 0x3050 R_386_RELATIVE - 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK: Type: PT_DYNAMIC -// CHECK-NEXT: Offset: 0x2000 -// CHECK-NEXT: VirtualAddress: 0x2000 -// CHECK-NEXT: PhysicalAddress: 0x2000 +// CHECK-NEXT: Offset: 0x3000 +// CHECK-NEXT: VirtualAddress: 0x3000 +// CHECK-NEXT: PhysicalAddress: 0x3000 calll .L0$pb .L0$pb: diff --git a/lld/test/ELF/global-offset-table-position-aarch64.s b/lld/test/ELF/global-offset-table-position-aarch64.s index 68bc4a4254ed..8e26913dc73c 100644 --- a/lld/test/ELF/global-offset-table-position-aarch64.s +++ b/lld/test/ELF/global-offset-table-position-aarch64.s @@ -20,11 +20,11 @@ _start: .long _GLOBAL_OFFSET_TABLE_ - . // CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11) -// CHECK-NEXT: Value: 0x30090 +// CHECK-NEXT: Value: 0x20008 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local (0x0) // CHECK-NEXT: Type: None (0x0) // CHECK-NEXT: Other [ (0x2) // CHECK-NEXT: STV_HIDDEN (0x2) // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got +// CHECK-NEXT: Section: .got.plt diff --git a/lld/test/ELF/global-offset-table-position-i386.s b/lld/test/ELF/global-offset-table-position-i386.s index 9f778e1efb50..8d50b4990e97 100644 --- a/lld/test/ELF/global-offset-table-position-i386.s +++ b/lld/test/ELF/global-offset-table-position-i386.s @@ -3,7 +3,8 @@ // RUN: llvm-readobj -t %t2 | FileCheck %s // REQUIRES: x86 -// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section. +// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt +// section. .globl a .type a,@object .comm a,4,4 @@ -21,11 +22,11 @@ addl $_GLOBAL_OFFSET_TABLE_, %eax calll f@PLT // CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1) -// CHECK-NEXT: Value: 0x306C +// CHECK-NEXT: Value: 0x2000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local (0x0) // CHECK-NEXT: Type: None (0x0) // CHECK-NEXT: Other [ (0x2) // CHECK-NEXT: STV_HIDDEN (0x2) // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got (0xA) +// CHECK-NEXT: Section: .got.plt diff --git a/lld/test/ELF/global-offset-table-position.s b/lld/test/ELF/global-offset-table-position.s index f1195b2cf674..57fe6c804d7f 100644 --- a/lld/test/ELF/global-offset-table-position.s +++ b/lld/test/ELF/global-offset-table-position.s @@ -3,7 +3,8 @@ // RUN: llvm-readobj -t %t2 | FileCheck %s // REQUIRES: x86 -// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section. +// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt +// section. .globl a .type a,@object .comm a,4,4 @@ -21,11 +22,11 @@ callq f@PLT .long _GLOBAL_OFFSET_TABLE_ - . // CHECK: Name: _GLOBAL_OFFSET_TABLE_ -// CHECK-NEXT: Value: 0x30D8 +// CHECK-NEXT: Value: 0x2008 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local // CHECK-NEXT: Type: None (0x0) // CHECK-NEXT: Other [ // CHECK-NEXT: STV_HIDDEN // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got +// CHECK-NEXT: Section: .got.plt diff --git a/lld/test/ELF/global_offset_table_shared.s b/lld/test/ELF/global_offset_table_shared.s index 03af02e5805e..06bd7b3cd7ae 100644 --- a/lld/test/ELF/global_offset_table_shared.s +++ b/lld/test/ELF/global_offset_table_shared.s @@ -4,11 +4,11 @@ .long _GLOBAL_OFFSET_TABLE_ - . // CHECK: Name: _GLOBAL_OFFSET_TABLE_ -// CHECK-NEXT: Value: 0x2060 +// CHECK-NEXT: Value: 0x2000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local // CHECK-NEXT: Type: None // CHECK-NEXT: Other [ (0x2) // CHECK-NEXT: STV_HIDDEN (0x2) // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got +// CHECK-NEXT: Section: .got.plt diff --git a/lld/test/ELF/got32x-i386.s b/lld/test/ELF/got32x-i386.s index dd0b895c364b..610051e8a962 100644 --- a/lld/test/ELF/got32x-i386.s +++ b/lld/test/ELF/got32x-i386.s @@ -33,13 +33,13 @@ ## 73728 == 0x12000 == ADDR(.got) # CHECK: _start: -# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 73728, %eax -# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 73728, %ebx +# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 77824, %eax +# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 77824, %ebx # CHECK-NEXT: 1100d: 8b 80 {{.*}} movl -4(%eax), %eax # CHECK-NEXT: 11013: 8b 83 {{.*}} movl -4(%ebx), %eax # CHECK: Sections: # CHECK: Name Size Address -# CHECK: .got 00000004 0000000000012000 +# CHECK: .got 00000004 0000000000013000 # RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \ # RUN: FileCheck %s --check-prefix=ERR diff --git a/lld/test/ELF/i386-gotpc.s b/lld/test/ELF/i386-gotpc.s index d2c5ef3d469c..af8380b91153 100644 --- a/lld/test/ELF/i386-gotpc.s +++ b/lld/test/ELF/i386-gotpc.s @@ -6,15 +6,23 @@ movl $_GLOBAL_OFFSET_TABLE_, %eax +// CHECK: Name: .got.plt +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x2000 + // CHECK: Name: .got // CHECK-NEXT: Type: SHT_PROGBITS // CHECK-NEXT: Flags [ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_WRITE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x2030 +// CHECK-NEXT: Address: 0x3030 // DISASM: Disassembly of section .text: // DISASM-NEXT: .text: -// DISASM-NEXT: 1000: {{.*}} movl $4144, %eax -// 0x2030 - 0x1000 = 4144 +// DISASM-NEXT: 1000: {{.*}} movl $8240, %eax +// 0x3030 - 0x1000 = 0x2030