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});
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;
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});
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(
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.
} // 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();
// 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>
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) {
// 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);
}
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
// 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;
}
// 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;
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
// 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);
}
}
// 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;
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});
}
}
}
}
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;
}
: 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) {
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 {
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; }
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);
}
}
};
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);
}
}
# 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"
## 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
# 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
# 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