[ELF] Refactor DynamicReloc to fix incorrect relocation addends
authorAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Fri, 9 Jul 2021 09:04:35 +0000 (10:04 +0100)
committerAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Fri, 9 Jul 2021 09:41:40 +0000 (10:41 +0100)
This patch changes the DynamicReloc class to store an enum instead
of the overloaded useSymVA member to make it easier to understand
and fix incorrect addends being written in some corner cases. The
change is motivated by a follow-up review that checks the value of
implicit Elf_Rel addends written to the output file.

This patch fixes an incorrect output when using `-z rela` for i386 files
with R_386_GOT32 relocations (not that this really matters since it's an
unsupported configuration).
Storing the relocation expression kind also addresses an incorrect addend
FIXME in ppc64-abs64-dyn.s introduced in D63383.

DynamicReloc now also has a special case for the MIPS TLS relocations
(DynamicReloc::AgainstSymbolWithTargetVA) since the
R_MIPS_TLS_TPREL{32/64} the symbol VA to the GOT for preemptible
symbols. I'm not sure if the symbol value actually should be written
for R_MIPS_TLS_TPREL32, but this patch does not attempt to change
that behaviour.

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D100490

lld/ELF/Relocations.cpp
lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
lld/ELF/Thunks.cpp
lld/ELF/Writer.cpp
lld/test/ELF/got32-i386-pie-rw.s
lld/test/ELF/i386-zrel-zrela.s
lld/test/ELF/ppc64-abs64-dyn.s
lld/test/ELF/ppc64-long-branch-pi.s

index 8575598..7e44e2d 100644 (file)
@@ -200,8 +200,11 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
       config->shared) {
     if (in.got->addDynTlsEntry(sym)) {
       uint64_t off = in.got->getGlobalDynOffset(sym);
-      mainPart->relaDyn->addReloc(
-          {target->tlsDescRel, in.got, off, !sym.isPreemptible, &sym, 0});
+      mainPart->relaDyn->addReloc({target->tlsDescRel, in.got, off,
+                                   sym.isPreemptible
+                                       ? DynamicReloc::AgainstSymbol
+                                       : DynamicReloc::AddendOnlyWithTargetVA,
+                                   sym, 0, R_ABS});
     }
     if (expr != R_TLSDESC_CALL)
       c.relocations.push_back({expr, type, offset, addend, &sym});
@@ -245,8 +248,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
         in.got->relocations.push_back(
             {R_ADDEND, target->symbolicRel, in.got->getTlsIndexOff(), 1, &sym});
       else
-        mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got,
-                                in.got->getTlsIndexOff(), nullptr);
+        mainPart->relaDyn->addReloc(
+            {target->tlsModuleIndexRel, in.got, in.got->getTlsIndexOff()});
     }
     c.relocations.push_back({expr, type, offset, addend, &sym});
     return 1;
@@ -283,14 +286,15 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
           in.got->relocations.push_back(
               {R_ADDEND, target->symbolicRel, off, 1, &sym});
         else
-          mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, in.got, off, &sym);
+          mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, in.got,
+                                            off, sym);
 
         // If the symbol is preemptible we need the dynamic linker to write
         // the offset too.
         uint64_t offsetOff = off + config->wordsize;
         if (sym.isPreemptible)
-          mainPart->relaDyn->addReloc(target->tlsOffsetRel, in.got, offsetOff,
-                                  &sym);
+          mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, in.got,
+                                            offsetOff, sym);
         else
           in.got->relocations.push_back(
               {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym});
@@ -307,8 +311,8 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
            addend, &sym});
       if (!sym.isInGot()) {
         in.got->addEntry(sym);
-        mainPart->relaDyn->addReloc(target->tlsGotRel, in.got, sym.getGotOffset(),
-                                &sym);
+        mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, in.got,
+                                          sym.getGotOffset(), sym);
       }
     } else {
       c.relocations.push_back(
@@ -618,7 +622,7 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
   for (SharedSymbol *sym : getSymbolsAt<ELFT>(ss))
     replaceWithDefined(*sym, sec, 0, sym->size);
 
-  mainPart->relaDyn->addReloc(target->copyRel, sec, 0, &ss);
+  mainPart->relaDyn->addSymbolReloc(target->copyRel, sec, 0, ss);
 }
 
 // MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -1047,7 +1051,7 @@ private:
 } // namespace
 
 static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
-                             Symbol *sym, int64_t addend, RelExpr expr,
+                             Symbol &sym, int64_t addend, RelExpr expr,
                              RelType type) {
   Partition &part = isec->getPartition();
 
@@ -1058,12 +1062,12 @@ static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
   // don't store the addend values, so we must write it to the relocated
   // address.
   if (part.relrDyn && isec->alignment >= 2 && offsetInSec % 2 == 0) {
-    isec->relocations.push_back({expr, type, offsetInSec, addend, sym});
+    isec->relocations.push_back({expr, type, offsetInSec, addend, &sym});
     part.relrDyn->relocs.push_back({isec, offsetInSec});
     return;
   }
-  part.relaDyn->addReloc(target->relativeRel, isec, offsetInSec, sym, addend,
-                         expr, type);
+  part.relaDyn->addRelativeReloc(target->relativeRel, isec, offsetInSec, sym,
+                                 addend, type, expr);
 }
 
 template <class PltSection, class GotPltSection>
@@ -1071,8 +1075,10 @@ static void addPltEntry(PltSection *plt, GotPltSection *gotPlt,
                         RelocationBaseSection *rel, RelType type, Symbol &sym) {
   plt->addEntry(sym);
   gotPlt->addEntry(sym);
-  rel->addReloc(
-      {type, gotPlt, sym.getGotPltOffset(), !sym.isPreemptible, &sym, 0});
+  rel->addReloc({type, gotPlt, sym.getGotPltOffset(),
+                 sym.isPreemptible ? DynamicReloc::AgainstSymbol
+                                   : DynamicReloc::AddendOnlyWithTargetVA,
+                 sym, 0, R_ABS});
 }
 
 static void addGotEntry(Symbol &sym) {
@@ -1098,11 +1104,13 @@ static void addGotEntry(Symbol &sym) {
   // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
   // the GOT slot will be fixed at load-time.
   if (!sym.isTls() && !sym.isPreemptible && config->isPic) {
-    addRelativeReloc(in.got, off, &sym, 0, R_ABS, target->symbolicRel);
+    addRelativeReloc(in.got, off, sym, 0, R_ABS, target->symbolicRel);
     return;
   }
   mainPart->relaDyn->addReloc(
-      sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, &sym, 0,
+      sym.isPreemptible ? DynamicReloc::AgainstSymbol
+                        : DynamicReloc::AddendOnlyWithTargetVA,
+      sym.isTls() ? target->tlsGotRel : target->gotRel, in.got, off, sym, 0,
       sym.isPreemptible ? R_ADDEND : R_ABS, target->symbolicRel);
 }
 
@@ -1167,13 +1175,13 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
   if (canWrite) {
     RelType rel = target->getDynRel(type);
     if (expr == R_GOT || (rel == target->symbolicRel && !sym.isPreemptible)) {
-      addRelativeReloc(&sec, offset, &sym, addend, expr, type);
+      addRelativeReloc(&sec, offset, sym, addend, expr, type);
       return;
     } else if (rel != 0) {
       if (config->emachine == EM_MIPS && rel == target->symbolicRel)
         rel = target->relativeRel;
-      sec.getPartition().relaDyn->addReloc(rel, &sec, offset, &sym, addend,
-                                           R_ADDEND, type);
+      sec.getPartition().relaDyn->addSymbolReloc(rel, &sec, offset, sym, addend,
+                                                 type);
 
       // MIPS ABI turns using of GOT and dynamic relocations inside out.
       // While regular ABI uses dynamic relocations to fill up GOT entries
@@ -1417,7 +1425,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
   // direct relocation on through.
   if (sym.isGnuIFunc() && config->zIfuncNoplt) {
     sym.exportDynamic = true;
-    mainPart->relaDyn->addReloc(type, &sec, offset, &sym, addend, R_ADDEND, type);
+    mainPart->relaDyn->addSymbolReloc(type, &sec, offset, sym, addend, type);
     return;
   }
 
index c76b449..a969ced 100644 (file)
@@ -989,7 +989,9 @@ void MipsGotSection::build() {
       // for the TP-relative offset as we don't know how much other data will
       // be allocated before us in the static TLS block.
       if (s->isPreemptible || config->shared)
-        mainPart->relaDyn->addReloc(target->tlsGotRel, this, offset, s);
+        mainPart->relaDyn->addReloc({target->tlsGotRel, this, offset,
+                                     DynamicReloc::AgainstSymbolWithTargetVA,
+                                     *s, 0, R_ABS});
     }
     for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) {
       Symbol *s = p.first;
@@ -997,7 +999,7 @@ void MipsGotSection::build() {
       if (s == nullptr) {
         if (!config->shared)
           continue;
-        mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s);
+        mainPart->relaDyn->addReloc({target->tlsModuleIndexRel, this, offset});
       } else {
         // When building a shared library we still need a dynamic relocation
         // for the module index. Therefore only checking for
@@ -1005,13 +1007,15 @@ void MipsGotSection::build() {
         // thread-locals that have been marked as local through a linker script)
         if (!s->isPreemptible && !config->shared)
           continue;
-        mainPart->relaDyn->addReloc(target->tlsModuleIndexRel, this, offset, s);
+        mainPart->relaDyn->addSymbolReloc(target->tlsModuleIndexRel, this,
+                                          offset, *s);
         // However, we can skip writing the TLS offset reloc for non-preemptible
         // symbols since it is known even in shared libraries
         if (!s->isPreemptible)
           continue;
         offset += config->wordsize;
-        mainPart->relaDyn->addReloc(target->tlsOffsetRel, this, offset, s);
+        mainPart->relaDyn->addSymbolReloc(target->tlsOffsetRel, this, offset,
+                                          *s);
       }
     }
 
@@ -1023,7 +1027,8 @@ void MipsGotSection::build() {
     // Dynamic relocations for "global" entries.
     for (const std::pair<Symbol *, size_t> &p : got.global) {
       uint64_t offset = p.second * config->wordsize;
-      mainPart->relaDyn->addReloc(target->relativeRel, this, offset, p.first);
+      mainPart->relaDyn->addSymbolReloc(target->relativeRel, this, offset,
+                                        *p.first);
     }
     if (!config->isPic)
       continue;
@@ -1034,13 +1039,14 @@ void MipsGotSection::build() {
       for (size_t pi = 0; pi < pageCount; ++pi) {
         uint64_t offset = (l.second.firstIndex + pi) * config->wordsize;
         mainPart->relaDyn->addReloc({target->relativeRel, this, offset, l.first,
-                                 int64_t(pi * 0x10000)});
+                                     int64_t(pi * 0x10000)});
       }
     }
     for (const std::pair<GotEntry, size_t> &p : got.local16) {
       uint64_t offset = p.second * config->wordsize;
-      mainPart->relaDyn->addReloc({target->relativeRel, this, offset, true,
-                               p.first.first, p.first.second});
+      mainPart->relaDyn->addReloc({target->relativeRel, this, offset,
+                                   DynamicReloc::AddendOnlyWithTargetVA,
+                                   *p.first.first, p.first.second, R_ABS});
     }
   }
 }
@@ -1568,16 +1574,25 @@ uint64_t DynamicReloc::getOffset() const {
 }
 
 int64_t DynamicReloc::computeAddend() const {
-  if (useSymVA)
-    return sym->getVA(addend);
-  if (!outputSec)
+  switch (kind) {
+  case AddendOnly:
+    assert(sym == nullptr);
     return addend;
-  // See the comment in the DynamicReloc ctor.
-  return getMipsPageAddr(outputSec->addr) + addend;
+  case AgainstSymbol:
+    assert(sym != nullptr);
+    return addend;
+  case AddendOnlyWithTargetVA:
+  case AgainstSymbolWithTargetVA:
+    return InputSection::getRelocTargetVA(inputSec->file, type, addend,
+                                          getOffset(), *sym, expr);
+  case MipsMultiGotPage:
+    assert(sym == nullptr);
+    return getMipsPageAddr(outputSec->addr) + addend;
+  }
 }
 
 uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const {
-  if (sym && !useSymVA)
+  if (needsDynSymIndex())
     return symTab->getSymbolIndex(sym);
   return 0;
 }
@@ -1588,21 +1603,39 @@ RelocationBaseSection::RelocationBaseSection(StringRef name, uint32_t type,
     : SyntheticSection(SHF_ALLOC, type, config->wordsize, name),
       dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {}
 
-void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec,
-                                     uint64_t offsetInSec, Symbol *sym) {
-  addReloc({dynType, isec, offsetInSec, false, sym, 0});
-}
-
-void RelocationBaseSection::addReloc(RelType dynType,
+void RelocationBaseSection::addSymbolReloc(RelType dynType,
+                                           InputSectionBase *isec,
+                                           uint64_t offsetInSec, Symbol &sym,
+                                           int64_t addend,
+                                           Optional<RelType> addendRelType) {
+  addReloc(DynamicReloc::AgainstSymbol, dynType, isec, offsetInSec, sym, addend,
+           R_ADDEND, addendRelType ? *addendRelType : target->noneRel);
+}
+
+void RelocationBaseSection::addRelativeReloc(
+    RelType dynType, InputSectionBase *inputSec, uint64_t offsetInSec,
+    Symbol &sym, int64_t addend, RelType addendRelType, RelExpr expr) {
+  // This function should only be called for non-preemptible symbols or
+  // RelExpr values that refer to an address inside the output file (e.g. the
+  // address of the GOT entry for a potentially preemptible symbol).
+  assert((!sym.isPreemptible || expr == R_GOT) &&
+         "cannot add relative relocation against preemptible symbol");
+  assert(expr != R_ADDEND && "expected non-addend relocation expression");
+  addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, inputSec, offsetInSec,
+           sym, addend, expr, addendRelType);
+}
+
+void RelocationBaseSection::addReloc(DynamicReloc::Kind kind, RelType dynType,
                                      InputSectionBase *inputSec,
-                                     uint64_t offsetInSec, Symbol *sym,
+                                     uint64_t offsetInSec, Symbol &sym,
                                      int64_t addend, RelExpr expr,
-                                     RelType type) {
+                                     RelType addendRelType) {
   // Write the addends to the relocated address if required. We skip
   // it if the written value would be zero.
   if (config->writeAddends && (expr != R_ADDEND || addend != 0))
-    inputSec->relocations.push_back({expr, type, offsetInSec, addend, sym});
-  addReloc({dynType, inputSec, offsetInSec, expr != R_ADDEND, sym, addend});
+    inputSec->relocations.push_back(
+        {expr, addendRelType, offsetInSec, addend, &sym});
+  addReloc({dynType, inputSec, offsetInSec, kind, sym, addend, expr});
 }
 
 void RelocationBaseSection::addReloc(const DynamicReloc &reloc) {
index c20386c..ef3588d 100644 (file)
@@ -425,39 +425,69 @@ private:
 
 class DynamicReloc {
 public:
+  enum Kind {
+    /// The resulting dynamic relocation does not reference a symbol (#sym must
+    /// be nullptr) and uses #addend as the result of computeAddend().
+    AddendOnly,
+    /// The resulting dynamic relocation will not reference a symbol: #sym is
+    /// only used to compute the addend with InputSection::getRelocTargetVA().
+    /// Useful for various relative and TLS relocations (e.g. R_X86_64_TPOFF64).
+    AddendOnlyWithTargetVA,
+    /// The resulting dynamic relocation references symbol #sym from the dynamic
+    /// symbol table and uses #addend as the value of computeAddend().
+    AgainstSymbol,
+    /// The resulting dynamic relocation references symbol #sym from the dynamic
+    /// symbol table and uses InputSection::getRelocTargetVA() + #addend for the
+    /// final addend. It can be used for relocations that write the symbol VA as
+    // the addend (e.g. R_MIPS_TLS_TPREL64) but still reference the symbol.
+    AgainstSymbolWithTargetVA,
+    /// This is used by the MIPS multi-GOT implementation. It relocates
+    /// addresses of 64kb pages that lie inside the output section.
+    MipsMultiGotPage,
+  };
+  /// This constructor records a relocation against a symbol.
+  DynamicReloc(RelType type, const InputSectionBase *inputSec,
+               uint64_t offsetInSec, Kind kind, Symbol &sym, int64_t addend,
+               RelExpr expr)
+      : type(type), sym(&sym), inputSec(inputSec), offsetInSec(offsetInSec),
+        kind(kind), expr(expr), addend(addend) {}
+  /// This constructor records a relative relocation with no symbol.
   DynamicReloc(RelType type, const InputSectionBase *inputSec,
-               uint64_t offsetInSec, bool useSymVA, Symbol *sym, int64_t addend)
-      : type(type), sym(sym), inputSec(inputSec), offsetInSec(offsetInSec),
-        useSymVA(useSymVA), addend(addend), outputSec(nullptr) {}
-  // This constructor records dynamic relocation settings used by MIPS
-  // multi-GOT implementation. It's to relocate addresses of 64kb pages
-  // lie inside the output section.
+               uint64_t offsetInSec, int64_t addend = 0)
+      : type(type), sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec),
+        kind(AddendOnly), expr(R_ADDEND), addend(addend) {}
+  /// This constructor records dynamic relocation settings used by the MIPS
+  /// multi-GOT implementation.
   DynamicReloc(RelType type, const InputSectionBase *inputSec,
                uint64_t offsetInSec, const OutputSection *outputSec,
                int64_t addend)
       : type(type), sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec),
-        useSymVA(false), addend(addend), outputSec(outputSec) {}
+        kind(MipsMultiGotPage), expr(R_ADDEND), addend(addend),
+        outputSec(outputSec) {}
 
   uint64_t getOffset() const;
   uint32_t getSymIndex(SymbolTableBaseSection *symTab) const;
+  bool needsDynSymIndex() const {
+    return kind == AgainstSymbol || kind == AgainstSymbolWithTargetVA;
+  }
 
-  // Computes the addend of the dynamic relocation. Note that this is not the
-  // same as the addend member variable as it also includes the symbol address
-  // if useSymVA is true.
+  /// Computes the addend of the dynamic relocation. Note that this is not the
+  /// same as the #addend member variable as it may also include the symbol
+  /// address/the address of the corresponding GOT entry/etc.
   int64_t computeAddend() const;
 
   RelType type;
-
   Symbol *sym;
-  const InputSectionBase *inputSec = nullptr;
+  const InputSectionBase *inputSec;
   uint64_t offsetInSec;
-  // If this member is true, the dynamic relocation will not be against the
-  // symbol but will instead be a relative relocation that simply adds the
-  // load address. This means we need to write the symbol virtual address
-  // plus the original addend as the final relocation addend.
-  bool useSymVA;
+
+private:
+  Kind kind;
+  // The kind of expression used to calculate the added (required e.g. for
+  // relative GOT relocations).
+  RelExpr expr;
   int64_t addend;
-  const OutputSection *outputSec;
+  const OutputSection *outputSec = nullptr;
 };
 
 template <class ELFT> class DynamicSection final : public SyntheticSection {
@@ -488,14 +518,22 @@ class RelocationBaseSection : public SyntheticSection {
 public:
   RelocationBaseSection(StringRef name, uint32_t type, int32_t dynamicTag,
                         int32_t sizeDynamicTag);
-  void addReloc(RelType dynType, InputSectionBase *isec, uint64_t offsetInSec,
-                Symbol *sym);
-  // Add a dynamic relocation that might need an addend. This takes care of
-  // writing the addend to the output section if needed.
-  void addReloc(RelType dynType, InputSectionBase *inputSec,
-                uint64_t offsetInSec, Symbol *sym, int64_t addend, RelExpr expr,
-                RelType type);
+  /// Add a dynamic relocation without writing an addend to the output section.
+  /// This overload can be used if the addends are written directly instead of
+  /// using relocations on the input section (e.g. MipsGotSection::writeTo()).
   void addReloc(const DynamicReloc &reloc);
+  /// Add a dynamic relocation against \p sym with an optional addend.
+  void addSymbolReloc(RelType dynType, InputSectionBase *isec,
+                      uint64_t offsetInSec, Symbol &sym, int64_t addend = 0,
+                      llvm::Optional<RelType> addendRelType = llvm::None);
+  /// Add a relative dynamic relocation that uses the target address of \p sym
+  /// (i.e. InputSection::getRelocTargetVA()) + \p addend as the addend.
+  void addRelativeReloc(RelType dynType, InputSectionBase *isec,
+                        uint64_t offsetInSec, Symbol &sym, int64_t addend,
+                        RelType addendRelType, RelExpr expr);
+  void addReloc(DynamicReloc::Kind kind, RelType dynType,
+                InputSectionBase *inputSec, uint64_t offsetInSec, Symbol &sym,
+                int64_t addend, RelExpr expr, RelType addendRelType);
   bool isNeeded() const override { return !relocs.empty(); }
   size_t getSize() const override { return relocs.size() * this->entsize; }
   size_t getRelativeRelocCount() const { return numRelativeRelocs; }
index 3d9b651..dbc476f 100644 (file)
@@ -383,10 +383,10 @@ public:
     assert(!dest.isPreemptible);
     if (Optional<uint32_t> index =
             in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
-      mainPart->relaDyn->addReloc(
-          {target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8),
-           true, &dest,
-           addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)});
+      mainPart->relaDyn->addRelativeReloc(
+          target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8),
+          dest, addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther),
+          target->symbolicRel, R_ABS);
     }
   }
 };
index 167df09..81ac28a 100644 (file)
@@ -2056,7 +2056,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
       for (const SymbolTableEntry &e : part.dynSymTab->getSymbols())
         syms.insert(e.sym);
       for (DynamicReloc &reloc : part.relaDyn->relocs)
-        if (reloc.sym && !reloc.useSymVA && syms.insert(reloc.sym).second)
+        if (reloc.sym && reloc.needsDynSymIndex() &&
+            syms.insert(reloc.sym).second)
           part.dynSymTab->addSymbol(reloc.sym);
     }
   }
index 8130806..7a14908 100644 (file)
@@ -1,14 +1,50 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+# RUN: llvm-readobj -r %t.o | FileCheck %s --check-prefix=OBJ
 # RUN: ld.lld %t.o -o %t -pie
-# RUN: llvm-readelf -r -S %t | FileCheck %s
+# RUN: llvm-objdump -s --section=.foobar --section=.got -r -d -t \
+# RUN:   --dynamic-reloc %t | FileCheck %s --check-prefixes=CHECK,REL
+# RUN: ld.lld %t.o -o %t-rela -pie -z rela
+# RUN: llvm-objdump -s --section=.foobar --section=.got -r -d -t \
+# RUN:   --dynamic-reloc %t-rela | FileCheck %s --check-prefixes=CHECK,RELA
 
 # Unlike bfd and gold we accept this.
 
-# CHECK: .foobar           PROGBITS        00002180
-# CHECK: .got              PROGBITS        [[GOT:[0-9a-z]*]]
-# CHECK-DAG: 00002182  00000008 R_386_RELATIVE
-# CHECK-DAG: [[GOT]]   00000008 R_386_RELATIVE
+# OBJ:      Relocations [
+# OBJ-NEXT:   Section (4) .rel.foobar {
+# OBJ-NEXT:     0x2 R_386_GOT32 foo
+# OBJ-NEXT:   }
+# OBJ-NEXT: ]
+
+# CHECK-LABEL: SYMBOL TABLE:
+# REL:  00001180 l       .text 00000000 foo
+# REL:  00002180 g       .foobar       00000000 _start
+# RELA: 00001188 l       .text 00000000 foo
+# RELA: 00002188 g       .foobar       00000000 _start
+
+# CHECK-LABEL: DYNAMIC RELOCATION RECORDS
+# REL-NEXT:  00002182 R_386_RELATIVE *ABS*{{$}}
+# REL-NEXT:  000031f0 R_386_RELATIVE *ABS*{{$}}
+# RELA-NEXT: 0000218a R_386_RELATIVE *ABS*+0x31f8{{$}}
+# RELA-NEXT: 000031f8 R_386_RELATIVE *ABS*+0x1188{{$}}
+# CHECK-NEXT: Contents of section .foobar:
+# REL-NEXT:   2180 8b1df031 0000
+##                     ^--- VA of GOT entry (0x31f0)
+# RELA-NEXT:  2188 8b1d0000 0000
+##                     ^--- VA of GOT entry in Elf_Rela addend
+# CHECK-NEXT: Contents of section .got:
+# REL-NEXT:   31f0 80110000
+##                 ^--- VA of foo (0x1180)
+# RELA-NEXT:  31f8 00000000
+##                 ^--- VA of foo in Elf_Rela addend
+
+# CHECK-LABEL: Disassembly of section .foobar:
+# CHECK:     <_start>:
+# REL-NEXT:  2180: 8b 1d f0 31 00 00 movl 12784, %ebx
+##                       ^--- VA of GOT entry (0x31f0)
+# RELA-NEXT: 2188: 8b 1d 00 00 00 00 movl 0, %ebx
+##                       ^--- VA of GOT entry in in Elf_Rela addend
+
 foo:
 
 .section .foobar, "awx"
index 5e73ca2..ddba5eb 100644 (file)
@@ -3,10 +3,10 @@
 ## Elf32_Rel dynamic relocations by default, but can use Elf32_Rela with -z rela.
 
 # RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o
-# RUN: ld.lld -shared %t.o -o %t.so
-# RUN: llvm-readobj -d -r -x .data %t.so | FileCheck --check-prefix=REL %s
+# RUN: ld.lld -shared %t.o -o %t.so --noinhibit-exec
+# RUN: llvm-readobj -d -r -x .data -x .got.plt %t.so | FileCheck --check-prefix=REL %s
 # RUN: ld.lld -shared -z rel %t.o -o %t1.so
-# RUN: llvm-readobj -d -r -x .data %t1.so | FileCheck --check-prefix=REL %s
+# RUN: llvm-readobj -d -r -x .data -x .got.plt %t1.so | FileCheck --check-prefix=REL %s
 
 # REL:      REL      {{.*}}
 # REL-NEXT: RELSZ    32 (bytes)
 # REL-NEXT:   R_386_JUMP_SLOT func
 # REL-NEXT: }
 
-# REL:      Hex dump of section '.data':
-# REL-NEXT: 0x000042d0 d0420000 2a000000
+# REL-LABEL: Hex dump of section '.data':
+# REL-NEXT:  0x000042d0 d0420000 2a000000
+##                       ^--- R_386_RELATIVE addend (0x42d0)
+##                                ^--- R_386_32 addend (0x2a)
+# REL-LABEL: Hex dump of section '.got.plt':
+# REL-NEXT:  0x000042d8 48320000 00000000 00000000 36120000
+##  R_386_JUMP_SLOT target (0x1236) ---------------^
 
 # RUN: ld.lld -shared -z rel -z rela %t.o -o %t2.so
-# RUN: llvm-readobj -d -r %t2.so | FileCheck --check-prefix=RELA %s
+# RUN: llvm-readobj -d -r -x .data -x .got.plt %t2.so | FileCheck --check-prefix=RELA %s
 
 # RELA:      RELA      {{.*}}
 # RELA-NEXT: RELASZ    48 (bytes)
 # RELA-NEXT:   R_386_JUMP_SLOT func 0x0
 # RELA-NEXT: }
 
+# RELA-LABEL: Hex dump of section '.data':
+# RELA-NEXT:  0x000042f0 00000000 2a000000
+##                                ^--- R_386_32 addend (0x2a)
+## TODO: we should probably clear the R_386_32 addend that was copied from the .o?
+## no addend written for R_386_RELATIVE
+# RELA-LABEL: Hex dump of section '.got.plt':
+# RELA-NEXT:  0x000042f8 68320000 00000000 00000000 56120000
+##  R_386_JUMP_SLOT target (0x1256) ----------------^
+
 .globl _start
 _start:
   call func@PLT
index 45d10b2..48818c1 100644 (file)
@@ -1,22 +1,26 @@
 # REQUIRES: ppc
 # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
 # RUN: ld.lld -shared %t.o -o %t.so
-# RUN: llvm-readobj -r %t.so | FileCheck %s
+# RUN: llvm-readobj -r %t.so --syms | FileCheck %s
 
 # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
 # RUN: ld.lld -shared %t.o -o %t.so
-# RUN: llvm-readobj -r %t.so | FileCheck %s
+# RUN: llvm-readobj -r %t.so --syms | FileCheck %s
 
 ## Test that we create R_PPC64_RELATIVE for R_PPC64_ADDR64 to non-preemptable
 ## symbols and R_PPC64_TOC in writable sections.
 
-## FIXME the addend for offset 0x20000 should be TOC base+0x8000+1, not 0x80001.
 # CHECK:      .rela.dyn {
-# CHECK-NEXT:   0x303B8 R_PPC64_RELATIVE - 0x8001
+# CHECK-NEXT:   0x303B8 R_PPC64_RELATIVE - 0x303B1
+## TOC base (0x283b0) + 0x8000 + 1 ---------^
 # CHECK-NEXT:   0x303C0 R_PPC64_RELATIVE - 0x303B9
 # CHECK-NEXT:   0x303C8 R_PPC64_ADDR64 external 0x1
 # CHECK-NEXT:   0x303D0 R_PPC64_ADDR64 global 0x1
 # CHECK-NEXT: }
+# CHECK-LABEL: Symbols [
+# CHECK:       Symbol {
+# CHECK:         Name: .TOC. ({{.+}})
+# CHECK-NEXT:    Value: 0x283B0
 
 .data
 .globl global
index 0a62aad..6cc596b 100644 (file)
@@ -22,7 +22,7 @@
 # SEC-SHARED: .branch_lt NOBITS   00000000020020f0 20120f0 000020 00  WA  0   0  8
 
 # RELOC:      .rela.dyn {
-# RELOC-NEXT:   0x2002108 R_PPC64_RELATIVE - 0x8000
+# RELOC-NEXT:   0x2002108 R_PPC64_RELATIVE - 0x2012100
 # RELOC-NEXT:   0x2002110 R_PPC64_RELATIVE - 0x2002000
 # RELOC-NEXT:   0x2002118 R_PPC64_RELATIVE - 0x2002008
 # RELOC-NEXT:   0x2002120 R_PPC64_RELATIVE - 0x200200C