diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -200,8 +200,11 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } // 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 @@ // 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 @@ 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 @@ // 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 @@ 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 @@ // 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.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -425,39 +425,69 @@ 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 @@ 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/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -989,7 +989,9 @@ // 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 @@ 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 @@ // 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 @@ // 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 @@ 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 @@ } 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 @@ : 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/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -383,10 +383,10 @@ 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 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2056,7 +2056,8 @@ 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 --- 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 --- 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 --- 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 --- 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