diff options
Diffstat (limited to 'contrib/llvm-project/lld/ELF/Relocations.cpp')
-rw-r--r-- | contrib/llvm-project/lld/ELF/Relocations.cpp | 627 |
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) { |