[ELF][MIPS] Calculate combined addend for R_MIPS_GOT16 against local symbol
authorSimon Atanasyan <simon@atanasyan.com>
Thu, 25 Feb 2016 21:33:56 +0000 (21:33 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Thu, 25 Feb 2016 21:33:56 +0000 (21:33 +0000)
R_MIPS_GOT16 relocation against local symbol requires index of a local
GOT entry which contains page address corresponds to sum of the symbol
address and addend. The addend in that case is calculated using addends
from the R_MIPS_GOT16 and paired R_MIPS_LO16 relocations.

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

llvm-svn: 261930

lld/ELF/InputSection.cpp
lld/test/ELF/mips-got16.s

index b594638..4ec818a 100644 (file)
 #include "OutputSections.h"
 #include "Target.h"
 
+#include "llvm/Support/Endian.h"
+
 using namespace llvm;
 using namespace llvm::ELF;
 using namespace llvm::object;
+using namespace llvm::support::endian;
 
 using namespace lld;
 using namespace lld::elf2;
@@ -141,6 +144,21 @@ void InputSection<ELFT>::copyRelocations(uint8_t *Buf,
   }
 }
 
+static uint32_t getMipsPairedRelocType(uint32_t Type) {
+  if (Config->EMachine != EM_MIPS)
+    return R_MIPS_NONE;
+  switch (Type) {
+  case R_MIPS_HI16:
+    return R_MIPS_LO16;
+  case R_MIPS_PCHI16:
+    return R_MIPS_PCLO16;
+  case R_MICROMIPS_HI16:
+    return R_MICROMIPS_LO16;
+  default:
+    return R_MIPS_NONE;
+  }
+}
+
 template <class ELFT>
 template <bool isRela>
 uint8_t *
@@ -151,15 +169,7 @@ InputSectionBase<ELFT>::findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex,
   // 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
+  if (isRela || Type == R_MIPS_NONE)
     return nullptr;
   for (const auto &RI : Rels) {
     if (RI.getType(Config->Mips64EL) != Type)
@@ -225,20 +235,31 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
     uintX_t A = getAddend<ELFT>(RI);
     if (!Body) {
       uintX_t SymVA = getLocalRelTarget(*File, RI, A);
+      uint8_t *PairedLoc = nullptr;
       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)
+        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);
+          // to sum of the symbol address and addend. The addend in that case
+          // is calculated using addends from R_MIPS_GOT16 and paired
+          // R_MIPS_LO16 relocations.
+          const endianness E = ELFT::TargetEndianness;
+          uint8_t *LowLoc =
+              findMipsPairedReloc(Buf, SymIndex, R_MIPS_LO16, NextRelocs);
+          uint64_t AHL = read32<E>(BufLoc) << 16;
+          if (LowLoc)
+            AHL += SignExtend64<16>(read32<E>(LowLoc));
+          SymVA = Out<ELFT>::Got->getMipsLocalPageAddr(SymVA + AHL);
+        } else
+          PairedLoc = findMipsPairedReloc(
+              Buf, SymIndex, getMipsPairedRelocType(Type), NextRelocs);
       }
-      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0,
-                          findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
+      Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0, PairedLoc);
       continue;
     }
 
@@ -284,7 +305,9 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
     }
     uintX_t Size = Body->getSize<ELFT>();
     Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + A, Size + A,
-                        findMipsPairedReloc(Buf, SymIndex, Type, NextRelocs));
+                        findMipsPairedReloc(Buf, SymIndex,
+                                            getMipsPairedRelocType(Type),
+                                            NextRelocs));
   }
 }
 
index c1eee3c..a04e33e 100644 (file)
 # 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:    10004:       21 08 00 2c     addi    $8, $8, 44
 # CHECK-NEXT:    10008:       8f 88 80 1c     lw      $8, -32740($gp)
-# CHECK-NEXT:    1000c:       21 08 00 00     addi    $8, $8, 0
+# CHECK-NEXT:    1000c:       21 08 90 00     addi    $8, $8, -28672
 # 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-NEXT:    10014:       21 08 90 04     addi    $8, $8, -28668
+# CHECK-NEXT:    10018:       8f 88 80 20     lw      $8, -32736($gp)
+# CHECK-NEXT:    1001c:       21 08 10 04     addi    $8, $8, 4100
+# CHECK-NEXT:    10020:       8f 88 80 24     lw      $8, -32732($gp)
+# CHECK-NEXT:    10024:       21 08 10 08     addi    $8, $8, 4104
+# CHECK-NEXT:    10028:       8f 88 80 2c     lw      $8, -32724($gp)
 #
 # CHECK: SYMBOL TABLE:
-# CHECK: 0001001c         .text           00000000 $LC0
-# CHECK: 00030000         .data           00000000 $LC1
-# CHECK: 00030004         .data           00000000 .hidden bar
+# CHECK: 0001002c         .text           00000000 $LC0
+# CHECK: 00039000         .data           00000000 $LC1
+# CHECK: 00051008         .data           00000000 .hidden bar
 # CHECK: 00000000         *UND*           00000000 foo
 
 # GOT:      Relocations [
 # GOT-NEXT:       Address: 0x20008
 # GOT-NEXT:       Access: -32744
 # GOT-NEXT:       Initial: 0x10000
+#                          ^-- (0x1002c + 0x8000) & ~0xffff
 # GOT-NEXT:     }
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x2000C
 # GOT-NEXT:       Access: -32740
-# GOT-NEXT:       Initial: 0x30000
+# GOT-NEXT:       Initial: 0x40000
+#                          ^-- (0x39000 + 0x8000) & ~0xffff
 # GOT-NEXT:     }
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x20010
 # GOT-NEXT:       Access: -32736
-# GOT-NEXT:       Initial: 0x30004
+# GOT-NEXT:       Initial: 0x50000
+#                          ^-- (0x39000 + 0x10004 + 0x8000) & ~0xffff
+#                          ^-- (0x39000 + 0x18004 + 0x8000) & ~0xffff
 # GOT-NEXT:     }
-# GOT-NEXT:   ]
-# GOT-NEXT:   Global entries [
 # GOT-NEXT:     Entry {
 # GOT-NEXT:       Address: 0x20014
 # GOT-NEXT:       Access: -32732
+# GOT-NEXT:       Initial: 0x51008
+#                          ^-- 'bar' address
+# GOT-NEXT:     }
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x20018
+# GOT-NEXT:       Access: -32728
+# GOT-NEXT:       Initial: 0x0
+#                          ^-- redundant unused entry
+# GOT-NEXT:     }
+# GOT-NEXT:   ]
+# GOT-NEXT:   Global entries [
+# GOT-NEXT:     Entry {
+# GOT-NEXT:       Address: 0x2001C
+# GOT-NEXT:       Access: -32724
 # GOT-NEXT:       Initial: 0x0
 # GOT-NEXT:       Value: 0x0
 # GOT-NEXT:       Type: None
@@ -80,6 +100,10 @@ __start:
   addi    $t0,$t0,%lo($LC0)
   lw      $t0,%got($LC1)($gp)
   addi    $t0,$t0,%lo($LC1)
+  lw      $t0,%got($LC1+0x10004)($gp)
+  addi    $t0,$t0,%lo($LC1+0x10004)
+  lw      $t0,%got($LC1+0x18004)($gp)
+  addi    $t0,$t0,%lo($LC1+0x18004)
   lw      $t0,%got(bar)($gp)
   addi    $t0,$t0,%lo(bar)
   lw      $t0,%got(foo)($gp)
@@ -87,8 +111,11 @@ $LC0:
   nop
 
   .data
+  .space 0x9000
 $LC1:
   .word 0
+  .space 0x18000
+  .word 0
 .global bar
 .hidden bar
 bar: