[lld] r306282 - [ELF] Define _GLOBAL_OFFSET_TABLE_ symbol relative to .got

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 26 03:22:17 PDT 2017


Author: psmith
Date: Mon Jun 26 03:22:17 2017
New Revision: 306282

URL: http://llvm.org/viewvc/llvm-project?rev=306282&view=rev
Log:
[ELF] Define _GLOBAL_OFFSET_TABLE_ symbol relative to .got

On many architectures gcc and clang will recognize _GLOBAL_OFFSET_TABLE_ - .
and produce a relocation that can be processed without needing to know the
value of _GLOBAL_OFFSET_TABLE_. This is not always the case; for example ARM
gcc produces R_ARM_BASE_PREL but clang produces the more general
R_ARM_REL32 to _GLOBAL_OFFSET_TABLE_. To evaluate this relocation
correctly _GLOBAL_OFFSET_TABLE_ must be defined to be the either the base of
the GOT or end of the GOT dependent on architecture..

If/when llvm-mc is changed to recognize _GLOBAL_OFFSET_TABLE_ - . this
change will not be necessary for new objects. However there may still be
old objects and versions of clang.

Differential Revision: https://reviews.llvm.org/D34355


Added:
    lld/trunk/test/ELF/global-offset-table-position-aarch64.s
    lld/trunk/test/ELF/global-offset-table-position-arm.s
    lld/trunk/test/ELF/global-offset-table-position-i386.s
    lld/trunk/test/ELF/global-offset-table-position-mips.s
    lld/trunk/test/ELF/global-offset-table-position.s
Modified:
    lld/trunk/ELF/Arch/PPC.cpp
    lld/trunk/ELF/Arch/X86.cpp
    lld/trunk/ELF/Arch/X86_64.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Target.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/arm-got-relative.s
    lld/trunk/test/ELF/global_offset_table_shared.s

Modified: lld/trunk/ELF/Arch/PPC.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC.cpp?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC.cpp (original)
+++ lld/trunk/ELF/Arch/PPC.cpp Mon Jun 26 03:22:17 2017
@@ -21,7 +21,7 @@ using namespace lld::elf;
 namespace {
 class PPC final : public TargetInfo {
 public:
-  PPC() {}
+  PPC() { GotBaseSymOff = 0x8000; }
   void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
   RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
                      const uint8_t *Loc) const override;

Modified: lld/trunk/ELF/Arch/X86.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/X86.cpp?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/X86.cpp (original)
+++ lld/trunk/ELF/Arch/X86.cpp Mon Jun 26 03:22:17 2017
@@ -46,6 +46,7 @@ public:
 } // namespace
 
 X86::X86() {
+  GotBaseSymOff = -1;
   CopyRel = R_386_COPY;
   GotRel = R_386_GLOB_DAT;
   PltRel = R_386_JUMP_SLOT;

Modified: lld/trunk/ELF/Arch/X86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/X86_64.cpp?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/X86_64.cpp (original)
+++ lld/trunk/ELF/Arch/X86_64.cpp Mon Jun 26 03:22:17 2017
@@ -51,6 +51,7 @@ private:
 } // namespace
 
 template <class ELFT> X86_64<ELFT>::X86_64() {
+  GotBaseSymOff = -1;
   CopyRel = R_X86_64_COPY;
   GotRel = R_X86_64_GLOB_DAT;
   PltRel = R_X86_64_JUMP_SLOT;

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Mon Jun 26 03:22:17 2017
@@ -361,7 +361,7 @@ static bool isStaticLinkTimeConstant(Rel
   // These expressions always compute a constant
   if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
                      R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
-                     R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC,
+                     R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
                      R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
                      R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
     return true;

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Mon Jun 26 03:22:17 2017
@@ -66,6 +66,10 @@ public:
   // Given that, the smallest value that can be used in here is 0x10000.
   uint64_t DefaultImageBase = 0x10000;
 
+  // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for
+  // end of .got
+  uint64_t GotBaseSymOff = 0;
+
   uint32_t CopyRel;
   uint32_t GotRel;
   uint32_t PltRel;

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Jun 26 03:22:17 2017
@@ -87,6 +87,8 @@ private:
 
   uint64_t FileSize;
   uint64_t SectionHeaderOff;
+
+  bool HasGotBaseSym = false;
 };
 } // anonymous namespace
 
@@ -815,19 +817,13 @@ template <class ELFT> void Writer<ELFT>:
           Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL);
   }
 
-  // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
-  // is magical and is used to produce a R_386_GOTPC relocation.
-  // The R_386_GOTPC relocation value doesn't actually depend on the
-  // symbol value, so it could use an index of STN_UNDEF which, according
-  // to the spec, means the symbol value is 0.
-  // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
-  // the object file.
-  // The situation is even stranger on x86_64 where the assembly doesn't
-  // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
-  // an undefined symbol in the .o files.
-  // Given that the symbol is effectively unused, we just create a dummy
-  // hidden one to avoid the undefined symbol error.
-  Symtab<ELFT>::X->addIgnored("_GLOBAL_OFFSET_TABLE_");
+  // 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<InputSection>(InX::MipsGot)
+                                            : cast<InputSection>(InX::Got);
+  HasGotBaseSym = addOptionalRegular<ELFT>("_GLOBAL_OFFSET_TABLE_", GotSection,
+                                           Target->GotBaseSymOff) != nullptr;
 
   // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
   // static linking the linker is required to optimize away any references to
@@ -1136,7 +1132,8 @@ static void applySynthetic(const std::ve
 // to make them visible from linkescript side. But not all sections are always
 // required to be in output. For example we don't need dynamic section content
 // sometimes. This function filters out such unused sections from the output.
-static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) {
+static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V,
+                                          bool HasGotBaseSym) {
   // All input synthetic sections that can be empty are placed after
   // all regular ones. We iterate over them all and exit at first
   // non-synthetic.
@@ -1147,6 +1144,8 @@ static void removeUnusedSyntheticSection
     OutputSection *OS = SS->getParent();
     if (!SS->empty() || !OS)
       continue;
+    if ((SS == InX::Got || SS == InX::MipsGot) && HasGotBaseSym)
+      continue;
     OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS));
     SS->Live = false;
     // If there are no other sections in the output section, remove it from the
@@ -1220,7 +1219,7 @@ template <class ELFT> void Writer<ELFT>:
     return;
 
   addPredefinedSections();
-  removeUnusedSyntheticSections(OutputSections);
+  removeUnusedSyntheticSections(OutputSections, HasGotBaseSym);
 
   clearOutputSections();
   sortSections();

Modified: lld/trunk/test/ELF/arm-got-relative.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-got-relative.s?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/test/ELF/arm-got-relative.s (original)
+++ lld/trunk/test/ELF/arm-got-relative.s Mon Jun 26 03:22:17 2017
@@ -16,9 +16,9 @@ _start:
  bx lr
  .align 2
 .LGOT:
- // gas implicitly uses (GOT_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC
- // llvm-mc needs the (GOT_PREL) suffix or it generates R_ARM_REL32
- .word _GLOBAL_OFFSET_TABLE_(GOT_PREL) - (.LPIC+8)
+ // gas implicitly uses (R_ARM_BASE_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC
+ // llvm-mc generates R_ARM_REL32, this will need updating when MC changes
+ .word _GLOBAL_OFFSET_TABLE_ - (.LPIC+8)
  .word function(GOT)
 
  .globl function
@@ -28,17 +28,17 @@ function:
  bx lr
 
 // CHECK: Dynamic Relocations {
-// CHECK-NEXT:  0x204C R_ARM_GLOB_DAT function 0x0
+// CHECK-NEXT:  0x2048 R_ARM_GLOB_DAT function 0x0
 
 // CHECK: Name: _GLOBAL_OFFSET_TABLE_
-// CHECK-NEXT:    Value: 0x0
+// CHECK-NEXT:    Value: 0x2048
 // CHECK-NEXT:    Size:
 // CHECK-NEXT:    Binding: Local
 // CHECK-NEXT:    Type: None
 // CHECK-NEXT:    Other [
 // CHECK-NEXT:      STV_HIDDEN
 // CHECK-NEXT:    ]
-// CHECK-NEXT:    Section: Absolute
+// CHECK-NEXT:    Section: .got
 
 // CODE: Disassembly of section .text:
 // CODE-NEXT: _start:
@@ -49,5 +49,5 @@ function:
 // CODE:$d.1:
 // (_GLOBAL_OFFSET_TABLE_ = 0x2048) - (0x1008 + 8) 0x1038
 // CODE-NEXT:    1010:        38 10 00 00
-// (Got(function) - GotBase = 0x4
-// CODE-NEXT:    1014:        04 00 00 00
+// (Got(function) - GotBase = 0x0
+// CODE-NEXT:    1014:        00 00 00 00

Added: lld/trunk/test/ELF/global-offset-table-position-aarch64.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/global-offset-table-position-aarch64.s?rev=306282&view=auto
==============================================================================
--- lld/trunk/test/ELF/global-offset-table-position-aarch64.s (added)
+++ lld/trunk/test/ELF/global-offset-table-position-aarch64.s Mon Jun 26 03:22:17 2017
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: aarch64
+.globl  a
+.type   a, at object
+.comm   a,4,4
+
+.globl  f
+.type   f, at function
+f:
+ adrp   x0, :got:a
+ ldr    x0, [x0, #:got_lo12:a]
+
+.global _start
+.type _start, at function
+_start:
+ bl f
+.data
+.long _GLOBAL_OFFSET_TABLE_ - .
+
+// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11)
+// CHECK-NEXT:     Value: 0x30090
+// 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

Added: lld/trunk/test/ELF/global-offset-table-position-arm.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/global-offset-table-position-arm.s?rev=306282&view=auto
==============================================================================
--- lld/trunk/test/ELF/global-offset-table-position-arm.s (added)
+++ lld/trunk/test/ELF/global-offset-table-position-arm.s Mon Jun 26 03:22:17 2017
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: arm
+
+// The ARM _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
+.globl  a
+.type   a,%object
+.comm   a,4,4
+
+.globl  f
+.type   f,%function
+f:
+ ldr r2, .L1
+.L0:
+ add r2, pc
+.L1:
+.word _GLOBAL_OFFSET_TABLE_ - (.L0+4)
+.word a(GOT)
+
+.global _start
+.type _start,%function
+_start:
+ bl f
+.data
+
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT:     Value: 0x3068
+// 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

Added: lld/trunk/test/ELF/global-offset-table-position-i386.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/global-offset-table-position-i386.s?rev=306282&view=auto
==============================================================================
--- lld/trunk/test/ELF/global-offset-table-position-i386.s (added)
+++ lld/trunk/test/ELF/global-offset-table-position-i386.s Mon Jun 26 03:22:17 2017
@@ -0,0 +1,31 @@
+// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
+.globl  a
+.type   a, at object
+.comm   a,4,4
+
+.globl  f
+.type   f, at function
+f:
+addl    $_GLOBAL_OFFSET_TABLE_, %eax
+movl    a at GOT(%eax), %eax
+
+.global _start
+.type _start, at function
+_start:
+addl    $_GLOBAL_OFFSET_TABLE_, %eax
+calll   f at PLT
+
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_ (1)
+// CHECK-NEXT:     Value: 0x306C
+// 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)

Added: lld/trunk/test/ELF/global-offset-table-position-mips.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/global-offset-table-position-mips.s?rev=306282&view=auto
==============================================================================
--- lld/trunk/test/ELF/global-offset-table-position-mips.s (added)
+++ lld/trunk/test/ELF/global-offset-table-position-mips.s Mon Jun 26 03:22:17 2017
@@ -0,0 +1,33 @@
+// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+
+// REQUIRES: mips
+
+// The Mips _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got
+
+.globl  a
+.hidden a
+.type   a, at object
+.comm   a,4,4
+
+.globl  f
+.type   f, at function
+f:
+ ld      $v0,%got_page(a)($gp)
+ daddiu  $v0,$v0,%got_ofst(a)
+
+.global _start
+.type _start, at function
+_start:
+ lw      $t0,%call16(f)($gp)
+ .word _GLOBAL_OFFSET_TABLE_ - .
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_ (1)
+// CHECK-NEXT:     Value: 0x20000
+// 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 (0x9)

Added: lld/trunk/test/ELF/global-offset-table-position.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/global-offset-table-position.s?rev=306282&view=auto
==============================================================================
--- lld/trunk/test/ELF/global-offset-table-position.s (added)
+++ lld/trunk/test/ELF/global-offset-table-position.s Mon Jun 26 03:22:17 2017
@@ -0,0 +1,31 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: ld.lld -shared %t -o %t2
+// RUN: llvm-readobj -t %t2 | FileCheck %s
+// REQUIRES: x86
+
+// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section.
+.globl  a
+.type   a, at object
+.comm   a,4,4
+
+.globl  f
+.type   f, at function
+f:
+movq	a at GOTPCREL(%rip), %rax
+
+.global _start
+.type _start, at function
+_start:
+callq	f at PLT
+.data
+.long _GLOBAL_OFFSET_TABLE_ - .
+
+// CHECK:     Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT:     Value: 0x30D8
+// 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

Modified: lld/trunk/test/ELF/global_offset_table_shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/global_offset_table_shared.s?rev=306282&r1=306281&r2=306282&view=diff
==============================================================================
--- lld/trunk/test/ELF/global_offset_table_shared.s (original)
+++ lld/trunk/test/ELF/global_offset_table_shared.s Mon Jun 26 03:22:17 2017
@@ -1,9 +1,14 @@
 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
 // RUN: ld.lld -shared %t -o %t2
 // RUN: llvm-readobj -t %t2 | FileCheck %s
-.long _GLOBAL_OFFSET_TABLE_
+.long _GLOBAL_OFFSET_TABLE_ - .
 
 // CHECK:      Name: _GLOBAL_OFFSET_TABLE_
-// CHECK-NEXT: Value:
+// CHECK-NEXT: Value: 0x2060
 // 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




More information about the llvm-commits mailing list