aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/Relocations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Relocations.cpp')
-rw-r--r--lld/ELF/Relocations.cpp465
1 files changed, 260 insertions, 205 deletions
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 5136ba2151a3..cfe49007b814 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -295,18 +295,20 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &ss) {
// in .bss and in the case of a canonical plt entry it is in .plt. This function
// replaces the existing symbol with a Defined pointing to the appropriate
// location.
-static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value,
+static void replaceWithDefined(Symbol &sym, SectionBase &sec, uint64_t value,
uint64_t size) {
Symbol old = sym;
sym.replace(Defined{sym.file, sym.getName(), sym.binding, sym.stOther,
- sym.type, value, size, sec});
+ sym.type, value, size, &sec});
sym.pltIndex = old.pltIndex;
sym.gotIndex = old.gotIndex;
sym.verdefIndex = old.verdefIndex;
sym.exportDynamic = true;
sym.isUsedInRegularObj = true;
+ // A copy relocated alias may need a GOT entry.
+ sym.needsGot = old.needsGot;
}
// Reserve space in .bss or .bss.rel.ro for copy relocation.
@@ -351,7 +353,7 @@ static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value,
// to the variable in .bss. This kind of issue is sometimes very hard to
// debug. What's a solution? Instead of exporting a variable V from a DSO,
// define an accessor getV().
-template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
+template <class ELFT> static void addCopyRelSymbolImpl(SharedSymbol &ss) {
// Copy relocation against zero-sized symbol doesn't make sense.
uint64_t symSize = ss.getSize();
if (symSize == 0 || ss.alignment == 0)
@@ -377,9 +379,29 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
for (SharedSymbol *sym : getSymbolsAt<ELFT>(ss))
- replaceWithDefined(*sym, sec, 0, sym->size);
+ replaceWithDefined(*sym, *sec, 0, sym->size);
- mainPart->relaDyn->addSymbolReloc(target->copyRel, sec, 0, ss);
+ mainPart->relaDyn->addSymbolReloc(target->copyRel, *sec, 0, ss);
+}
+
+static void addCopyRelSymbol(SharedSymbol &ss) {
+ const SharedFile &file = ss.getFile();
+ switch (file.ekind) {
+ case ELF32LEKind:
+ addCopyRelSymbolImpl<ELF32LE>(ss);
+ break;
+ case ELF32BEKind:
+ addCopyRelSymbolImpl<ELF32BE>(ss);
+ break;
+ case ELF64LEKind:
+ addCopyRelSymbolImpl<ELF64LE>(ss);
+ break;
+ case ELF64BEKind:
+ addCopyRelSymbolImpl<ELF64BE>(ss);
+ break;
+ default:
+ llvm_unreachable("");
+ }
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -450,8 +472,8 @@ static std::string maybeReportDiscarded(Undefined &sym) {
if (!file || !sym.discardedSecIdx ||
file->getSections()[sym.discardedSecIdx] != &InputSection::discarded)
return "";
- ArrayRef<Elf_Shdr_Impl<ELFT>> objSections =
- CHECK(file->getObj().sections(), file);
+ ArrayRef<typename ELFT::Shdr> objSections =
+ file->template getELFShdrs<ELFT>();
std::string msg;
if (sym.type == ELF::STT_SECTION) {
@@ -680,6 +702,12 @@ static void reportUndefinedSymbol(const UndefinedDiag &undef,
msg +=
"\n>>> the vtable symbol may be undefined because the class is missing "
"its key function (see https://lld.llvm.org/missingkeyfunction)";
+ if (config->gcSections && config->zStartStopGC &&
+ sym.getName().startswith("__start_")) {
+ msg += "\n>>> the encapsulation symbol needs to be retained under "
+ "--gc-sections properly; consider -z nostart-stop-gc "
+ "(see https://lld.llvm.org/ELF/start-stop-gc)";
+ }
if (undef.isWarning)
warn(msg);
@@ -711,8 +739,6 @@ template <class ELFT> void elf::reportUndefinedSymbols() {
// Returns true if the undefined symbol will produce an error message.
static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
uint64_t offset) {
- if (!sym.isUndefined())
- return false;
// If versioned, issue an error (even if the symbol is weak) because we don't
// know the defining filename which is required to construct a Verneed entry.
if (*sym.getVersionSuffix() == '@') {
@@ -807,10 +833,10 @@ private:
};
} // namespace
-static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
+static void addRelativeReloc(InputSectionBase &isec, uint64_t offsetInSec,
Symbol &sym, int64_t addend, RelExpr expr,
RelType type) {
- Partition &part = isec->getPartition();
+ Partition &part = isec.getPartition();
// Add a relative relocation. If relrDyn section is enabled, and the
// relocation offset is guaranteed to be even, add the relocation to
@@ -818,9 +844,9 @@ static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
// relrDyn sections don't support odd offsets. Also, relrDyn sections
// 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});
- part.relrDyn->relocs.push_back({isec, offsetInSec});
+ if (part.relrDyn && isec.alignment >= 2 && offsetInSec % 2 == 0) {
+ isec.relocations.push_back({expr, type, offsetInSec, addend, &sym});
+ part.relrDyn->relocs.push_back({&isec, offsetInSec});
return;
}
part.relaDyn->addRelativeReloc(target->relativeRel, isec, offsetInSec, sym,
@@ -828,14 +854,14 @@ static void addRelativeReloc(InputSectionBase *isec, uint64_t offsetInSec,
}
template <class PltSection, class GotPltSection>
-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 ? DynamicReloc::AgainstSymbol
- : DynamicReloc::AddendOnlyWithTargetVA,
- sym, 0, R_ABS});
+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 ? DynamicReloc::AgainstSymbol
+ : DynamicReloc::AddendOnlyWithTargetVA,
+ sym, 0, R_ABS});
}
static void addGotEntry(Symbol &sym) {
@@ -854,7 +880,7 @@ static void addGotEntry(Symbol &sym) {
if (!config->isPic || isAbsolute(sym))
in.got->relocations.push_back({R_ABS, target->symbolicRel, off, 0, &sym});
else
- addRelativeReloc(in.got, off, sym, 0, R_ABS, target->symbolicRel);
+ addRelativeReloc(*in.got, off, sym, 0, R_ABS, target->symbolicRel);
}
static void addTpOffsetGotEntry(Symbol &sym) {
@@ -865,7 +891,7 @@ static void addTpOffsetGotEntry(Symbol &sym) {
return;
}
mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
- target->tlsGotRel, in.got, off, sym, target->symbolicRel);
+ target->tlsGotRel, *in.got, off, sym, target->symbolicRel);
}
// Return true if we can define a symbol in the executable that
@@ -993,12 +1019,12 @@ 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->addSymbolReloc(rel, &sec, offset, sym, addend,
+ sec.getPartition().relaDyn->addSymbolReloc(rel, sec, offset, sym, addend,
type);
// MIPS ABI turns using of GOT and dynamic relocations inside out.
@@ -1039,7 +1065,7 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
" against symbol '" + toString(*ss) +
"'; recompile with -fPIC or remove '-z nocopyreloc'" +
getLocation(sec, sym, offset));
- addCopyRelSymbol<ELFT>(*ss);
+ sym.needsCopy = true;
}
sec.relocations.push_back({expr, type, offset, addend, &sym});
return;
@@ -1077,20 +1103,8 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
errorOrWarn("symbol '" + toString(sym) +
"' cannot be preempted; recompile with -fPIE" +
getLocation(sec, sym, offset));
- if (!sym.isInPlt())
- addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
- if (!sym.isDefined()) {
- replaceWithDefined(
- sym, in.plt,
- target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
- if (config->emachine == EM_PPC) {
- // PPC32 canonical PLT entries are at the beginning of .glink
- cast<Defined>(sym).value = in.plt->headerSize;
- in.plt->headerSize += 16;
- cast<PPC32GlinkSection>(in.plt)->canonical_plts.push_back(&sym);
- }
- }
- sym.needsPltAddr = true;
+ sym.needsCopy = true;
+ sym.needsPlt = true;
sec.relocations.push_back({expr, type, offset, addend, &sym});
return;
}
@@ -1144,13 +1158,10 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT>(expr) &&
config->shared) {
- if (in.got->addDynTlsEntry(sym)) {
- uint64_t off = in.got->getGlobalDynOffset(sym);
- mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
- target->tlsDescRel, in.got, off, sym, target->tlsDescRel);
- }
- if (expr != R_TLSDESC_CALL)
+ if (expr != R_TLSDESC_CALL) {
+ sym.needsTlsDesc = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
+ }
return 1;
}
@@ -1186,14 +1197,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
}
if (expr == R_TLSLD_HINT)
return 1;
- if (in.got->addTlsIndex()) {
- if (isLocalInExecutable)
- 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()});
- }
+ sym.needsTlsLd = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
@@ -1209,12 +1213,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
// Local-Dynamic sequence where offset of tls variable relative to dynamic
// thread pointer is stored in the got. This cannot be relaxed to Local-Exec.
if (expr == R_TLSLD_GOT_OFF) {
- if (!sym.isInGot()) {
- in.got->addEntry(sym);
- uint64_t off = sym.getGotOffset();
- in.got->relocations.push_back(
- {R_ABS, target->tlsOffsetRel, off, 0, &sym});
- }
+ sym.needsGotDtprel = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
@@ -1222,27 +1221,7 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(expr)) {
if (!toExecRelax) {
- if (in.got->addDynTlsEntry(sym)) {
- uint64_t off = in.got->getGlobalDynOffset(sym);
-
- if (isLocalInExecutable)
- // Write one to the GOT slot.
- in.got->relocations.push_back(
- {R_ADDEND, target->symbolicRel, off, 1, &sym});
- else
- 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->addSymbolReloc(target->tlsOffsetRel, in.got,
- offsetOff, sym);
- else
- in.got->relocations.push_back(
- {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym});
- }
+ sym.needsTlsGd = true;
c.relocations.push_back({expr, type, offset, addend, &sym});
return 1;
}
@@ -1250,14 +1229,10 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
// Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
// depending on the symbol being locally defined or not.
if (sym.isPreemptible) {
+ sym.needsTlsGdToIe = true;
c.relocations.push_back(
{target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), type, offset,
addend, &sym});
- if (!sym.isInGot()) {
- in.got->addEntry(sym);
- mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, in.got,
- sym.getGotOffset(), sym);
- }
} else {
c.relocations.push_back(
{target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_LE), type, offset,
@@ -1274,11 +1249,10 @@ handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
c.relocations.push_back(
{R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym});
} else if (expr != R_TLSIE_HINT) {
- if (!sym.isInGot())
- addTpOffsetGotEntry(sym);
+ sym.needsTlsIe = true;
// R_GOT needs a relative relocation for PIC on i386 and Hexagon.
if (expr == R_GOT && config->isPic && !target->usesOnlyLowPageBits(type))
- addRelativeReloc(&c, offset, sym, addend, expr, type);
+ addRelativeReloc(c, offset, sym, addend, expr, type);
else
c.relocations.push_back({expr, type, offset, addend, &sym});
}
@@ -1311,7 +1285,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// Error if the target symbol is undefined. Symbol index 0 may be used by
// marker relocations, e.g. R_*_NONE and R_ARM_V4BX. Don't error on them.
- if (symIndex != 0 && maybeReportUndefined(sym, sec, rel.r_offset))
+ if (sym.isUndefined() && symIndex != 0 &&
+ maybeReportUndefined(sym, sec, rel.r_offset))
return;
const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset;
@@ -1365,8 +1340,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_PLT_GOTPLT,
R_TLSDESC_GOTPLT, R_TLSGD_GOTPLT>(expr)) {
in.gotPlt->hasGotPltOffRel = true;
- } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC64_TOCBASE, R_PPC64_RELAX_TOC>(
- expr)) {
+ } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC32_PLTREL, R_PPC64_TOCBASE,
+ R_PPC64_RELAX_TOC>(expr)) {
in.got->hasGotOffRel = true;
}
@@ -1415,120 +1390,27 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// direct relocation on through.
if (sym.isGnuIFunc() && config->zIfuncNoplt) {
sym.exportDynamic = true;
- mainPart->relaDyn->addSymbolReloc(type, &sec, offset, sym, addend, type);
+ mainPart->relaDyn->addSymbolReloc(type, sec, offset, sym, addend, type);
return;
}
- // Non-preemptible ifuncs require special handling. First, handle the usual
- // case where the symbol isn't one of these.
- if (!sym.isGnuIFunc() || sym.isPreemptible) {
- // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
- if (needsPlt(expr) && !sym.isInPlt())
- addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
-
- // Create a GOT slot if a relocation needs GOT.
- if (needsGot(expr)) {
- if (config->emachine == EM_MIPS) {
- // MIPS ABI has special rules to process GOT entries and doesn't
- // require relocation entries for them. A special case is TLS
- // relocations. In that case dynamic loader applies dynamic
- // relocations to initialize TLS GOT entries.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- in.mipsGot->addEntry(*sec.file, sym, addend, expr);
- } else if (!sym.isInGot()) {
- addGotEntry(sym);
- }
+ if (needsGot(expr)) {
+ if (config->emachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ in.mipsGot->addEntry(*sec.file, sym, addend, expr);
+ } else {
+ sym.needsGot = true;
}
+ } else if (needsPlt(expr)) {
+ sym.needsPlt = true;
} else {
- // Handle a reference to a non-preemptible ifunc. These are special in a
- // few ways:
- //
- // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
- // a fixed value. But assuming that all references to the ifunc are
- // GOT-generating or PLT-generating, the handling of an ifunc is
- // relatively straightforward. We create a PLT entry in Iplt, which is
- // usually at the end of .plt, which makes an indirect call using a
- // matching GOT entry in igotPlt, which is usually at the end of .got.plt.
- // The GOT entry is relocated using an IRELATIVE relocation in relaIplt,
- // which is usually at the end of .rela.plt. Unlike most relocations in
- // .rela.plt, which may be evaluated lazily without -z now, dynamic
- // loaders evaluate IRELATIVE relocs eagerly, which means that for
- // IRELATIVE relocs only, GOT-generating relocations can point directly to
- // .got.plt without requiring a separate GOT entry.
- //
- // - Despite the fact that an ifunc does not have a fixed value, compilers
- // that are not passed -fPIC will assume that they do, and will emit
- // direct (non-GOT-generating, non-PLT-generating) relocations to the
- // symbol. This means that if a direct relocation to the symbol is
- // seen, the linker must set a value for the symbol, and this value must
- // be consistent no matter what type of reference is made to the symbol.
- // This can be done by creating a PLT entry for the symbol in the way
- // described above and making it canonical, that is, making all references
- // point to the PLT entry instead of the resolver. In lld we also store
- // the address of the PLT entry in the dynamic symbol table, which means
- // that the symbol will also have the same value in other modules.
- // Because the value loaded from the GOT needs to be consistent with
- // the value computed using a direct relocation, a non-preemptible ifunc
- // may end up with two GOT entries, one in .got.plt that points to the
- // address returned by the resolver and is used only by the PLT entry,
- // and another in .got that points to the PLT entry and is used by
- // GOT-generating relocations.
- //
- // - The fact that these symbols do not have a fixed value makes them an
- // exception to the general rule that a statically linked executable does
- // not require any form of dynamic relocation. To handle these relocations
- // correctly, the IRELATIVE relocations are stored in an array which a
- // statically linked executable's startup code must enumerate using the
- // linker-defined symbols __rela?_iplt_{start,end}.
- if (!sym.isInPlt()) {
- // Create PLT and GOTPLT slots for the symbol.
- sym.isInIplt = true;
-
- // Create a copy of the symbol to use as the target of the IRELATIVE
- // relocation in the igotPlt. This is in case we make the PLT canonical
- // later, which would overwrite the original symbol.
- //
- // FIXME: Creating a copy of the symbol here is a bit of a hack. All
- // that's really needed to create the IRELATIVE is the section and value,
- // so ideally we should just need to copy those.
- auto *directSym = make<Defined>(cast<Defined>(sym));
- addPltEntry(in.iplt, in.igotPlt, in.relaIplt, target->iRelativeRel,
- *directSym);
- sym.pltIndex = directSym->pltIndex;
- }
- if (needsGot(expr)) {
- // Redirect GOT accesses to point to the Igot.
- //
- // This field is also used to keep track of whether we ever needed a GOT
- // entry. If we did and we make the PLT canonical later, we'll need to
- // create a GOT entry pointing to the PLT entry for Sym.
- sym.gotInIgot = true;
- } else if (!needsPlt(expr)) {
- // Make the ifunc's PLT entry canonical by changing the value of its
- // symbol to redirect all references to point to it.
- auto &d = cast<Defined>(sym);
- d.section = in.iplt;
- d.value = sym.pltIndex * target->ipltEntrySize;
- d.size = 0;
- // It's important to set the symbol type here so that dynamic loaders
- // don't try to call the PLT as if it were an ifunc resolver.
- d.type = STT_FUNC;
-
- if (sym.gotInIgot) {
- // We previously encountered a GOT generating reference that we
- // redirected to the Igot. Now that the PLT entry is canonical we must
- // clear the redirection to the Igot and add a GOT entry. As we've
- // changed the symbol type to STT_FUNC future GOT generating references
- // will naturally use this GOT entry.
- //
- // We don't need to worry about creating a MIPS GOT here because ifuncs
- // aren't a thing on MIPS.
- sym.gotInIgot = false;
- addGotEntry(sym);
- }
- }
+ sym.hasDirectReloc = true;
}
processRelocAux<ELFT>(sec, expr, type, offset, sym, addend);
@@ -1609,6 +1491,179 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
scanRelocs<ELFT>(s, rels.relas);
}
+static bool handleNonPreemptibleIfunc(Symbol &sym) {
+ // Handle a reference to a non-preemptible ifunc. These are special in a
+ // few ways:
+ //
+ // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
+ // a fixed value. But assuming that all references to the ifunc are
+ // GOT-generating or PLT-generating, the handling of an ifunc is
+ // relatively straightforward. We create a PLT entry in Iplt, which is
+ // usually at the end of .plt, which makes an indirect call using a
+ // matching GOT entry in igotPlt, which is usually at the end of .got.plt.
+ // The GOT entry is relocated using an IRELATIVE relocation in relaIplt,
+ // which is usually at the end of .rela.plt. Unlike most relocations in
+ // .rela.plt, which may be evaluated lazily without -z now, dynamic
+ // loaders evaluate IRELATIVE relocs eagerly, which means that for
+ // IRELATIVE relocs only, GOT-generating relocations can point directly to
+ // .got.plt without requiring a separate GOT entry.
+ //
+ // - Despite the fact that an ifunc does not have a fixed value, compilers
+ // that are not passed -fPIC will assume that they do, and will emit
+ // direct (non-GOT-generating, non-PLT-generating) relocations to the
+ // symbol. This means that if a direct relocation to the symbol is
+ // seen, the linker must set a value for the symbol, and this value must
+ // be consistent no matter what type of reference is made to the symbol.
+ // This can be done by creating a PLT entry for the symbol in the way
+ // described above and making it canonical, that is, making all references
+ // point to the PLT entry instead of the resolver. In lld we also store
+ // the address of the PLT entry in the dynamic symbol table, which means
+ // that the symbol will also have the same value in other modules.
+ // Because the value loaded from the GOT needs to be consistent with
+ // the value computed using a direct relocation, a non-preemptible ifunc
+ // may end up with two GOT entries, one in .got.plt that points to the
+ // address returned by the resolver and is used only by the PLT entry,
+ // and another in .got that points to the PLT entry and is used by
+ // GOT-generating relocations.
+ //
+ // - The fact that these symbols do not have a fixed value makes them an
+ // exception to the general rule that a statically linked executable does
+ // not require any form of dynamic relocation. To handle these relocations
+ // correctly, the IRELATIVE relocations are stored in an array which a
+ // statically linked executable's startup code must enumerate using the
+ // linker-defined symbols __rela?_iplt_{start,end}.
+ if (!sym.isGnuIFunc() || sym.isPreemptible || config->zIfuncNoplt)
+ return false;
+ // Skip unreferenced non-preemptible ifunc.
+ if (!(sym.needsGot || sym.needsPlt || sym.hasDirectReloc))
+ return true;
+
+ sym.isInIplt = true;
+
+ // Create an Iplt and the associated IRELATIVE relocation pointing to the
+ // original section/value pairs. For non-GOT non-PLT relocation case below, we
+ // may alter section/value, so create a copy of the symbol to make
+ // section/value fixed.
+ auto *directSym = makeDefined(cast<Defined>(sym));
+ addPltEntry(*in.iplt, *in.igotPlt, *in.relaIplt, target->iRelativeRel,
+ *directSym);
+ sym.pltIndex = directSym->pltIndex;
+
+ if (sym.hasDirectReloc) {
+ // Change the value to the IPLT and redirect all references to it.
+ auto &d = cast<Defined>(sym);
+ d.section = in.iplt;
+ d.value = sym.pltIndex * target->ipltEntrySize;
+ d.size = 0;
+ // It's important to set the symbol type here so that dynamic loaders
+ // don't try to call the PLT as if it were an ifunc resolver.
+ d.type = STT_FUNC;
+
+ if (sym.needsGot)
+ addGotEntry(sym);
+ } else if (sym.needsGot) {
+ // Redirect GOT accesses to point to the Igot.
+ sym.gotInIgot = true;
+ }
+ return true;
+}
+
+void elf::postScanRelocations() {
+ auto fn = [](Symbol &sym) {
+ if (handleNonPreemptibleIfunc(sym))
+ return;
+ if (sym.needsGot)
+ addGotEntry(sym);
+ if (sym.needsPlt)
+ addPltEntry(*in.plt, *in.gotPlt, *in.relaPlt, target->pltRel, sym);
+ if (sym.needsCopy) {
+ if (sym.isObject()) {
+ addCopyRelSymbol(cast<SharedSymbol>(sym));
+ // needsCopy is cleared for sym and its aliases so that in later
+ // iterations aliases won't cause redundant copies.
+ assert(!sym.needsCopy);
+ } else {
+ assert(sym.isFunc() && sym.needsPlt);
+ if (!sym.isDefined()) {
+ replaceWithDefined(
+ sym, *in.plt,
+ target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
+ sym.needsCopy = true;
+ if (config->emachine == EM_PPC) {
+ // PPC32 canonical PLT entries are at the beginning of .glink
+ cast<Defined>(sym).value = in.plt->headerSize;
+ in.plt->headerSize += 16;
+ cast<PPC32GlinkSection>(*in.plt).canonical_plts.push_back(&sym);
+ }
+ }
+ }
+ }
+
+ if (!sym.isTls())
+ return;
+ bool isLocalInExecutable = !sym.isPreemptible && !config->shared;
+
+ if (sym.needsTlsDesc) {
+ in.got->addDynTlsEntry(sym);
+ mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
+ target->tlsDescRel, *in.got, in.got->getGlobalDynOffset(sym), sym,
+ target->tlsDescRel);
+ }
+ if (sym.needsTlsGd && !sym.needsTlsDesc) {
+ // TODO Support mixed TLSDESC and TLS GD.
+ in.got->addDynTlsEntry(sym);
+ uint64_t off = in.got->getGlobalDynOffset(sym);
+ if (isLocalInExecutable)
+ // Write one to the GOT slot.
+ in.got->relocations.push_back(
+ {R_ADDEND, target->symbolicRel, off, 1, &sym});
+ else
+ 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->addSymbolReloc(target->tlsOffsetRel, *in.got,
+ offsetOff, sym);
+ else
+ in.got->relocations.push_back(
+ {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym});
+ }
+ if (sym.needsTlsGdToIe) {
+ in.got->addEntry(sym);
+ mainPart->relaDyn->addSymbolReloc(target->tlsGotRel, *in.got,
+ sym.getGotOffset(), sym);
+ }
+
+ if (sym.needsTlsLd && in.got->addTlsIndex()) {
+ if (isLocalInExecutable)
+ 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()});
+ }
+ if (sym.needsGotDtprel) {
+ in.got->addEntry(sym);
+ in.got->relocations.push_back(
+ {R_ABS, target->tlsOffsetRel, sym.getGotOffset(), 0, &sym});
+ }
+
+ if (sym.needsTlsIe && !sym.needsTlsGdToIe)
+ addTpOffsetGotEntry(sym);
+ };
+ for (Symbol *sym : symtab->symbols())
+ fn(*sym);
+
+ // Local symbols may need the aforementioned non-preemptible ifunc and GOT
+ // handling. They don't need regular PLT.
+ for (ELFFileBase *file : objectFiles)
+ for (Symbol *sym : cast<ELFFileBase>(file)->getLocalSymbols())
+ fn(*sym);
+}
+
static bool mergeCmp(const InputSection *a, const InputSection *b) {
// std::merge requires a strict weak ordering.
if (a->outSecOff < b->outSecOff)
@@ -1964,8 +2019,8 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
// non-Thunk target, so we cannot fold offset + addend.
if (auto *d = dyn_cast<Defined>(rel.sym))
if (!d->isInPlt() && d->section)
- thunkVec = &thunkedSymbolsBySectionAndAddend[{
- {d->section->repl, d->value}, keyAddend}];
+ thunkVec = &thunkedSymbolsBySectionAndAddend[{{d->section, d->value},
+ keyAddend}];
if (!thunkVec)
thunkVec = &thunkedSymbols[{rel.sym, keyAddend}];
@@ -2119,7 +2174,7 @@ void elf::hexagonTLSSymbolUpdate(ArrayRef<OutputSection *> outputSections) {
for (Relocation &rel : isec->relocations)
if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC) {
if (needEntry) {
- addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel,
+ addPltEntry(*in.plt, *in.gotPlt, *in.relaPlt, target->pltRel,
*sym);
needEntry = false;
}