diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -707,20 +707,28 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const { switch (type) { default: + errorOrWarn(toString(type) + " not handled in getImplicitAddend"); return 0; case R_ARM_ABS32: case R_ARM_BASE_PREL: + case R_ARM_GLOB_DAT: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: + case R_ARM_IRELATIVE: case R_ARM_REL32: + case R_ARM_RELATIVE: + case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: + case R_ARM_TLS_DTPMOD32: + case R_ARM_TLS_DTPOFF32: case R_ARM_TLS_GD32: - case R_ARM_TLS_LDM32: - case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: + case R_ARM_TLS_LDM32: case R_ARM_TLS_LE32: + case R_ARM_TLS_LDO32: + case R_ARM_TLS_TPOFF32: return SignExtend64<32>(read32le(buf)); case R_ARM_PREL31: return SignExtend64<31>(read32le(buf)); @@ -828,6 +836,9 @@ uint64_t imm12 = read16le(buf + 2) & 0x0fff; return u ? imm12 : -imm12; } + case R_ARM_NONE: + case R_ARM_JUMP_SLOT: + return 0; // The stored value at this location is not the addend. } } diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -385,8 +385,10 @@ const endianness e = ELFT::TargetEndianness; switch (type) { case R_MIPS_32: + case R_MIPS_REL32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_DTPMOD32: case R_MIPS_TLS_TPREL32: return SignExtend64<32>(read32(buf)); case R_MIPS_26: @@ -394,25 +396,37 @@ // we should use another expression for calculation: // ((A << 2) | (P & 0xf0000000)) >> 2 return SignExtend64<28>(read32(buf) << 2); + case R_MIPS_CALL_HI16: case R_MIPS_GOT16: + case R_MIPS_GOT_HI16: case R_MIPS_HI16: case R_MIPS_PCHI16: return SignExtend64<16>(read32(buf)) << 16; + case R_MIPS_CALL16: + case R_MIPS_CALL_LO16: + case R_MIPS_GOT_LO16: case R_MIPS_GPREL16: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_DTPREL_LO16: + case R_MIPS_TLS_GD: + case R_MIPS_TLS_GOTTPREL: + case R_MIPS_TLS_LDM: case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: return SignExtend64<16>(read32(buf)); case R_MICROMIPS_GOT16: case R_MICROMIPS_HI16: return SignExtend64<16>(readShuffle(buf)) << 16; + case R_MICROMIPS_CALL16: case R_MICROMIPS_GPREL16: case R_MICROMIPS_LO16: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_DTPREL_LO16: + case R_MICROMIPS_TLS_GD: + case R_MICROMIPS_TLS_GOTTPREL: + case R_MICROMIPS_TLS_LDM: case R_MICROMIPS_TLS_TPREL_HI16: case R_MICROMIPS_TLS_TPREL_LO16: return SignExtend64<16>(readShuffle(buf)); @@ -446,7 +460,20 @@ return SignExtend64<25>(readShuffle(buf) << 2); case R_MICROMIPS_PC26_S1: return SignExtend64<27>(readShuffle(buf) << 1); + case R_MIPS_64: + case R_MIPS_TLS_DTPMOD64: + case R_MIPS_TLS_DTPREL64: + case R_MIPS_TLS_TPREL64: + case (R_MIPS_64 << 8) | R_MIPS_REL32: + return read64(buf); + case R_MIPS_COPY: + return config->is64 ? read64(buf) : read32(buf); + case R_MIPS_NONE: + case R_MIPS_JUMP_SLOT: + case R_MIPS_JALR: + return 0; // The stored value at this location is not the addend. default: + errorOrWarn(toString(type) + " not handled in getImplicitAddend"); return 0; } } diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -250,16 +250,34 @@ case R_386_PC16: return SignExtend64<16>(read16le(buf)); case R_386_32: + case R_386_GLOB_DAT: case R_386_GOT32: case R_386_GOT32X: case R_386_GOTOFF: case R_386_GOTPC: + case R_386_IRELATIVE: case R_386_PC32: case R_386_PLT32: + case R_386_RELATIVE: + case R_386_TLS_DTPMOD32: + case R_386_TLS_DTPOFF32: case R_386_TLS_LDO_32: + case R_386_TLS_LDM: + case R_386_TLS_IE: + case R_386_TLS_IE_32: case R_386_TLS_LE: + case R_386_TLS_LE_32: + case R_386_TLS_GD: + case R_386_TLS_GD_32: + case R_386_TLS_GOTIE: + case R_386_TLS_TPOFF: + case R_386_TLS_TPOFF32: return SignExtend64<32>(read32le(buf)); + case R_386_NONE: + case R_386_JUMP_SLOT: + return 0; // The stored value at this location is not the addend. default: + errorOrWarn(toString(type) + " not handled in getImplicitAddend"); return 0; } } diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -37,6 +37,7 @@ uint64_t pltEntryAddr) const override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; + int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; void applyJumpInstrMod(uint8_t *loc, JumpModType type, unsigned size) const override; @@ -674,6 +675,51 @@ } } +int64_t X86_64::getImplicitAddend(const uint8_t *buf, RelType type) const { + switch (type) { + case R_X86_64_8: + case R_X86_64_PC8: + return SignExtend64<8>(*buf); + case R_X86_64_16: + case R_X86_64_PC16: + return SignExtend64<16>(read16le(buf)); + case R_X86_64_32: + case R_X86_64_32S: + case R_X86_64_TPOFF32: + case R_X86_64_GOT32: + case R_X86_64_GOTPC32: + case R_X86_64_GOTPC32_TLSDESC: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + case R_X86_64_REX_GOTPCRELX: + case R_X86_64_PC32: + case R_X86_64_GOTTPOFF: + case R_X86_64_PLT32: + case R_X86_64_TLSGD: + case R_X86_64_TLSLD: + case R_X86_64_DTPOFF32: + case R_X86_64_SIZE32: + return SignExtend64<32>(read32le(buf)); + case R_X86_64_64: + case R_X86_64_DTPOFF64: + case R_X86_64_PC64: + case R_X86_64_SIZE64: + case R_X86_64_GLOB_DAT: + case R_X86_64_GOT64: + case R_X86_64_GOTOFF64: + case R_X86_64_GOTPC64: + case R_X86_64_IRELATIVE: + case R_X86_64_RELATIVE: + return read64le(buf); + case R_X86_64_JUMP_SLOT: + case R_X86_64_NONE: + return 0; // The stored value at this location is not the addend. + default: + errorOrWarn(toString(type) + " not handled in getImplicitAddend"); + return 0; + } +} + void X86_64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { switch (rel.type) { case R_X86_64_8: diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -102,6 +102,8 @@ void finalize(); template void writeTo(uint8_t *buf); + // Check that the addends for dynamic relocations were written correctly. + void checkDynRelAddends(const uint8_t *bufStart); template void maybeCompress(); void sort(llvm::function_ref order); diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -539,6 +539,40 @@ return {0, 0, 0, 0}; } +void OutputSection::checkDynRelAddends(const uint8_t *bufStart) { + assert(config->writeAddends); + assert(type == SHT_REL || type == SHT_RELA); + std::vector sections = getInputSections(this); + parallelForEachN(0, sections.size(), [&](size_t i) { + const auto *sec = dyn_cast(sections[i]); + // When linking with -r we might also call this function for input + // .rel[a].data sections. In this case we don't check the addend since we + // should just be passing through the object file + if (!sec) + return; + for (const DynamicReloc &rel : sec->relocs) { + int64_t addend = rel.computeAddend(); + const OutputSection *relOsec = rel.inputSec->getOutputSection(); + assert(relOsec != nullptr && "No output section for relocation"); + const uint8_t *relocTarget = + bufStart + relOsec->offset + rel.inputSec->getOffset(rel.offsetInSec); + // For SHT_NOBITS the written addend is always zero. + int64_t writtenAddend = + relOsec->type == SHT_NOBITS + ? 0 + : target->getImplicitAddend(relocTarget, rel.type); + if (addend != writtenAddend) + errorOrWarn( + getErrorLocation(relocTarget) + + "wrote incorrect addend for dynamic relocation: value is 0x" + + utohexstr(writtenAddend) + " but expected 0x" + utohexstr(addend) + + " for " + toString(rel.type) + " against " + + (rel.sym ? toString(*rel.sym) : "load address") + " at 0x" + + utohexstr(rel.getOffset())); + } + }); +} + template void OutputSection::writeHeaderTo(ELF32LE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF32BE::Shdr *Shdr); template void OutputSection::writeHeaderTo(ELF64LE::Shdr *Shdr); 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,8 @@ 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, &sym, 0, R_ABS}); } if (expr != R_TLSDESC_CALL) c.relocations.push_back({expr, type, offset, addend, &sym}); @@ -1071,8 +1071,8 @@ 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, &sym, + 0, R_ABS}); } static void addGotEntry(Symbol &sym) { diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -426,9 +426,11 @@ class DynamicReloc { public: DynamicReloc(RelType type, const InputSectionBase *inputSec, - uint64_t offsetInSec, bool useSymVA, Symbol *sym, int64_t addend) + uint64_t offsetInSec, bool useSymVA, Symbol *sym, int64_t addend, + RelExpr expr, bool mustRetainSymbol = false) : type(type), sym(sym), inputSec(inputSec), offsetInSec(offsetInSec), - useSymVA(useSymVA), addend(addend), outputSec(nullptr) {} + useSymVA(useSymVA), mustRetainSymbol(mustRetainSymbol), expr(expr), + 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. @@ -436,10 +438,14 @@ uint64_t offsetInSec, const OutputSection *outputSec, int64_t addend) : type(type), sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec), - useSymVA(false), addend(addend), outputSec(outputSec) {} + useSymVA(false), expr(R_MIPS_GOT_LOCAL_PAGE), addend(addend), + outputSec(outputSec) {} uint64_t getOffset() const; uint32_t getSymIndex(SymbolTableBaseSection *symTab) const; + bool needsDynSymIndex() const { + return sym && (mustRetainSymbol || !useSymVA); + } // 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 @@ -451,11 +457,22 @@ Symbol *sym; const InputSectionBase *inputSec = nullptr; uint64_t offsetInSec; + +private: // 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; + // If true, the relocation will be against sym rather than the load address + // (even if useSymVA is set). This should be set to true for relocations that + // write the symbol VA as the addend (e.g. R_MIPS_TLS_TPREL64) + bool mustRetainSymbol = false; + // The kind of expression used to calculate the added (required e.g. for + // relative GOT relocations). + RelExpr expr; + +public: int64_t addend; const OutputSection *outputSec; }; @@ -500,6 +517,11 @@ size_t getSize() const override { return relocs.size() * this->entsize; } size_t getRelativeRelocCount() const { return numRelativeRelocs; } void finalizeContents() override; + static bool classof(const SectionBase *d) { + return SyntheticSection::classof(d) && + (d->type == llvm::ELF::SHT_RELA || d->type == llvm::ELF::SHT_REL || + d->type == llvm::ELF::SHT_RELR); + } int32_t dynamicTag, sizeDynamicTag; std::vector relocs; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -999,7 +999,9 @@ Symbol *s = p.first; uint64_t offset = p.second * config->wordsize; if (s->isPreemptible) - mainPart->relaDyn->addReloc(target->tlsGotRel, this, offset, s); + mainPart->relaDyn->addReloc({target->tlsGotRel, this, offset, + /*useSymVA=*/true, s, 0, R_ABS, + /*mustRetainSymbol=*/true}); } for (std::pair &p : got.dynTlsSymbols) { Symbol *s = p.first; @@ -1044,13 +1046,13 @@ 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}); + p.first.first, p.first.second, R_ABS}); } } } @@ -1106,7 +1108,7 @@ // If TLS entry has a corresponding dynamic relocations, leave it // initialized by zero. Write down adjusted TLS symbol's values otherwise. // To calculate the adjustments use offsets for thread-local storage. - // https://www.linux-mips.org/wiki/NPTL + // http://web.archive.org/web/20190324223224/https://www.linux-mips.org/wiki/NPTL for (const std::pair &p : g.local16) write(p.second, p.first.first, p.first.second); // Write VA to the primary GOT only. For secondary GOTs that @@ -1577,7 +1579,8 @@ int64_t DynamicReloc::computeAddend() const { if (useSymVA) - return sym->getVA(addend); + return InputSection::getRelocTargetVA(inputSec->file, type, addend, + getOffset(), *sym, expr); if (!outputSec) return addend; // See the comment in the DynamicReloc ctor. @@ -1585,7 +1588,7 @@ } uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const { - if (sym && !useSymVA) + if (needsDynSymIndex()) return symTab->getSymbolIndex(sym); return 0; } @@ -1598,7 +1601,7 @@ void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol *sym) { - addReloc({dynType, isec, offsetInSec, false, sym, 0}); + addReloc({dynType, isec, offsetInSec, false, sym, 0, R_ADDEND}); } void RelocationBaseSection::addReloc(RelType dynType, @@ -1610,7 +1613,8 @@ // 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}); + addReloc( + {dynType, inputSec, offsetInSec, expr != R_ADDEND, sym, addend, expr}); } void RelocationBaseSection::addReloc(const DynamicReloc &reloc) { diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -130,6 +130,8 @@ TargetInfo::~TargetInfo() {} int64_t TargetInfo::getImplicitAddend(const uint8_t *buf, RelType type) const { + errorOrWarn(toString(type) + " not handled in getImplicitAddend"); + // llvm_unreachable("unknown relocation"); return 0; } diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -382,7 +382,8 @@ mainPart->relaDyn->addReloc( {target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8), true, &dest, - addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)}); + addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther), + R_ABS}); } } }; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2057,7 +2057,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); } } @@ -2971,6 +2972,13 @@ for (OutputSection *sec : outputSections) if (sec->type != SHT_REL && sec->type != SHT_RELA) sec->writeTo(Out::bufferStart + sec->offset); + + // Finally, check that all relocation addends were written correctly. + if (config->writeAddends) { + for (OutputSection *sec : outputSections) + if (sec->type == SHT_REL || sec->type == SHT_RELA) + sec->checkDynRelAddends(Out::bufferStart); + } } // Computes a hash value of Data using a given hash function. 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,48 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o +# RUN: llvm-objdump -r -d %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: 00000000 <_start>: +# OBJ-NEXT: 0: 8b 1d 00 00 00 00 movl 0, %ebx +# OBJ-NEXT: 00000002: R_386_GOT32 foo + +# 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