From 6d87ca08aed19fd4e975788ffd3d25592447ff8e Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 9 Jul 2021 10:04:35 +0100 Subject: [PATCH] [ELF] Refactor DynamicReloc to fix incorrect relocation addends 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 | 52 ++++++++++++---------- lld/ELF/SyntheticSections.cpp | 81 ++++++++++++++++++++++++---------- lld/ELF/SyntheticSections.h | 88 ++++++++++++++++++++++++++----------- lld/ELF/Thunks.cpp | 8 ++-- lld/ELF/Writer.cpp | 3 +- lld/test/ELF/got32-i386-pie-rw.s | 46 ++++++++++++++++--- lld/test/ELF/i386-zrel-zrela.s | 26 ++++++++--- lld/test/ELF/ppc64-abs64-dyn.s | 12 +++-- lld/test/ELF/ppc64-long-branch-pi.s | 2 +- 9 files changed, 226 insertions(+), 92 deletions(-) diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 8575598..7e44e2d 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -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 static void addCopyRelSymbol(SharedSymbol &ss) { for (SharedSymbol *sym : getSymbolsAt(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 @@ -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; } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index c76b449..a969ced 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -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 &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 &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 &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 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) { diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index c20386c..ef3588d 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -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 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 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; } diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp index 3d9b651..dbc476ff 100644 --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -383,10 +383,10 @@ public: assert(!dest.isPreemptible); if (Optional 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); } } }; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 167df09..81ac28a 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2056,7 +2056,8 @@ template void Writer::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); } } diff --git a/lld/test/ELF/got32-i386-pie-rw.s b/lld/test/ELF/got32-i386-pie-rw.s index 8130806..7a14908 100644 --- a/lld/test/ELF/got32-i386-pie-rw.s +++ b/lld/test/ELF/got32-i386-pie-rw.s @@ -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" diff --git a/lld/test/ELF/i386-zrel-zrela.s b/lld/test/ELF/i386-zrel-zrela.s index 5e73ca2..ddba5eb 100644 --- a/lld/test/ELF/i386-zrel-zrela.s +++ b/lld/test/ELF/i386-zrel-zrela.s @@ -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) @@ -26,11 +26,16 @@ # 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) @@ -50,6 +55,15 @@ # 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 diff --git a/lld/test/ELF/ppc64-abs64-dyn.s b/lld/test/ELF/ppc64-abs64-dyn.s index 45d10b2..48818c1 100644 --- a/lld/test/ELF/ppc64-abs64-dyn.s +++ b/lld/test/ELF/ppc64-abs64-dyn.s @@ -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 diff --git a/lld/test/ELF/ppc64-long-branch-pi.s b/lld/test/ELF/ppc64-long-branch-pi.s index 0a62aad..6cc596b 100644 --- a/lld/test/ELF/ppc64-long-branch-pi.s +++ b/lld/test/ELF/ppc64-long-branch-pi.s @@ -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 -- 2.7.4