[lld] r254461 - [ELF] MIPS paired R_MIPS_HI16/LO16 relocations support

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 1 13:24:46 PST 2015


Author: atanasyan
Date: Tue Dec  1 15:24:45 2015
New Revision: 254461

URL: http://llvm.org/viewvc/llvm-project?rev=254461&view=rev
Log:
[ELF] MIPS paired R_MIPS_HI16/LO16 relocations support

Some MIPS relocations including `R_MIPS_HI16/R_MIPS_LO16` use combined
addends. Such addend is calculated using addends of both paired relocations.
Each `R_MIPS_HI16` relocation is paired with the next `R_MIPS_LO16`
relocation. ABI requires to compute such combined addend in case of REL
relocation record format only.

For details see p. 4-17 at
ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf

This patch implements lookup of the next paired relocation suing new
`InputSectionBase::findPairedRelocLocation` method. The primary
disadvantage of this approach is that we put MIPS specific logic into
the common code. The next disadvantage is that we lookup `R_MIPS_LO16`
for each `R_MIPS_HI16` relocation, while in fact multiple `R_MIPS_HI16`
might be paired with the single `R_MIPS_LO16`. From the other side
this way allows us to keep `MipsTargetInfo` class stateless and implement
later relocation handling in parallel.

This patch does not support `R_MIPS_HI16/R_MIPS_LO16` relocations against
`_gp_disp` symbol. In that case the relocations use a special formula for
the calculation. That will be implemented later.

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

Added:
    lld/trunk/test/ELF/mips-hilo-hi-only.s
    lld/trunk/test/ELF/mips-hilo.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=254461&r1=254460&r2=254461&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue Dec  1 15:24:45 2015
@@ -94,9 +94,38 @@ bool InputSection<ELFT>::classof(const I
 
 template <class ELFT>
 template <bool isRela>
-void InputSectionBase<ELFT>::relocate(
-    uint8_t *Buf, uint8_t *BufEnd,
-    iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels) {
+uint8_t *
+InputSectionBase<ELFT>::findMipsPairedReloc(uint8_t *Buf, uint32_t Type,
+                                            RelIteratorRange<isRela> Rels) {
+  // Some MIPS relocations use addend calculated from addend of the relocation
+  // itself and addend of paired relocation. ABI requires to compute such
+  // combined addend in case of REL relocation record format only.
+  // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+  if (isRela || Config->EMachine != EM_MIPS)
+    return nullptr;
+  if (Type == R_MIPS_HI16)
+    Type = R_MIPS_LO16;
+  else if (Type == R_MIPS_PCHI16)
+    Type = R_MIPS_PCLO16;
+  else if (Type == R_MICROMIPS_HI16)
+    Type = R_MICROMIPS_LO16;
+  else
+    return nullptr;
+  for (const auto &RI : Rels) {
+    if (RI.getType(Config->Mips64EL) != Type)
+      continue;
+    uintX_t Offset = getOffset(RI.r_offset);
+    if (Offset == (uintX_t)-1)
+      return nullptr;
+    return Buf + Offset;
+  }
+  return nullptr;
+}
+
+template <class ELFT>
+template <bool isRela>
+void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
+                                      RelIteratorRange<isRela> Rels) {
   typedef Elf_Rel_Impl<ELFT, isRela> RelType;
   size_t Num = Rels.end() - Rels.begin();
   for (size_t I = 0; I < Num; ++I) {
@@ -109,6 +138,7 @@ void InputSectionBase<ELFT>::relocate(
 
     uint8_t *BufLoc = Buf + Offset;
     uintX_t AddrLoc = OutSec->getVA() + Offset;
+    auto NextRelocs = llvm::make_range(&RI, Rels.end());
 
     if (Target->isTlsLocalDynamicReloc(Type) &&
         !Target->isTlsOptimized(Type, nullptr)) {
@@ -123,7 +153,8 @@ void InputSectionBase<ELFT>::relocate(
     const Elf_Shdr *SymTab = File->getSymbolTable();
     if (SymIndex < SymTab->sh_info) {
       uintX_t SymVA = getLocalRelTarget(*File, RI);
-      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
+      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA,
+                          findMipsPairedReloc(Buf, Type, NextRelocs));
       continue;
     }
 
@@ -161,7 +192,8 @@ void InputSectionBase<ELFT>::relocate(
       continue;
     }
     Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
-                        SymVA + getAddend<ELFT>(RI));
+                        SymVA + getAddend<ELFT>(RI),
+                        findMipsPairedReloc(Buf, Type, NextRelocs));
   }
 }
 

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=254461&r1=254460&r2=254461&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Tue Dec  1 15:24:45 2015
@@ -76,9 +76,16 @@ public:
   InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel);
 
   template <bool isRela>
-  void relocate(uint8_t *Buf, uint8_t *BufEnd,
-                llvm::iterator_range<
-                    const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels);
+  using RelIteratorRange =
+      llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, isRela> *>;
+
+  template <bool isRela>
+  void relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange<isRela> Rels);
+
+private:
+  template <bool isRela>
+  uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t Type,
+                               RelIteratorRange<isRela> Rels);
 };
 
 template <class ELFT>

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=254461&r1=254460&r2=254461&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Tue Dec  1 15:24:45 2015
@@ -87,7 +87,7 @@ public:
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+                   uint64_t SA, uint8_t *PairedLoc = nullptr) const override;
 };
 
 class X86_64TargetInfo final : public TargetInfo {
@@ -106,7 +106,7 @@ public:
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+                   uint64_t SA, uint8_t *PairedLoc = nullptr) const override;
   bool isRelRelative(uint32_t Type) const override;
   bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override;
   unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
@@ -133,7 +133,7 @@ public:
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+                   uint64_t SA, uint8_t *PairedLoc = nullptr) const override;
   bool isRelRelative(uint32_t Type) const override;
 };
 
@@ -150,7 +150,7 @@ public:
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+                   uint64_t SA, uint8_t *PairedLoc = nullptr) const override;
 };
 
 template <class ELFT> class MipsTargetInfo final : public TargetInfo {
@@ -166,7 +166,7 @@ public:
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
-                   uint64_t SA) const override;
+                   uint64_t SA, uint8_t *PairedLoc = nullptr) const override;
 };
 } // anonymous namespace
 
@@ -308,7 +308,8 @@ bool X86TargetInfo::relocNeedsPlt(uint32
 }
 
 void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                uint64_t P, uint64_t SA) const {
+                                uint64_t P, uint64_t SA,
+                                uint8_t *PairedLoc) const {
   switch (Type) {
   case R_386_32:
     add32le(Loc, SA);
@@ -581,7 +582,8 @@ unsigned X86_64TargetInfo::relocateTlsOp
 }
 
 void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                   uint64_t P, uint64_t SA) const {
+                                   uint64_t P, uint64_t SA,
+                                   uint8_t *PairedLoc) const {
   switch (Type) {
   case R_X86_64_32:
     checkUInt<32>(SA, Type);
@@ -728,7 +730,8 @@ bool PPC64TargetInfo::isRelRelative(uint
 }
 
 void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                                  uint64_t P, uint64_t SA) const {
+                                  uint64_t P, uint64_t SA,
+                                  uint8_t *PairedLoc) const {
   uint64_t TB = getPPC64TocBase();
 
   // For a TOC-relative relocation, adjust the addend and proceed in terms of
@@ -933,8 +936,8 @@ static uint64_t getAArch64Page(uint64_t
 }
 
 void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
-                                    uint32_t Type, uint64_t P,
-                                    uint64_t SA) const {
+                                    uint32_t Type, uint64_t P, uint64_t SA,
+                                    uint8_t *PairedLoc) const {
   switch (Type) {
   case R_AARCH64_ABS16:
     checkIntUInt<16>(SA, Type);
@@ -1046,13 +1049,31 @@ bool MipsTargetInfo<ELFT>::relocNeedsPlt
 
 template <class ELFT>
 void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
-                                       uint32_t Type, uint64_t P,
-                                       uint64_t SA) const {
+                                       uint32_t Type, uint64_t P, uint64_t SA,
+                                       uint8_t *PairedLoc) const {
   const endianness E = ELFT::TargetEndianness;
   switch (Type) {
   case R_MIPS_32:
     add32<E>(Loc, SA);
     break;
+  case R_MIPS_HI16: {
+    uint32_t Instr = read32<E>(Loc);
+    if (PairedLoc) {
+      uint64_t AHL = ((Instr & 0xffff) << 16) +
+                     llvm::SignExtend64<16>(read32<E>(PairedLoc) & 0xffff);
+      write32<E>(Loc, (Instr & 0xffff0000) | (((SA + AHL) >> 16) & 0xffff));
+    } else {
+      warning("Can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16");
+      write32<E>(Loc, (Instr & 0xffff0000) | ((SA >> 16) & 0xffff));
+    }
+    break;
+  }
+  case R_MIPS_LO16: {
+    uint32_t Instr = read32<E>(Loc);
+    int64_t AHL = llvm::SignExtend64<16>(Instr & 0xffff);
+    write32<E>(Loc, (Instr & 0xffff0000) | ((SA + AHL) & 0xffff));
+    break;
+  }
   case R_MIPS_CALL16:
   case R_MIPS_GOT16: {
     int64_t V = SA - getMipsGpAddr<ELFT>();

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=254461&r1=254460&r2=254461&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Tue Dec  1 15:24:45 2015
@@ -57,7 +57,8 @@ public:
   virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0;
   virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0;
   virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
-                           uint64_t P, uint64_t SA) const = 0;
+                           uint64_t P, uint64_t SA,
+                           uint8_t *PairedLoc = nullptr) const = 0;
   virtual bool isTlsOptimized(unsigned Type, const SymbolBody *S) const;
   virtual unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd,
                                        uint32_t Type, uint64_t P,

Added: lld/trunk/test/ELF/mips-hilo-hi-only.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-hilo-hi-only.s?rev=254461&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-hilo-hi-only.s (added)
+++ lld/trunk/test/ELF/mips-hilo-hi-only.s Tue Dec  1 15:24:45 2015
@@ -0,0 +1,22 @@
+# Check warning on orphaned R_MIPS_HI16 relocations.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe 2>&1 | FileCheck -check-prefix=WARN %s
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__start+0x10000)
+
+# WARN: Can't find matching R_MIPS_LO16 relocation for R_MIPS_HI16
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
+#                                                ^-- %hi(__start) w/o addend
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 0020000     .text   00000000 __start

Added: lld/trunk/test/ELF/mips-hilo.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-hilo.s?rev=254461&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-hilo.s (added)
+++ lld/trunk/test/ELF/mips-hilo.s Tue Dec  1 15:24:45 2015
@@ -0,0 +1,53 @@
+# Check R_MIPS_HI16 / LO16 relocations calculation.
+
+# 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 -t %t.exe | FileCheck %s
+
+# REQUIRES: mips
+
+  .text
+  .globl  __start
+__start:
+  lui    $t0,%hi(__start)
+  lui    $t1,%hi(g1)
+  addi   $t0,$t0,%lo(__start+4)
+  addi   $t0,$t0,%lo(g1+8)
+
+  lui    $t0,%hi(l1+0x10000)
+  lui    $t1,%hi(l1+0x20000)
+  addi   $t0,$t0,%lo(l1+(-4))
+
+  .data
+  .type  l1, at object
+  .size  l1,4
+l1:
+  .word 0
+
+  .globl g1
+  .type  g1, at object
+  .size  g1,4
+g1:
+  .word 0
+
+# CHECK:      Disassembly of section .text:
+# CHECK-NEXT: __start:
+# CHECK-NEXT:  20000:   3c 08 00 02   lui    $8, 2
+#                                                ^-- %hi(__start+4)
+# CHECK-NEXT:  20004:   3c 09 00 03   lui    $9, 3
+#                                                ^-- %hi(g1+8)
+# CHECK-NEXT:  20008:   21 08 00 04   addi   $8, $8, 4
+#                                                    ^-- %lo(__start+4)
+# CHECK-NEXT:  2000c:   21 08 00 0c   addi   $8, $8, 12
+#                                                    ^-- %lo(g1+8)
+# CHECK-NEXT:  20010:   3c 08 00 03   lui    $8, 3
+#                                                ^-- %hi(l1+0x10000-4)
+# CHECK-NEXT:  20014:   3c 09 00 04   lui    $9, 4
+#                                                ^-- %hi(l1+0x20000-4)
+# CHECK-NEXT:  20018:   21 08 ff fc   addi   $8, $8, -4
+#                                                    ^-- %lo(l1-4)
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 0030000 l   .data   00000004 l1
+# CHECK: 0020000     .text   00000000 __start
+# CHECK: 0030004 g   .data   00000004 g1




More information about the llvm-commits mailing list