[lld] r284809 - [ELF][MIPS] Put local GOT entries accessed via a 16-bit index first

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 21 00:22:30 PDT 2016


Author: atanasyan
Date: Fri Oct 21 02:22:30 2016
New Revision: 284809

URL: http://llvm.org/viewvc/llvm-project?rev=284809&view=rev
Log:
[ELF][MIPS] Put local GOT entries accessed via a 16-bit index first

Some MIPS relocations used to access GOT entries are able to manipulate
16-bit index. The other ones like R_MIPS_CALL_HI16/LO16 can handle
32-bit indexes. 16-bit relocations are generated by default. The 32-bit
relocations are generated by -mxgot flag passed to compiler. Usually
these relocation are not mixed in the same code but files like crt*.o
contain 16-bit relocations so even if all "user's" code compiled with
-mxgot flag a few 16-bit relocations might come to the linking phase.

Now LLD does not differentiate local GOT entries accessed via a 16-bit
and 32-bit indexes. That might lead to relocation's overflow if 16-bit
entries are allocated to far from the beginning of the GOT.

The patch introduces new "part" of MIPS GOT dedicated to the local GOT
entries accessed by 32-bit relocations. That allows to put local GOT
entries accessed via a 16-bit index first and escape relocation's overflow.

Differential revision: https://reviews.llvm.org/D25833

Added:
    lld/trunk/test/ELF/mips-xgot-order.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Relocations.h
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Target.cpp

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Fri Oct 21 02:22:30 2016
@@ -325,6 +325,7 @@ static typename ELFT::uint getSymVA(uint
     // of sum the symbol's value and the addend.
     return Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
   case R_MIPS_GOT_OFF:
+  case R_MIPS_GOT_OFF32:
     // In case of MIPS if a GOT relocation has non-zero addend this addend
     // should be applied to the GOT entry content not to the GOT entry offset.
     // That is why we use separate expression type.

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Fri Oct 21 02:22:30 2016
@@ -202,8 +202,15 @@ void GotSection<ELFT>::addMipsEntry(Symb
     // Ignore addends for preemptible symbols. They got single GOT entry anyway.
     AddEntry(Sym, 0, MipsGlobal);
     Sym.IsInGlobalMipsGot = true;
-  } else
+  } else if (Expr == R_MIPS_GOT_OFF32) {
+    AddEntry(Sym, Addend, MipsLocal32);
+    Sym.Is32BitMipsGot = true;
+  } else {
+    // Hold local GOT entries accessed via a 16-bit index separately.
+    // That allows to write them in the beginning of the GOT and keep
+    // their indexes as less as possible to escape relocation's overflow.
     AddEntry(Sym, Addend, MipsLocal);
+  }
 }
 
 template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
@@ -250,6 +257,8 @@ GotSection<ELFT>::getMipsGotOffset(const
     GotBlockOff = getMipsTlsOffset();
   else if (B.IsInGlobalMipsGot)
     GotBlockOff = getMipsLocalEntriesNum() * sizeof(uintX_t);
+  else if (B.Is32BitMipsGot)
+    GotBlockOff = (MipsPageEntries + MipsLocal.size()) * sizeof(uintX_t);
   else
     GotBlockOff = MipsPageEntries * sizeof(uintX_t);
   // Calculate index of the GOT entry in the block.
@@ -288,7 +297,7 @@ const SymbolBody *GotSection<ELFT>::getM
 
 template <class ELFT>
 unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
-  return MipsPageEntries + MipsLocal.size();
+  return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
 }
 
 template <class ELFT> void GotSection<ELFT>::finalize() {
@@ -347,6 +356,7 @@ template <class ELFT> void GotSection<EL
     writeUint<ELFT>(Entry, VA);
   };
   std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
+  std::for_each(std::begin(MipsLocal32), std::end(MipsLocal32), AddEntry);
   std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
   // Initialize TLS-related GOT entries. If the entry has a corresponding
   // dynamic relocations, leave it initialized by zero. Write down adjusted

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Fri Oct 21 02:22:30 2016
@@ -217,6 +217,7 @@ private:
   typedef std::vector<MipsGotEntry> MipsGotEntries;
   llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
   MipsGotEntries MipsLocal;
+  MipsGotEntries MipsLocal32;
   MipsGotEntries MipsGlobal;
 
   // Write MIPS-specific parts of the GOT.

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Fri Oct 21 02:22:30 2016
@@ -62,10 +62,11 @@ namespace elf {
 
 static bool refersToGotEntry(RelExpr Expr) {
   return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE ||
-         Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_TLSGD ||
-         Expr == R_MIPS_TLSLD || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC ||
-         Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC ||
-         Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
+         Expr == R_MIPS_GOT_OFF || Expr == R_MIPS_GOT_OFF32 ||
+         Expr == R_MIPS_TLSGD || Expr == R_MIPS_TLSLD ||
+         Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC || Expr == R_GOT_FROM_END ||
+         Expr == R_TLSGD || Expr == R_TLSGD_PC || Expr == R_TLSDESC ||
+         Expr == R_TLSDESC_PAGE;
 }
 
 static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
@@ -303,11 +304,11 @@ static bool isStaticLinkTimeConstant(Rel
                                      const SymbolBody &Body) {
   // These expressions always compute a constant
   if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF ||
-      E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_MIPS_TLSGD ||
-      E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC ||
-      E == R_TLSGD_PC || E == R_TLSGD || E == R_PPC_PLT_OPD ||
-      E == R_TLSDESC_CALL || E == R_TLSDESC_PAGE || E == R_HINT ||
-      E == R_THUNK_PC || E == R_THUNK_PLT_PC)
+      E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF ||
+      E == R_MIPS_GOT_OFF32 || E == R_MIPS_TLSGD || E == R_GOT_PAGE_PC ||
+      E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || E == R_TLSGD ||
+      E == R_PPC_PLT_OPD || E == R_TLSDESC_CALL || E == R_TLSDESC_PAGE ||
+      E == R_HINT || E == R_THUNK_PC || E == R_THUNK_PLT_PC)
     return true;
 
   // These never do, except if the entire file is position dependent or if

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Fri Oct 21 02:22:30 2016
@@ -36,6 +36,7 @@ enum RelExpr {
   R_HINT,
   R_MIPS_GOT_LOCAL_PAGE,
   R_MIPS_GOT_OFF,
+  R_MIPS_GOT_OFF32,
   R_MIPS_TLSGD,
   R_MIPS_TLSLD,
   R_NEG_TLS,

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Fri Oct 21 02:22:30 2016
@@ -93,13 +93,13 @@ static typename ELFT::uint getSymVA(cons
 SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
                        uint8_t Type)
     : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
-      IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
-      NameOffset(NameOffset) {}
+      IsInGlobalMipsGot(false), Is32BitMipsGot(false), Type(Type),
+      StOther(StOther), NameOffset(NameOffset) {}
 
 SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
     : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
-      IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
-      Name({Name.data(), Name.size()}) {}
+      IsInGlobalMipsGot(false), Is32BitMipsGot(false), Type(Type),
+      StOther(StOther), Name({Name.data(), Name.size()}) {}
 
 StringRef SymbolBody::getName() const {
   assert(!isLocal());

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Fri Oct 21 02:22:30 2016
@@ -120,6 +120,9 @@ public:
   // True if this symbol has an entry in the global part of MIPS GOT.
   unsigned IsInGlobalMipsGot : 1;
 
+  // True if this symbol is referenced by 32-bit GOT relocations.
+  unsigned Is32BitMipsGot : 1;
+
   // The following fields have the same meaning as the ELF symbol attributes.
   uint8_t Type;    // symbol type
   uint8_t StOther; // st_other field value

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=284809&r1=284808&r2=284809&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Fri Oct 21 02:22:30 2016
@@ -1940,13 +1940,14 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr
       return R_MIPS_GOT_LOCAL_PAGE;
   // fallthrough
   case R_MIPS_CALL16:
+  case R_MIPS_GOT_DISP:
+  case R_MIPS_TLS_GOTTPREL:
+    return R_MIPS_GOT_OFF;
   case R_MIPS_CALL_HI16:
   case R_MIPS_CALL_LO16:
-  case R_MIPS_GOT_DISP:
   case R_MIPS_GOT_HI16:
   case R_MIPS_GOT_LO16:
-  case R_MIPS_TLS_GOTTPREL:
-    return R_MIPS_GOT_OFF;
+    return R_MIPS_GOT_OFF32;
   case R_MIPS_GOT_PAGE:
     return R_MIPS_GOT_LOCAL_PAGE;
   case R_MIPS_TLS_GD:

Added: lld/trunk/test/ELF/mips-xgot-order.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-xgot-order.s?rev=284809&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-xgot-order.s (added)
+++ lld/trunk/test/ELF/mips-xgot-order.s Fri Oct 21 02:22:30 2016
@@ -0,0 +1,48 @@
+# Check that GOT entries accessed via 16-bit indexing are allocated
+# in the beginning of the GOT.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    20000:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    20004:       8c 42 80 20     lw      $2, -32736($2)
+# CHECK-NEXT:    20008:       3c 02 00 00     lui     $2, 0
+# CHECK-NEXT:    2000c:       8c 42 80 24     lw      $2, -32732($2)
+#
+# CHECK:      bar:
+# CHECK-NEXT:    20010:       8c 42 80 1c     lw      $2, -32740($2)
+# CHECK-NEXT:    20014:       8c 42 80 18     lw      $2, -32744($2)
+# CHECK-NEXT:    20018:       20 42 00 00     addi    $2, $2, 0
+
+# CHECK:      Contents of section .got:
+# CHECK-NEXT:  30000 00000000 80000000 00040000 00020010
+#                                      ^ %hi(loc)
+#                                               ^ %got(bar)
+# CHECK-NEXT:  30010 00020000 00040000
+#                    ^ %got_hi/lo(start)
+#                             ^ %got_hi/lo(loc)
+
+# CHECK: 00040000         .data           00000000 loc
+# CHECK: 00020000         .text           00000000 __start
+# CHECK: 00020010         .text           00000000 bar
+
+  .text
+  .global __start, bar
+__start:
+  lui   $2, %got_hi(__start)
+  lw    $2, %got_lo(__start)($2)
+  lui   $2, %got_hi(loc)
+  lw    $2, %got_lo(loc)($2)
+bar:
+  lw    $2, %got(bar)($2)
+  lw    $2, %got(loc)($2)
+  addi  $2, $2, %lo(loc)
+
+  .data
+loc:
+  .word 0




More information about the llvm-commits mailing list