[Mips] Fix addend writing for R_MIPS_REL32 relocation
authorSimon Atanasyan <simon@atanasyan.com>
Tue, 21 Jul 2015 05:54:30 +0000 (05:54 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Tue, 21 Jul 2015 05:54:30 +0000 (05:54 +0000)
llvm-svn: 242760

lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
lld/test/elf/Mips/rel-dynamic-15.test [new file with mode: 0644]

index c0feb73..66267c6 100644 (file)
@@ -320,12 +320,12 @@ static ErrorOr<int64_t> relocJalr(uint64_t P, uint64_t S, bool isCrossJump,
   return ins;
 }
 
-static int64_t relocRel32(int64_t A) {
+static int64_t relocRel32(uint64_t S, int64_t A, bool isLocal) {
   // If output relocation format is REL and the input one is RELA, the only
   // method to transfer the relocation addend from the input relocation
   // to the output dynamic relocation is to save this addend to the location
   // modified by R_MIPS_REL32.
-  return A;
+  return isLocal ? S + A : A;
 }
 
 static std::error_code adjustJumpOpCode(uint64_t &ins, uint64_t tgt,
@@ -383,8 +383,8 @@ template <class ELFT>
 static ErrorOr<int64_t>
 calculateRelocation(Reference::KindValue kind, Reference::Addend addend,
                     uint64_t tgtAddr, uint64_t relAddr, uint64_t gpAddr,
-                    bool isGP, bool isCrossJump, bool isDynamic,
-                    uint8_t *location) {
+                    uint8_t *location, bool isGP, bool isCrossJump,
+                    bool isDynamic, bool isLocalSym) {
   switch (kind) {
   case R_MIPS_NONE:
     return 0;
@@ -490,7 +490,7 @@ calculateRelocation(Reference::KindValue kind, Reference::Addend addend,
     // We do not do JALR optimization now.
     return 0;
   case R_MIPS_REL32:
-    return relocRel32(addend);
+    return relocRel32(tgtAddr, addend, isLocalSym);
   case R_MIPS_JUMP_SLOT:
   case R_MIPS_COPY:
     // Ignore runtime relocations.
@@ -585,6 +585,12 @@ static uint8_t getRelShift(Reference::KindValue kind,
   return shift;
 }
 
+static bool isLocalTarget(const Atom *a) {
+  if (auto *da = dyn_cast<DefinedAtom>(a))
+    return da->scope() == Atom::scopeTranslationUnit;
+  return false;
+}
+
 template <class ELFT>
 std::error_code RelocationHandler<ELFT>::applyRelocation(
     ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
@@ -595,6 +601,7 @@ std::error_code RelocationHandler<ELFT>::applyRelocation(
 
   uint64_t gpAddr = _targetLayout.getGPAddr();
   bool isGpDisp = ref.target()->name() == "_gp_disp";
+  bool isLocalSym = isLocalTarget(ref.target());
 
   uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
   uint8_t *location = atomContent + ref.offsetInAtom();
@@ -616,8 +623,9 @@ std::error_code RelocationHandler<ELFT>::applyRelocation(
     if (kind == R_MIPS_NONE)
       break;
     auto params = getRelocationParams(kind);
-    res = calculateRelocation<ELFT>(kind, *res, sym, relAddr, gpAddr, isGpDisp,
-                                    isCrossJump, _ctx.isDynamic(), location);
+    res = calculateRelocation<ELFT>(kind, *res, sym, relAddr, gpAddr, location,
+                                    isGpDisp, isCrossJump, _ctx.isDynamic(),
+                                    isLocalSym);
     if (auto ec = res.getError())
       return ec;
     // Check result for the last relocation only.
index 99d2ccf..75a9ae5 100644 (file)
@@ -586,7 +586,8 @@ std::error_code RelocationPass<ELFT>::perform(SimpleFile &mf) {
 
   // Create R_MIPS_REL32 relocations.
   for (auto *ref : _rel32Candidates) {
-    if (!isDynamic(ref->target()) || hasPLTEntry(ref->target()))
+    bool forceRel = isLocal(ref->target()) && _ctx.getOutputELFType() == ET_DYN;
+    if (!forceRel && (!isDynamic(ref->target()) || hasPLTEntry(ref->target())))
       continue;
     ref->setKindValue(R_MIPS_REL32);
     if (ELFT::Is64Bits)
@@ -817,10 +818,10 @@ RelocationPass<ELFT>::collectReferenceInfo(const MipsELFDefinedAtom<ELFT> &atom,
   if (!isConstrainSym(atom, refKind))
     return std::error_code();
 
-  if (mightBeDynamic(atom, refKind))
-    _rel32Candidates.push_back(&ref);
-  else
+  if (!mightBeDynamic(atom, refKind))
     _hasStaticRelocations.insert(ref.target());
+  else if (refKind == R_MIPS_32 || refKind == R_MIPS_64)
+    _rel32Candidates.push_back(&ref);
 
   if (!isBranchReloc(refKind) && !isAllCallReloc(refKind) &&
       refKind != R_MIPS_EH)
diff --git a/lld/test/elf/Mips/rel-dynamic-15.test b/lld/test/elf/Mips/rel-dynamic-15.test
new file mode 100644 (file)
index 0000000..8bd486f
--- /dev/null
@@ -0,0 +1,81 @@
+# Check that LLD generates dynamic relocation R_MIPS_REL32 for local
+# symbols if the symbols referenced by R_MIPS_32 relocation.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.o
+# RUN: llvm-objdump -s %t.so | FileCheck -check-prefix=RAW %s
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=REL %s
+
+# RAW:      Contents of section .text:
+# RAW-NEXT:  0120 00000000 00000000
+# RAW:      Contents of section .data.rel.local:
+# RAW-NEXT:  2000 20010000 00000000
+
+# REL:      Relocations [
+# REL-NEXT:   Section (4) .rel.dyn {
+# REL-NEXT:     0x2000 R_MIPS_REL32 - 0x0
+# REL-NEXT:     0x2004 R_MIPS_REL32 T1 0x0
+# REL-NEXT:   }
+# REL-NEXT: ]
+
+---
+FileHeader:
+  Class:    ELFCLASS32
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_MIPS
+  Flags:    [EF_MIPS_NOREORDER, EF_MIPS_PIC, EF_MIPS_CPIC,
+             EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2]
+
+Sections:
+  - Name:          .text
+    Type:          SHT_PROGBITS
+    Flags:         [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:  16
+    Size:          8
+
+  - Name:          .data.rel.local
+    Type:          SHT_PROGBITS
+    Flags:         [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:  4
+    Size:          8
+
+  - Name:          .rel.data.rel.local
+    Type:          SHT_REL
+    Link:          .symtab
+    AddressAlign:  4
+    Info:          .data.rel.local
+    Relocations:
+      - Offset:  0
+        Symbol:  .text
+        Type:    R_MIPS_32
+      - Offset:  4
+        Symbol:  T1
+        Type:    R_MIPS_32
+
+Symbols:
+  Local:
+    - Name:     .text
+      Type:     STT_SECTION
+      Section:  .text
+    - Name:     T0
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0
+      Size:     4
+    - Name:     .data.rel.local
+      Type:     STT_SECTION
+      Section:  .data.rel.local
+
+  Global:
+    - Name:     D0
+      Type:     STT_OBJECT
+      Section:  .data.rel.local
+      Value:    0
+      Size:     8
+    - Name:     T1
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    4
+      Size:     4
+...