[lld] r258388 - [ELF][MIPS] Initial support of MIPS local GOT entries

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 20 21:33:24 PST 2016


Author: atanasyan
Date: Wed Jan 20 23:33:23 2016
New Revision: 258388

URL: http://llvm.org/viewvc/llvm-project?rev=258388&view=rev
Log:
[ELF][MIPS] Initial support of MIPS local GOT entries

Some MIPS relocation (for now R_MIPS_GOT16) requires creation of GOT
entries for symbol not included in the dynamic symbol table. They are
local symbols and non-local symbols with 'local' visibility. Local GOT
entries occupy continuous block between GOT header and regular GOT
entries.

The patch adds initial support for handling local GOT entries. The main
problem is allocating local GOT entries for local symbols. Such entries
should be initialized by high 16-bit of the symbol value. In ideal world
there should be no duplicated entries with the same values. But at the
moment of the `Writer::scanRelocs` call we do not know a value of the
symbol. In this patch we create new local GOT entry for each relocation
against local symbol, though we can exhaust GOT quickly. That needs to
be optimized later. When we calculate relocation we know a final symbol
value and request local GOT entry index. To do that we maintain map
between addresses and local GOT entry indexes. If we start to calculate
relocations in parallel we will have to serialize access to this map.

Differential Revision: http://reviews.llvm.org/D16324

Added:
    lld/trunk/test/ELF/mips-got16.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=258388&r1=258387&r2=258388&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed Jan 20 23:33:23 2016
@@ -189,12 +189,18 @@ void InputSectionBase<ELFT>::relocate(ui
     uintX_t A = getAddend<ELFT>(RI);
     if (!Body) {
       uintX_t SymVA = getLocalRelTarget(*File, RI, A);
-      // We need to adjust SymVA value in case of R_MIPS_GPREL16/32 relocations
-      // because they use the following expression to calculate the relocation's
-      // result for local symbol: S + A + GP0 - G.
-      if (Config->EMachine == EM_MIPS &&
-          (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32))
-        SymVA += File->getMipsGp0();
+      if (Config->EMachine == EM_MIPS) {
+        if (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32)
+          // We need to adjust SymVA value in case of R_MIPS_GPREL16/32
+          // relocations because they use the following expression to calculate
+          // the relocation's result for local symbol: S + A + GP0 - G.
+          SymVA += File->getMipsGp0();
+        else if (Type == R_MIPS_GOT16)
+          // R_MIPS_GOT16 relocation against local symbol requires index of
+          // a local GOT entry which contains page address corresponds
+          // to the symbol address.
+          SymVA = Out<ELFT>::Got->getMipsLocalPageAddr(SymVA);
+      }
       Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0,
                           findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
       continue;
@@ -212,7 +218,13 @@ void InputSectionBase<ELFT>::relocate(ui
     if (Target->relocNeedsPlt(Type, *Body)) {
       SymVA = Out<ELFT>::Plt->getEntryAddr(*Body);
     } else if (Target->relocNeedsGot(Type, *Body)) {
-      SymVA = Out<ELFT>::Got->getEntryAddr(*Body);
+      if (Config->EMachine == EM_MIPS && needsMipsLocalGot(Type, Body))
+        // Under some conditions relocations against non-local symbols require
+        // entries in the local part of MIPS GOT. In that case we need an entry
+        // initialized by full address of the symbol.
+        SymVA = Out<ELFT>::Got->getMipsLocalFullAddr(*Body);
+      else
+        SymVA = Out<ELFT>::Got->getEntryAddr(*Body);
       if (Body->isTls())
         Type = Target->getTlsGotReloc(Type);
     } else if (!Target->needsCopyRel(Type, *Body) &&

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=258388&r1=258387&r2=258388&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Wed Jan 20 23:33:23 2016
@@ -78,10 +78,14 @@ GotSection<ELFT>::GotSection()
 }
 
 template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) {
-  Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size();
+  Sym->GotIndex = Entries.size();
   Entries.push_back(Sym);
 }
 
+template <class ELFT> void GotSection<ELFT>::addMipsLocalEntry() {
+  ++MipsLocalEntries;
+}
+
 template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody *Sym) {
   if (Sym->hasGlobalDynIndex())
     return false;
@@ -104,7 +108,32 @@ template <class ELFT> bool GotSection<EL
 template <class ELFT>
 typename GotSection<ELFT>::uintX_t
 GotSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
-  return this->getVA() + B.GotIndex * sizeof(uintX_t);
+  return this->getVA() +
+         (Target->getGotHeaderEntriesNum() + MipsLocalEntries + B.GotIndex) *
+             sizeof(uintX_t);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getMipsLocalFullAddr(const SymbolBody &B) {
+  return getMipsLocalEntryAddr(getSymVA<ELFT>(B));
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getMipsLocalPageAddr(uintX_t EntryValue) {
+  // Initialize the entry by the %hi(EntryValue) expression
+  // but without right-shifting.
+  return getMipsLocalEntryAddr((EntryValue + 0x8000) & ~0xffff);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getMipsLocalEntryAddr(uintX_t EntryValue) {
+  size_t NewIndex = Target->getGotHeaderEntriesNum() + MipsLocalGotPos.size();
+  auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
+  assert(!P.second || MipsLocalGotPos.size() <= MipsLocalEntries);
+  return this->getVA() + P.first->second * sizeof(uintX_t);
 }
 
 template <class ELFT>
@@ -120,18 +149,23 @@ const SymbolBody *GotSection<ELFT>::getM
 
 template <class ELFT>
 unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
-  // TODO: Update when the support of GOT entries for local symbols is added.
-  return Target->getGotHeaderEntriesNum();
+  return Target->getGotHeaderEntriesNum() + MipsLocalEntries;
 }
 
 template <class ELFT> void GotSection<ELFT>::finalize() {
   this->Header.sh_size =
-      (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t);
+      (Target->getGotHeaderEntriesNum() + MipsLocalEntries + Entries.size()) *
+      sizeof(uintX_t);
 }
 
 template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
   Target->writeGotHeaderEntries(Buf);
+  for (const auto &L : MipsLocalGotPos) {
+    uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
+    write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
+  }
   Buf += Target->getGotHeaderEntriesNum() * sizeof(uintX_t);
+  Buf += MipsLocalEntries * sizeof(uintX_t);
   for (const SymbolBody *B : Entries) {
     uint8_t *Entry = Buf;
     Buf += sizeof(uintX_t);

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=258388&r1=258387&r2=258388&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Wed Jan 20 23:33:23 2016
@@ -123,10 +123,13 @@ public:
   void finalize() override;
   void writeTo(uint8_t *Buf) override;
   void addEntry(SymbolBody *Sym);
+  void addMipsLocalEntry();
   bool addDynTlsEntry(SymbolBody *Sym);
   bool addCurrentModuleTlsIndex();
-  bool empty() const { return Entries.empty(); }
+  bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); }
   uintX_t getEntryAddr(const SymbolBody &B) const;
+  uintX_t getMipsLocalFullAddr(const SymbolBody &B);
+  uintX_t getMipsLocalPageAddr(uintX_t Addr);
   uintX_t getGlobalDynAddr(const SymbolBody &B) const;
   uintX_t getNumEntries() const { return Entries.size(); }
 
@@ -145,6 +148,10 @@ public:
 private:
   std::vector<const SymbolBody *> Entries;
   uint32_t LocalTlsIndexOff = -1;
+  uint32_t MipsLocalEntries = 0;
+  llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
+
+  uintX_t getMipsLocalEntryAddr(uintX_t EntryValue);
 };
 
 template <class ELFT>

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=258388&r1=258387&r2=258388&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Wed Jan 20 23:33:23 2016
@@ -1634,6 +1634,20 @@ template <class ELFT> typename ELFFile<E
   return 0;
 }
 
+bool needsMipsLocalGot(uint32_t Type, SymbolBody *Body) {
+  // The R_MIPS_GOT16 relocation requires creation of entry in the local part
+  // of GOT if its target is a local symbol or non-local symbol with 'local'
+  // visibility.
+  if (Type != R_MIPS_GOT16)
+    return false;
+  if (!Body)
+    return true;
+  uint8_t V = Body->getVisibility();
+  if (V != STV_DEFAULT && V != STV_PROTECTED)
+    return true;
+  return !Config->Shared;
+}
+
 template uint32_t getMipsGpAddr<ELF32LE>();
 template uint32_t getMipsGpAddr<ELF32BE>();
 template uint64_t getMipsGpAddr<ELF64LE>();

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=258388&r1=258387&r2=258388&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Wed Jan 20 23:33:23 2016
@@ -118,6 +118,9 @@ uint64_t getPPC64TocBase();
 template <class ELFT>
 typename llvm::object::ELFFile<ELFT>::uintX_t getMipsGpAddr();
 
+// Returns true if the relocation requires entry in the local part of GOT.
+bool needsMipsLocalGot(uint32_t Type, SymbolBody *Body);
+
 template <class ELFT> bool isGnuIFunc(const SymbolBody &S);
 
 extern std::unique_ptr<TargetInfo> Target;

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=258388&r1=258387&r2=258388&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Jan 20 23:33:23 2016
@@ -258,8 +258,13 @@ void Writer<ELFT>::scanRelocs(
     }
 
     bool NeedsGot = false;
+    bool NeedsMipsLocalGot = false;
     bool NeedsPlt = false;
-    if (Body) {
+    if (Config->EMachine == EM_MIPS && needsMipsLocalGot(Type, Body)) {
+      NeedsMipsLocalGot = true;
+      // FIXME (simon): Do not add so many redundant entries.
+      Out<ELFT>::Got->addMipsLocalEntry();
+    } else if (Body) {
       if (auto *E = dyn_cast<SharedSymbol<ELFT>>(Body)) {
         if (E->NeedsCopy)
           continue;
@@ -294,13 +299,23 @@ void Writer<ELFT>::scanRelocs(
     }
 
     if (Config->EMachine == EM_MIPS) {
-      if (NeedsGot) {
+      if (Type == R_MIPS_LO16)
+        // Ignore R_MIPS_LO16 relocation. If it is a pair for R_MIPS_GOT16 we
+        // already completed all required action (GOT entry allocation) when
+        // handle R_MIPS_GOT16a. If it is a pair for R_MIPS_HI16 against
+        // _gp_disp it does not require dynamic relocation. If its a pair for
+        // R_MIPS_HI16 against a regular symbol it does not require dynamic
+        // relocation too because that case is possible for executable file
+        // linking only.
+        continue;
+      if (NeedsGot || NeedsMipsLocalGot) {
         // MIPS ABI has special rules to process GOT entries
         // and doesn't require relocation entries for them.
         // See "Global Offset Table" in Chapter 5 in the following document
         // for detailed description:
         // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-        Body->setUsedInDynamicReloc();
+        if (NeedsGot)
+          Body->setUsedInDynamicReloc();
         continue;
       }
       if (Body == Config->MipsGpDisp)

Added: lld/trunk/test/ELF/mips-got16.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-got16.s?rev=258388&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-got16.s (added)
+++ lld/trunk/test/ELF/mips-got16.s Wed Jan 20 23:33:23 2016
@@ -0,0 +1,95 @@
+# Check R_MIPS_GOT16 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-objdump -d -t %t.so | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:    10000:       8f 88 80 18     lw      $8, -32744($gp)
+# CHECK-NEXT:    10004:       21 08 00 1c     addi    $8, $8, 28
+# CHECK-NEXT:    10008:       8f 88 80 1c     lw      $8, -32740($gp)
+# CHECK-NEXT:    1000c:       21 08 00 00     addi    $8, $8, 0
+# CHECK-NEXT:    10010:       8f 88 80 20     lw      $8, -32736($gp)
+# CHECK-NEXT:    10014:       21 08 00 04     addi    $8, $8, 4
+# CHECK-NEXT:    10018:       8f 88 80 24     lw      $8, -32732($gp)
+#
+# CHECK: SYMBOL TABLE:
+# CHECK: 0001001c         .text           00000000 $LC0
+# CHECK: 00030000         .data           00000000 $LC1
+# CHECK: 00030004         .data           00000000 .hidden bar
+# CHECK: 00000000         *UND*           00000000 foo
+
+# GOT:      Relocations [
+# GOT-NEXT: ]
+
+# GOT:      Primary GOT {
+# GOT-NEXT:   Canonical gp value: 0x27FF0
+# GOT-NEXT:   Reserved entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20000
+# GOT-NEXT:       Access: -32752
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Purpose: Lazy resolver
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20004
+# GOT-NEXT:       Access: -32748
+# GOT-NEXT:       Initial: 0x80000000
+# GOT-NEXT:       Purpose: Module pointer (GNU extension)
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Local entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20008
+# GOT-NEXT:       Access: -32744
+# GOT-NEXT:       Initial: 0x10000
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x2000C
+# GOT-NEXT:       Access: -32740
+# GOT-NEXT:       Initial: 0x30000
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20010
+# GOT-NEXT:       Access: -32736
+# GOT-NEXT:       Initial: 0x30004
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20014
+# GOT-NEXT:       Access: -32732
+# GOT-NEXT:       Initial: 0x0
+# GOT-NEXT:       Value: 0x0
+# GOT-NEXT:       Type: None
+# GOT-NEXT:       Section: Undefined
+# GOT-NEXT:       Name: foo@
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%got($LC0)($gp)
+  addi    $t0,$t0,%lo($LC0)
+  lw      $t0,%got($LC1)($gp)
+  addi    $t0,$t0,%lo($LC1)
+  lw      $t0,%got(bar)($gp)
+  addi    $t0,$t0,%lo(bar)
+  lw      $t0,%got(foo)($gp)
+$LC0:
+  nop
+
+  .data
+$LC1:
+  .word 0
+.global bar
+.hidden bar
+bar:
+  .word 0




More information about the llvm-commits mailing list