aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lld/ELF/Relocations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lld/ELF/Relocations.cpp')
-rw-r--r--contrib/llvm-project/lld/ELF/Relocations.cpp627
1 files changed, 308 insertions, 319 deletions
diff --git a/contrib/llvm-project/lld/ELF/Relocations.cpp b/contrib/llvm-project/lld/ELF/Relocations.cpp
index eb3d115266a6..49bd5f4c4fa1 100644
--- a/contrib/llvm-project/lld/ELF/Relocations.cpp
+++ b/contrib/llvm-project/lld/ELF/Relocations.cpp
@@ -101,8 +101,11 @@ void elf::reportRangeError(uint8_t *loc, const Relocation &rel, const Twine &v,
ErrorPlace errPlace = getErrorPlace(loc);
std::string hint;
if (rel.sym && !rel.sym->isLocal())
- hint = "; references " + lld::toString(*rel.sym) +
- getDefinedLocation(*rel.sym);
+ hint = "; references " + lld::toString(*rel.sym);
+ if (!errPlace.srcLoc.empty())
+ hint += "\n>>> referenced by " + errPlace.srcLoc;
+ if (rel.sym && !rel.sym->isLocal())
+ hint += getDefinedLocation(*rel.sym);
if (errPlace.isec && errPlace.isec->name.startswith(".debug"))
hint += "; consider recompiling with -fdebug-types-section to reduce size "
@@ -124,213 +127,27 @@ void elf::reportRangeError(uint8_t *loc, int64_t v, int n, const Symbol &sym,
Twine(llvm::maxIntN(n)) + "]" + hint);
}
-namespace {
-// Build a bitmask with one bit set for each RelExpr.
-//
-// Constexpr function arguments can't be used in static asserts, so we
-// use template arguments to build the mask.
-// But function template partial specializations don't exist (needed
-// for base case of the recursion), so we need a dummy struct.
-template <RelExpr... Exprs> struct RelExprMaskBuilder {
- static inline uint64_t build() { return 0; }
-};
-
-// Specialization for recursive case.
-template <RelExpr Head, RelExpr... Tail>
-struct RelExprMaskBuilder<Head, Tail...> {
- static inline uint64_t build() {
- static_assert(0 <= Head && Head < 64,
- "RelExpr is too large for 64-bit mask!");
- return (uint64_t(1) << Head) | RelExprMaskBuilder<Tail...>::build();
- }
-};
-} // namespace
+// Build a bitmask with one bit set for each 64 subset of RelExpr.
+static constexpr uint64_t buildMask() { return 0; }
-// Return true if `Expr` is one of `Exprs`.
-// There are fewer than 64 RelExpr's, so we can represent any set of
-// RelExpr's as a constant bit mask and test for membership with a
-// couple cheap bitwise operations.
-template <RelExpr... Exprs> bool oneof(RelExpr expr) {
- assert(0 <= expr && (int)expr < 64 &&
- "RelExpr is too large for 64-bit mask!");
- return (uint64_t(1) << expr) & RelExprMaskBuilder<Exprs...>::build();
+template <typename... Tails>
+static constexpr uint64_t buildMask(int head, Tails... tails) {
+ return (0 <= head && head < 64 ? uint64_t(1) << head : 0) |
+ buildMask(tails...);
}
-// This function is similar to the `handleTlsRelocation`. MIPS does not
-// support any relaxations for TLS relocations so by factoring out MIPS
-// handling in to the separate function we can simplify the code and do not
-// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
-// Mips has a custom MipsGotSection that handles the writing of GOT entries
-// without dynamic relocations.
-static unsigned handleMipsTlsRelocation(RelType type, Symbol &sym,
- InputSectionBase &c, uint64_t offset,
- int64_t addend, RelExpr expr) {
- if (expr == R_MIPS_TLSLD) {
- in.mipsGot->addTlsIndex(*c.file);
- c.relocations.push_back({expr, type, offset, addend, &sym});
- return 1;
- }
- if (expr == R_MIPS_TLSGD) {
- in.mipsGot->addDynTlsEntry(*c.file, sym);
- c.relocations.push_back({expr, type, offset, addend, &sym});
- return 1;
- }
- return 0;
-}
-
-// Notes about General Dynamic and Local Dynamic TLS models below. They may
-// require the generation of a pair of GOT entries that have associated dynamic
-// relocations. The pair of GOT entries created are of the form GOT[e0] Module
-// Index (Used to find pointer to TLS block at run-time) GOT[e1] Offset of
-// symbol in TLS block.
-//
-// Returns the number of relocations processed.
-template <class ELFT>
-static unsigned
-handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
- typename ELFT::uint offset, int64_t addend, RelExpr expr) {
- if (!sym.isTls())
- return 0;
-
- if (config->emachine == EM_MIPS)
- return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
-
- if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC>(
- 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)
- c.relocations.push_back({expr, type, offset, addend, &sym});
- return 1;
- }
-
- // ARM, Hexagon and RISC-V do not support GD/LD to IE/LE relaxation. For
- // PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
- // relaxation as well.
- bool toExecRelax = !config->shared && config->emachine != EM_ARM &&
- config->emachine != EM_HEXAGON &&
- config->emachine != EM_RISCV &&
- !c.file->ppc64DisableTLSRelax;
-
- // If we are producing an executable and the symbol is non-preemptable, it
- // must be defined and the code sequence can be relaxed to use Local-Exec.
- //
- // ARM and RISC-V do not support any relaxations for TLS relocations, however,
- // we can omit the DTPMOD dynamic relocations and resolve them at link time
- // because them are always 1. This may be necessary for static linking as
- // DTPMOD may not be expected at load time.
- bool isLocalInExecutable = !sym.isPreemptible && !config->shared;
-
- // Local Dynamic is for access to module local TLS variables, while still
- // being suitable for being dynamically loaded via dlopen. GOT[e0] is the
- // module index, with a special value of 0 for the current module. GOT[e1] is
- // unused. There only needs to be one module index entry.
- if (oneof<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>(
- expr)) {
- // Local-Dynamic relocs can be relaxed to Local-Exec.
- if (toExecRelax) {
- c.relocations.push_back(
- {target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE), type, offset,
- addend, &sym});
- return target->getTlsGdRelaxSkip(type);
- }
- 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()});
- }
- c.relocations.push_back({expr, type, offset, addend, &sym});
- return 1;
- }
-
- // Local-Dynamic relocs can be relaxed to Local-Exec.
- if (expr == R_DTPREL && toExecRelax) {
- c.relocations.push_back({target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE),
- type, offset, addend, &sym});
- return 1;
- }
-
- // 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});
- }
- c.relocations.push_back({expr, type, offset, addend, &sym});
- return 1;
- }
-
- if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
- 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});
- }
- c.relocations.push_back({expr, type, offset, addend, &sym});
- return 1;
- }
-
- // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
- // depending on the symbol being locally defined or not.
- if (sym.isPreemptible) {
- 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,
- addend, &sym});
- }
- return target->getTlsGdRelaxSkip(type);
- }
-
- // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
- // defined.
- if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, R_AARCH64_GOT_PAGE_PC, R_GOT_OFF,
- R_TLSIE_HINT>(expr) &&
- toExecRelax && isLocalInExecutable) {
- c.relocations.push_back({R_RELAX_TLS_IE_TO_LE, type, offset, addend, &sym});
- return 1;
- }
-
- if (expr == R_TLSIE_HINT)
- return 1;
- return 0;
+// Return true if `Expr` is one of `Exprs`.
+// There are more than 64 but less than 128 RelExprs, so we divide the set of
+// exprs into [0, 64) and [64, 128) and represent each range as a constant
+// 64-bit mask. Then we decide which mask to test depending on the value of
+// expr and use a simple shift and bitwise-and to test for membership.
+template <RelExpr... Exprs> static bool oneof(RelExpr expr) {
+ assert(0 <= expr && (int)expr < 128 &&
+ "RelExpr is too large for 128-bit mask!");
+
+ if (expr >= 64)
+ return (uint64_t(1) << (expr - 64)) & buildMask((Exprs - 64)...);
+ return (uint64_t(1) << expr) & buildMask(Exprs...);
}
static RelType getMipsPairType(RelType type, bool isLocal) {
@@ -374,7 +191,8 @@ static bool isAbsoluteValue(const Symbol &sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr expr) {
- return oneof<R_PLT_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PLT>(expr);
+ return oneof<R_PLT, R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT>(
+ expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@@ -394,73 +212,6 @@ static bool isRelExpr(RelExpr expr) {
R_RISCV_PC_INDIRECT, R_PPC64_RELAX_GOT_PC>(expr);
}
-// Returns true if a given relocation can be computed at link-time.
-//
-// For instance, we know the offset from a relocation to its target at
-// link-time if the relocation is PC-relative and refers a
-// non-interposable function in the same executable. This function
-// will return true for such relocation.
-//
-// If this function returns false, that means we need to emit a
-// dynamic relocation so that the relocation will be fixed at load-time.
-static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
- InputSectionBase &s, uint64_t relOff) {
- // These expressions always compute a constant
- if (oneof<R_DTPREL, R_GOTPLT, R_GOT_OFF, R_TLSLD_GOT_OFF,
- R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
- R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
- R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL,
- R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_TLSDESC_CALL,
- R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT,
- R_AARCH64_GOT_PAGE>(
- e))
- return true;
-
- // These never do, except if the entire file is position dependent or if
- // only the low bits are used.
- if (e == R_GOT || e == R_PLT || e == R_TLSDESC)
- return target->usesOnlyLowPageBits(type) || !config->isPic;
-
- if (sym.isPreemptible)
- return false;
- if (!config->isPic)
- return true;
-
- // The size of a non preemptible symbol is a constant.
- if (e == R_SIZE)
- return true;
-
- // For the target and the relocation, we want to know if they are
- // absolute or relative.
- bool absVal = isAbsoluteValue(sym);
- bool relE = isRelExpr(e);
- if (absVal && !relE)
- return true;
- if (!absVal && relE)
- return true;
- if (!absVal && !relE)
- return target->usesOnlyLowPageBits(type);
-
- assert(absVal && relE);
-
- // Allow R_PLT_PC (optimized to R_PC here) to a hidden undefined weak symbol
- // in PIC mode. This is a little strange, but it allows us to link function
- // calls to such symbols (e.g. glibc/stdlib/exit.c:__run_exit_handlers).
- // Normally such a call will be guarded with a comparison, which will load a
- // zero from the GOT.
- if (sym.isUndefWeak())
- return true;
-
- // We set the final symbols values for linker script defined symbols later.
- // They always can be computed as a link time constant.
- if (sym.scriptDefined)
- return true;
-
- error("relocation " + toString(type) + " cannot refer to absolute symbol: " +
- toString(sym) + getLocation(s, sym, relOff));
- return true;
-}
static RelExpr toPlt(RelExpr expr) {
switch (expr) {
@@ -486,6 +237,8 @@ static RelExpr fromPlt(RelExpr expr) {
return R_PPC64_CALL;
case R_PLT:
return R_ABS;
+ case R_PLT_GOTPLT:
+ return R_GOTPLTREL;
default:
return expr;
}
@@ -1087,33 +840,32 @@ static void addPltEntry(PltSection *plt, GotPltSection *gotPlt,
static void addGotEntry(Symbol &sym) {
in.got->addEntry(sym);
-
- RelExpr expr = sym.isTls() ? R_TPREL : R_ABS;
uint64_t off = sym.getGotOffset();
- // If a GOT slot value can be calculated at link-time, which is now,
- // we can just fill that out.
- //
- // (We don't actually write a value to a GOT slot right now, but we
- // add a static relocation to a Relocations vector so that
- // InputSection::relocate will do the work for us. We may be able
- // to just write a value now, but it is a TODO.)
- bool isLinkTimeConstant =
- !sym.isPreemptible && (!config->isPic || isAbsolute(sym));
- if (isLinkTimeConstant) {
- in.got->relocations.push_back({expr, target->symbolicRel, off, 0, &sym});
+ // If preemptible, emit a GLOB_DAT relocation.
+ if (sym.isPreemptible) {
+ mainPart->relaDyn->addReloc({target->gotRel, in.got, off,
+ DynamicReloc::AgainstSymbol, sym, 0, R_ABS});
return;
}
- // 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) {
+ // Otherwise, the value is either a link-time constant or the load base
+ // plus a constant.
+ 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);
+}
+
+static void addTpOffsetGotEntry(Symbol &sym) {
+ in.got->addEntry(sym);
+ uint64_t off = sym.getGotOffset();
+ if (!sym.isPreemptible && !config->isPic) {
+ in.got->relocations.push_back({R_TPREL, target->symbolicRel, off, 0, &sym});
return;
}
mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
- sym.isTls() ? target->tlsGotRel : target->gotRel, 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
@@ -1136,6 +888,71 @@ static bool canDefineSymbolInExecutable(Symbol &sym) {
(sym.isObject() && config->ignoreDataAddressEquality));
}
+// Returns true if a given relocation can be computed at link-time.
+// This only handles relocation types expected in processRelocAux.
+//
+// For instance, we know the offset from a relocation to its target at
+// link-time if the relocation is PC-relative and refers a
+// non-interposable function in the same executable. This function
+// will return true for such relocation.
+//
+// If this function returns false, that means we need to emit a
+// dynamic relocation so that the relocation will be fixed at load-time.
+static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
+ InputSectionBase &s, uint64_t relOff) {
+ // These expressions always compute a constant
+ if (oneof<R_GOTPLT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL,
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
+ R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC,
+ R_PLT_PC, R_PLT_GOTPLT, R_PPC32_PLTREL, R_PPC64_CALL_PLT,
+ R_PPC64_RELAX_TOC, R_RISCV_ADD, R_AARCH64_GOT_PAGE>(e))
+ return true;
+
+ // These never do, except if the entire file is position dependent or if
+ // only the low bits are used.
+ if (e == R_GOT || e == R_PLT)
+ return target->usesOnlyLowPageBits(type) || !config->isPic;
+
+ if (sym.isPreemptible)
+ return false;
+ if (!config->isPic)
+ return true;
+
+ // The size of a non preemptible symbol is a constant.
+ if (e == R_SIZE)
+ return true;
+
+ // For the target and the relocation, we want to know if they are
+ // absolute or relative.
+ bool absVal = isAbsoluteValue(sym);
+ bool relE = isRelExpr(e);
+ if (absVal && !relE)
+ return true;
+ if (!absVal && relE)
+ return true;
+ if (!absVal && !relE)
+ return target->usesOnlyLowPageBits(type);
+
+ assert(absVal && relE);
+
+ // Allow R_PLT_PC (optimized to R_PC here) to a hidden undefined weak symbol
+ // in PIC mode. This is a little strange, but it allows us to link function
+ // calls to such symbols (e.g. glibc/stdlib/exit.c:__run_exit_handlers).
+ // Normally such a call will be guarded with a comparison, which will load a
+ // zero from the GOT.
+ if (sym.isUndefWeak())
+ return true;
+
+ // We set the final symbols values for linker script defined symbols later.
+ // They always can be computed as a link time constant.
+ if (sym.scriptDefined)
+ return true;
+
+ error("relocation " + toString(type) + " cannot refer to absolute symbol: " +
+ toString(sym) + getLocation(s, sym, relOff));
+ return true;
+}
+
// The reason we have to do this early scan is as follows
// * To mmap the output file, we need to know the size
// * For that, we need to know how many dynamic relocs we will have.
@@ -1149,10 +966,9 @@ static bool canDefineSymbolInExecutable(Symbol &sym) {
// sections. Given that it is ro, we will need an extra PT_LOAD. This
// complicates things for the dynamic linker and means we would have to reserve
// space for the extra PT_LOAD even if we end up not using it.
-template <class ELFT, class RelTy>
+template <class ELFT>
static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
- uint64_t offset, Symbol &sym, const RelTy &rel,
- int64_t addend) {
+ uint64_t offset, Symbol &sym, int64_t addend) {
// If the relocation is known to be a link-time constant, we know no dynamic
// relocation will be created, pass the control to relocateAlloc() or
// relocateNonAlloc() to resolve it.
@@ -1280,25 +1096,196 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
}
}
- if (config->isPic) {
- if (!canWrite && !isRelExpr(expr))
- errorOrWarn(
- "can't create dynamic relocation " + toString(type) + " against " +
- (sym.getName().empty() ? "local symbol"
- : "symbol: " + toString(sym)) +
- " in readonly segment; recompile object files with -fPIC "
- "or pass '-Wl,-z,notext' to allow text relocations in the output" +
- getLocation(sec, sym, offset));
- else
- errorOrWarn(
- "relocation " + toString(type) + " cannot be used against " +
- (sym.getName().empty() ? "local symbol" : "symbol " + toString(sym)) +
- "; recompile with -fPIC" + getLocation(sec, sym, offset));
- return;
+ errorOrWarn("relocation " + toString(type) + " cannot be used against " +
+ (sym.getName().empty() ? "local symbol"
+ : "symbol '" + toString(sym) + "'") +
+ "; recompile with -fPIC" + getLocation(sec, sym, offset));
+}
+
+// This function is similar to the `handleTlsRelocation`. MIPS does not
+// support any relaxations for TLS relocations so by factoring out MIPS
+// handling in to the separate function we can simplify the code and do not
+// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
+// Mips has a custom MipsGotSection that handles the writing of GOT entries
+// without dynamic relocations.
+static unsigned handleMipsTlsRelocation(RelType type, Symbol &sym,
+ InputSectionBase &c, uint64_t offset,
+ int64_t addend, RelExpr expr) {
+ if (expr == R_MIPS_TLSLD) {
+ in.mipsGot->addTlsIndex(*c.file);
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ return 1;
+ }
+ if (expr == R_MIPS_TLSGD) {
+ in.mipsGot->addDynTlsEntry(*c.file, sym);
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ return 1;
+ }
+ return 0;
+}
+
+// Notes about General Dynamic and Local Dynamic TLS models below. They may
+// require the generation of a pair of GOT entries that have associated dynamic
+// relocations. The pair of GOT entries created are of the form GOT[e0] Module
+// Index (Used to find pointer to TLS block at run-time) GOT[e1] Offset of
+// symbol in TLS block.
+//
+// Returns the number of relocations processed.
+template <class ELFT>
+static unsigned
+handleTlsRelocation(RelType type, Symbol &sym, InputSectionBase &c,
+ typename ELFT::uint offset, int64_t addend, RelExpr expr) {
+ if (!sym.isTls())
+ return 0;
+
+ if (config->emachine == EM_MIPS)
+ return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
+
+ 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)
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ return 1;
}
- errorOrWarn("symbol '" + toString(sym) + "' has no type" +
- getLocation(sec, sym, offset));
+ // ARM, Hexagon and RISC-V do not support GD/LD to IE/LE relaxation. For
+ // PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable
+ // relaxation as well.
+ bool toExecRelax = !config->shared && config->emachine != EM_ARM &&
+ config->emachine != EM_HEXAGON &&
+ config->emachine != EM_RISCV &&
+ !c.file->ppc64DisableTLSRelax;
+
+ // If we are producing an executable and the symbol is non-preemptable, it
+ // must be defined and the code sequence can be relaxed to use Local-Exec.
+ //
+ // ARM and RISC-V do not support any relaxations for TLS relocations, however,
+ // we can omit the DTPMOD dynamic relocations and resolve them at link time
+ // because them are always 1. This may be necessary for static linking as
+ // DTPMOD may not be expected at load time.
+ bool isLocalInExecutable = !sym.isPreemptible && !config->shared;
+
+ // Local Dynamic is for access to module local TLS variables, while still
+ // being suitable for being dynamically loaded via dlopen. GOT[e0] is the
+ // module index, with a special value of 0 for the current module. GOT[e1] is
+ // unused. There only needs to be one module index entry.
+ if (oneof<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>(
+ expr)) {
+ // Local-Dynamic relocs can be relaxed to Local-Exec.
+ if (toExecRelax) {
+ c.relocations.push_back(
+ {target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE), type, offset,
+ addend, &sym});
+ return target->getTlsGdRelaxSkip(type);
+ }
+ 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()});
+ }
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ return 1;
+ }
+
+ // Local-Dynamic relocs can be relaxed to Local-Exec.
+ if (expr == R_DTPREL) {
+ if (toExecRelax)
+ expr = target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE);
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ return 1;
+ }
+
+ // 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});
+ }
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ return 1;
+ }
+
+ 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});
+ }
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ return 1;
+ }
+
+ // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
+ // depending on the symbol being locally defined or not.
+ if (sym.isPreemptible) {
+ 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,
+ addend, &sym});
+ }
+ return target->getTlsGdRelaxSkip(type);
+ }
+
+ if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, R_AARCH64_GOT_PAGE_PC, R_GOT_OFF,
+ R_TLSIE_HINT>(expr)) {
+ // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
+ // defined.
+ if (toExecRelax && isLocalInExecutable) {
+ 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);
+ // 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);
+ else
+ c.relocations.push_back({expr, type, offset, addend, &sym});
+ }
+ return 1;
+ }
+
+ return 0;
}
template <class ELFT, class RelTy>
@@ -1346,7 +1333,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// have got-based small code model relocs. The .toc sections get placed
// after the end of the linker allocated .got section and we do sort those
// so sections addressed with small code model relocations come first.
- if (isPPC64SmallCodeModelTocReloc(type))
+ if (type == R_PPC64_TOC16 || type == R_PPC64_TOC16_DS)
sec.file->ppc64SmallCodeModelTocRelocs = true;
// Record the TOC entry (.toc + addend) as not relaxable. See the comment in
@@ -1400,8 +1387,9 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// If the relocation does not emit a GOT or GOTPLT entry but its computation
// uses their addresses, we need GOT or GOTPLT to be created.
//
- // The 4 types that relative GOTPLT are all x86 and x86-64 specific.
- if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_TLSGD_GOTPLT>(expr)) {
+ // The 5 types that relative GOTPLT are all x86 and x86-64 specific.
+ 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)) {
@@ -1543,7 +1531,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
}
}
- processRelocAux<ELFT>(sec, expr, type, offset, sym, rel, addend);
+ processRelocAux<ELFT>(sec, expr, type, offset, sym, addend);
}
// R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for
@@ -1614,10 +1602,11 @@ static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) {
}
template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
- if (s.areRelocsRela)
- scanRelocs<ELFT>(s, s.relas<ELFT>());
+ const RelsOrRelas<ELFT> rels = s.template relsOrRelas<ELFT>();
+ if (rels.areRelocsRel())
+ scanRelocs<ELFT>(s, rels.rels);
else
- scanRelocs<ELFT>(s, s.rels<ELFT>());
+ scanRelocs<ELFT>(s, rels.relas);
}
static bool mergeCmp(const InputSection *a, const InputSection *b) {