[lld] r268876 - [ELF][MIPS] Handling 'packed' N64 ABI relocations

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Sun May 8 07:08:42 PDT 2016


Author: atanasyan
Date: Sun May  8 09:08:40 2016
New Revision: 268876

URL: http://llvm.org/viewvc/llvm-project?rev=268876&view=rev
Log:
[ELF][MIPS] Handling 'packed' N64 ABI relocations

MIPS N64 ABI packs multiple relocations into the single relocation
record. In general, all up to three relocations can have arbitrary types.
In fact, Clang and GCC uses only a few combinations. For now, we support
two of them. That is allow to pass at least all LLVM test suite cases.

<any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
<any relocation> / R_MIPS_64 / R_MIPS_NONE

The first relocation is a 'real' relocation which is calculated using
the corresponding symbol's value. The second and the third relocations
used to modify result of the first one: extend it to 64-bit, extract
high or low part etc. For details, see part 2.9 'Relocation' at
https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf

Added:
    lld/trunk/test/ELF/mips-64-rels.s
Modified:
    lld/trunk/ELF/Target.cpp

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=268876&r1=268875&r2=268876&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Sun May  8 09:08:40 2016
@@ -1244,6 +1244,9 @@ template <class ELFT> MipsTargetInfo<ELF
 template <class ELFT>
 RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
                                          const SymbolBody &S) const {
+  if (ELFT::Is64Bits)
+    // See comment in the calculateMips64RelChain.
+    Type &= 0xff;
   switch (Type) {
   default:
     return R_ABS;
@@ -1443,14 +1446,44 @@ uint64_t MipsTargetInfo<ELFT>::getImplic
   }
 }
 
+static std::pair<uint32_t, uint64_t> calculateMips64RelChain(uint32_t Type,
+                                                             uint64_t Val) {
+  // MIPS N64 ABI packs multiple relocations into the single relocation
+  // record. In general, all up to three relocations can have arbitrary
+  // types. In fact, Clang and GCC uses only a few combinations. For now,
+  // we support two of them. That is allow to pass at least all LLVM
+  // test suite cases.
+  // <any relocation> / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16
+  // <any relocation> / R_MIPS_64 / R_MIPS_NONE
+  // The first relocation is a 'real' relocation which is calculated
+  // using the corresponding symbol's value. The second and the third
+  // relocations used to modify result of the first one: extend it to
+  // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation
+  // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf
+  uint32_t Type2 = (Type >> 8) & 0xff;
+  uint32_t Type3 = (Type >> 16) & 0xff;
+  if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE)
+    return std::make_pair(Type, Val);
+  if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE)
+    return std::make_pair(Type2, Val);
+  if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
+    return std::make_pair(Type3, -Val);
+  error("unsupported relocations combination " + Twine(Type));
+  return std::make_pair(Type & 0xff, Val);
+}
+
 template <class ELFT>
 void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
                                        uint64_t Val) const {
   const endianness E = ELFT::TargetEndianness;
   // Thread pointer and DRP offsets from the start of TLS data area.
   // https://www.linux-mips.org/wiki/NPTL
-  const uint32_t TPOffset = 0x7000;
-  const uint32_t DTPOffset = 0x8000;
+  if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16)
+    Val -= 0x8000;
+  else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16)
+    Val -= 0x7000;
+  if (ELFT::Is64Bits)
+    std::tie(Type, Val) = calculateMips64RelChain(Type, Val);
   switch (Type) {
   case R_MIPS_32:
   case R_MIPS_GPREL32:
@@ -1472,10 +1505,14 @@ void MipsTargetInfo<ELFT>::relocateOne(u
   case R_MIPS_GOT_OFST:
   case R_MIPS_LO16:
   case R_MIPS_PCLO16:
+  case R_MIPS_TLS_DTPREL_LO16:
+  case R_MIPS_TLS_TPREL_LO16:
     writeMipsLo16<E>(Loc, Val);
     break;
   case R_MIPS_HI16:
   case R_MIPS_PCHI16:
+  case R_MIPS_TLS_DTPREL_HI16:
+  case R_MIPS_TLS_TPREL_HI16:
     writeMipsHi16<E>(Loc, Val);
     break;
   case R_MIPS_JALR:
@@ -1496,18 +1533,6 @@ void MipsTargetInfo<ELFT>::relocateOne(u
   case R_MIPS_PC32:
     applyMipsPcReloc<E, 32, 0>(Loc, Type, Val);
     break;
-  case R_MIPS_TLS_DTPREL_HI16:
-    writeMipsHi16<E>(Loc, Val - DTPOffset);
-    break;
-  case R_MIPS_TLS_DTPREL_LO16:
-    writeMipsLo16<E>(Loc, Val - DTPOffset);
-    break;
-  case R_MIPS_TLS_TPREL_HI16:
-    writeMipsHi16<E>(Loc, Val - TPOffset);
-    break;
-  case R_MIPS_TLS_TPREL_LO16:
-    writeMipsLo16<E>(Loc, Val - TPOffset);
-    break;
   default:
     fatal("unrecognized reloc " + Twine(Type));
   }

Added: lld/trunk/test/ELF/mips-64-rels.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-64-rels.s?rev=268876&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-64-rels.s (added)
+++ lld/trunk/test/ELF/mips-64-rels.s Sun May  8 09:08:40 2016
@@ -0,0 +1,46 @@
+# Check handling multiple MIPS N64 ABI relocations packed
+# into the single relocation record.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s
+
+# REQUIRES: mips
+
+# CHECK:      __start:
+# CHECK-NEXT:    20000:   3c 1c 00 01   lui     $gp, 1
+#                                                    ^-- 0x20000 - 0x37ff0
+#                                                    ^-- 0 - 0xfffffffffffe8010
+#                                                    ^-- %hi(0x17ff0)
+# CHECK:      loc:
+# CHECK-NEXT:    20004:   67 9c 7f f0   daddiu  $gp, $gp, 32752
+#                                                    ^-- 0x20000 - 0x37ff0
+#                                                    ^-- 0 - 0xfffffffffffe8010
+#                                                    ^-- %lo(0x17ff0)
+
+# CHECK:      Contents of section .rodata:
+# CHECK-NEXT:  10190 ffffffff fffe8014
+#                    ^-- 0x20004 - 0x37ff0 = 0xfffffffffffe8014
+
+# CHECK: 0000000000020004   .text   00000000 loc
+# CHECK: 0000000000037ff0   .got    00000000 .hidden _gp
+# CHECK: 0000000000020000   .text   00000000 __start
+
+# REL:      Relocations [
+# REL-NEXT: ]
+
+  .text
+  .global  __start
+__start:
+  lui     $gp,%hi(%neg(%gp_rel(__start)))     # R_MIPS_GPREL16
+                                              # R_MIPS_SUB
+                                              # R_MIPS_HI16
+loc:
+  daddiu  $gp,$gp,%lo(%neg(%gp_rel(__start))) # R_MIPS_GPREL16
+                                              # R_MIPS_SUB
+                                              # R_MIPS_LO16
+
+  .section  .rodata,"a", at progbits
+  .gpdword(loc)                               # R_MIPS_GPREL32
+                                              # R_MIPS_64




More information about the llvm-commits mailing list