[lld] r256416 - [ELF][MIPS] Implement R_MIPS_GPREL16/R_MIPS_GPREL32 relocations

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 25 05:02:16 PST 2015


Author: atanasyan
Date: Fri Dec 25 07:02:13 2015
New Revision: 256416

URL: http://llvm.org/viewvc/llvm-project?rev=256416&view=rev
Log:
[ELF][MIPS] Implement R_MIPS_GPREL16/R_MIPS_GPREL32 relocations

The R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations use the following
expressions for calculations:
```
local symbol:  S + A + GP0 - GP
global symbol: S + A - GP

GP  - Represents the final gp value, i.e. _gp symbol
GP0 - Represents the gp value used to create the relocatable object
```
The GP0 value is taken from the .reginfo data section defined by an object
file. To implement that I keep a reference to `MipsReginfoInputSection`
in the `ObjectFile` class. This reference is used by the
`ObjectFile::getMipsGp0` method to return the GP0 value.

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

Added:
    lld/trunk/test/ELF/mips-gprel32-relocs.test
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/Target.cpp

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=256416&r1=256415&r2=256416&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Fri Dec 25 07:02:13 2015
@@ -93,6 +93,10 @@ typename ObjectFile<ELFT>::Elf_Sym_Range
   return this->getSymbolsHelper(true);
 }
 
+template <class ELFT> uint32_t ObjectFile<ELFT>::getMipsGp0() const {
+  return MipsReginfo ? MipsReginfo->getGp0() : 0;
+}
+
 template <class ELFT>
 const typename ObjectFile<ELFT>::Elf_Sym *
 ObjectFile<ELFT>::getLocalSymbol(uintX_t SymIndex) {
@@ -245,8 +249,10 @@ elf2::ObjectFile<ELFT>::createInputSecti
 
   // A MIPS object file has a special section that contains register
   // usage info, which needs to be handled by the linker specially.
-  if (Config->EMachine == EM_MIPS && Name == ".reginfo")
-    return new (this->Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
+  if (Config->EMachine == EM_MIPS && Name == ".reginfo") {
+    MipsReginfo = new (this->Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
+    return MipsReginfo;
+  }
 
   if (Name == ".eh_frame")
     return new (this->EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec);

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=256416&r1=256415&r2=256416&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri Dec 25 07:02:13 2015
@@ -121,6 +121,11 @@ public:
 
   const Elf_Shdr *getSymbolTable() const { return this->Symtab; };
 
+  // Get MIPS GP0 value defined by this file. This value represents the gp value
+  // used to create the relocatable object and required to support
+  // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
+  uint32_t getMipsGp0() const;
+
 private:
   void initializeSections(llvm::DenseSet<StringRef> &Comdats);
   void initializeSymbols();
@@ -134,6 +139,9 @@ private:
   // List of all symbols referenced or defined by this file.
   std::vector<SymbolBody *> SymbolBodies;
 
+  // MIPS .reginfo section defined by this file.
+  MipsReginfoInputSection<ELFT> *MipsReginfo = nullptr;
+
   llvm::BumpPtrAllocator Alloc;
   llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc;
   llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc;

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=256416&r1=256415&r2=256416&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Fri Dec 25 07:02:13 2015
@@ -187,6 +187,12 @@ 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();
       Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0,
                           findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
       continue;
@@ -351,6 +357,13 @@ uint32_t MipsReginfoInputSection<ELFT>::
   return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gprmask;
 }
 
+template <class ELFT> uint32_t MipsReginfoInputSection<ELFT>::getGp0() const {
+  ArrayRef<uint8_t> D = this->getSectionData();
+  if (D.size() != sizeof(Elf_Mips_RegInfo))
+    error("Invalid size of .reginfo section");
+  return reinterpret_cast<const Elf_Mips_RegInfo *>(D.data())->ri_gp_value;
+}
+
 template <class ELFT>
 bool MipsReginfoInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
   return S->SectionKind == InputSectionBase<ELFT>::MipsReginfo;

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=256416&r1=256415&r2=256416&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Fri Dec 25 07:02:13 2015
@@ -176,6 +176,7 @@ public:
   MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
 
   uint32_t getGeneralMask() const;
+  uint32_t getGp0() const;
 
   static bool classof(const InputSectionBase<ELFT> *S);
 };

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=256416&r1=256415&r2=256416&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Fri Dec 25 07:02:13 2015
@@ -1382,6 +1382,16 @@ void MipsTargetInfo<ELFT>::relocateOne(u
     write32<E>(Loc, (read32<E>(Loc) & 0xffff0000) | (V & 0xffff));
     break;
   }
+  case R_MIPS_GPREL16: {
+    uint32_t Instr = read32<E>(Loc);
+    int64_t V = SA + SignExtend64<16>(Instr & 0xffff) - getMipsGpAddr<ELFT>();
+    checkInt<16>(V, Type);
+    write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff));
+    break;
+  }
+  case R_MIPS_GPREL32:
+    write32<E>(Loc, SA + int32_t(read32<E>(Loc)) - getMipsGpAddr<ELFT>());
+    break;
   case R_MIPS_HI16: {
     uint32_t Instr = read32<E>(Loc);
     if (PairedLoc) {

Added: lld/trunk/test/ELF/mips-gprel32-relocs.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-gprel32-relocs.test?rev=256416&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-gprel32-relocs.test (added)
+++ lld/trunk/test/ELF/mips-gprel32-relocs.test Fri Dec 25 07:02:13 2015
@@ -0,0 +1,31 @@
+# Check R_MIPS_GPREL32 relocation calculation.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared -o %t.so %t.o
+# RUN: llvm-objdump -s -section=.rodata -t %t.so | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lw      $t0,%call16(__start)($gp)
+foo:
+  nop
+bar:
+  nop
+
+  .section .rodata, "a"
+v1:
+  .gpword foo
+  .gpword bar
+
+# CHECK: Contents of section .rodata:
+# CHECK:  0114 fffe8014 fffe8018
+#              ^ 0x10004 - 0x27ff0
+#                       ^ 0x10008 - 0x27ff0
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00010008         .text           00000000 bar
+# CHECK: 00010004         .text           00000000 foo
+# CHECK: 00027ff0         *ABS*           00000000 _gp




More information about the llvm-commits mailing list