diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -150,8 +150,9 @@ case R_AARCH64_LD64_GOTPAGE_LO15: return R_AARCH64_GOT_PAGE; case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: return R_AARCH64_GOT_PAGE_PC; + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + return R_AARCH64_TLS_GOT_PAGE_PC; case R_AARCH64_NONE: return R_NONE; default: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -699,6 +699,7 @@ case R_RELAX_TLS_GD_TO_IE_GOT_OFF: return sym.getGotOffset() + a; case R_AARCH64_GOT_PAGE_PC: + case R_AARCH64_TLS_GOT_PAGE_PC: case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(p); case R_AARCH64_GOT_PAGE: diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -84,6 +84,7 @@ // of a relocation type, there are some relocations whose semantics are // unique to a target. Such relocation are marked with R_. R_AARCH64_GOT_PAGE_PC, + R_AARCH64_TLS_GOT_PAGE_PC, R_AARCH64_GOT_PAGE, R_AARCH64_PAGE_PC, R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC, diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -887,6 +887,14 @@ (sym.isObject() && config->ignoreDataAddressEquality)); } +static void invalidRelocAgainstSym(InputSectionBase &sec, uint64_t offset, + RelType type, Symbol &sym) { + errorOrWarn("relocation " + toString(type) + " cannot be used against " + + (sym.getName().empty() ? "local symbol" + : "symbol '" + toString(sym) + "'") + + "; recompile with -fPIC" + getLocation(sec, sym, offset)); +} + // Returns true if a given relocation can be computed at link-time. // This only handles relocation types expected in processRelocAux. // @@ -897,19 +905,20 @@ // // 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(e)) + R_PPC64_RELAX_TOC>(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_TLS_GOT) + if (e == R_GOT || e == R_PLT) return target->usesOnlyLowPageBits(type) || !config->isPic; if (sym.isPreemptible) @@ -982,7 +991,7 @@ // -shared matches the spirit of its -z undefs default. -pie has freedom on // choices, and we choose dynamic relocations to be consistent with the // handling of GOT-generating relocations. - if (isStaticLinkTimeConstant(expr, type, sym, sec, offset) || + if (customRelocIsLinkTimeConstant(expr, type, sym, sec, offset) || (!config->isPic && sym.isUndefWeak())) { sec.relocations.push_back({expr, type, offset, addend, &sym}); return; @@ -1095,16 +1104,13 @@ } } - errorOrWarn("relocation " + toString(type) + " cannot be used against " + - (sym.getName().empty() ? "local symbol" - : "symbol '" + toString(sym) + "'") + - "; recompile with -fPIC" + getLocation(sec, sym, offset)); + invalidRelocAgainstSym(sec, offset, type, sym); } -// This function is similar to the `handleTlsRelocation`. MIPS does not +// This function is similar to the `handleTlsRelocationNonIE`. 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. +// pollute other `handleTlsRelocationNonIE` 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, @@ -1123,23 +1129,47 @@ return 0; } +template +static void handleTlsIe(RelType type, Symbol &sym, InputSectionBase &c, + typename ELFT::uint offset, int64_t addend, + RelExpr expr, bool relax) { + // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally + // defined. + if (relax) { + 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_TLS_GOT needs a relative relocation for PIC on i386 and Hexagon. + if (expr == R_TLS_GOT && config->isPic && + !target->usesOnlyLowPageBits(type)) + addRelativeReloc(&c, offset, sym, addend, expr, type); + else + c.relocations.push_back({expr, type, offset, addend, &sym}); + } +} + +static inline bool toExecRelax(const InputSectionBase &sec) { + // 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. + auto m = config->emachine; + return !config->shared && m != EM_ARM && m != EM_MIPS && m != EM_HEXAGON && + m != EM_RISCV && !sec.file->ppc64DisableTLSRelax; +} + // 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. +// Returns the number of subsequent relocations which should be skipped. template -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); - +static unsigned handleTlsRelocationNonIE(RelType type, Symbol &sym, + InputSectionBase &c, + typename ELFT::uint offset, + int64_t addend, RelExpr expr) { if (oneof(expr) && config->shared) { @@ -1150,17 +1180,9 @@ } if (expr != R_TLSDESC_CALL) c.relocations.push_back({expr, type, offset, addend, &sym}); - return 1; + return 0; } - // 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. // @@ -1177,14 +1199,14 @@ if (oneof( expr)) { // Local-Dynamic relocs can be relaxed to Local-Exec. - if (toExecRelax) { + if (toExecRelax(c)) { c.relocations.push_back( {target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE), type, offset, addend, &sym}); - return target->getTlsGdRelaxSkip(type); + return target->getTlsGdRelaxSkip(type) - 1; } if (expr == R_TLSLD_HINT) - return 1; + return 0; if (in.got->addTlsIndex()) { if (isLocalInExecutable) in.got->relocations.push_back( @@ -1194,33 +1216,14 @@ {target->tlsModuleIndexRel, in.got, in.got->getTlsIndexOff()}); } c.relocations.push_back({expr, type, offset, addend, &sym}); - return 1; + return 0; } - // 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(expr)) { - if (!toExecRelax) { + assert( + (oneof(expr))); + { + if (!toExecRelax(c)) { if (in.got->addDynTlsEntry(sym)) { uint64_t off = in.got->getGlobalDynOffset(sym); @@ -1243,7 +1246,7 @@ {R_ABS, target->tlsOffsetRel, offsetOff, 0, &sym}); } c.relocations.push_back({expr, type, offset, addend, &sym}); - return 1; + return 0; } // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec @@ -1262,27 +1265,7 @@ {target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_LE), type, offset, addend, &sym}); } - return target->getTlsGdRelaxSkip(type); - } - - if (oneof(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_TLS_GOT needs a relative relocation for PIC on i386 and Hexagon. - if (expr == R_TLS_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 target->getTlsGdRelaxSkip(type) - 1; } return 0; @@ -1317,131 +1300,22 @@ const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset; RelExpr expr = target->getRelExpr(type, sym, relocatedAddr); - // Ignore R_*_NONE and other marker relocations. - if (expr == R_NONE) - return; - // Read an addend. int64_t addend = computeAddend(rel, end, sec, expr, sym.isLocal()); - if (config->emachine == EM_PPC64) { - // We can separate the small code model relocations into 2 categories: - // 1) Those that access the compiler generated .toc sections. - // 2) Those that access the linker allocated got entries. - // lld allocates got entries to symbols on demand. Since we don't try to - // sort the got entries in any way, we don't have to track which objects - // 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 (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 - // InputSectionBase::relocateAlloc(). - if (type == R_PPC64_TOC16_LO && sym.isSection() && isa(sym) && - cast(sym).section->name == ".toc") - ppc64noTocRelax.insert({&sym, addend}); - - if ((type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) || - (type == R_PPC64_TLSLD && expr == R_TLSLD_HINT)) { - if (i == end) { - errorOrWarn("R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last " - "relocation" + - getLocation(sec, sym, offset)); - return; + if (sym.isGnuIFunc()) { + if (config->zIfuncNoplt) { + if (!sym.isPreemptible) { + if (expr == R_PPC32_PLTREL) + addend &= ~0x8000; + expr = fromPlt(expr); } - - // Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC case, - // so we can discern it later from the toc-case. - if (i->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC) - ++offset; - } - } - - // Relax relocations. - // - // If we know that a PLT entry will be resolved within the same ELF module, we - // can skip PLT access and directly jump to the destination function. For - // example, if we are linking a main executable, all dynamic symbols that can - // be resolved within the executable will actually be resolved that way at - // runtime, because the main executable is always at the beginning of a search - // list. We can leverage that fact. - if (!sym.isPreemptible && (!sym.isGnuIFunc() || config->zIfuncNoplt)) { - if (expr != R_GOT_PC) { - // The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call - // stub type. It should be ignored if optimized to R_PC. - if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL) - addend &= ~0x8000; - // R_HEX_GD_PLT_B22_PCREL (call a@GDPLT) is transformed into - // call __tls_get_addr even if the symbol is non-preemptible. - if (!(config->emachine == EM_HEXAGON && - (type == R_HEX_GD_PLT_B22_PCREL || - type == R_HEX_GD_PLT_B22_PCREL_X || - type == R_HEX_GD_PLT_B32_PCREL_X))) - expr = fromPlt(expr); - } else if (!isAbsoluteValue(sym)) { - expr = target->adjustGotPcExpr(type, addend, relocatedAddr); - } - } - - // 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 5 types that relative GOTPLT are all x86 and x86-64 specific. - if (oneof(expr)) { - in.gotPlt->hasGotPltOffRel = true; - } else if (oneof( - expr)) { - in.got->hasGotOffRel = true; - } - - // Process TLS relocations, including relaxing TLS relocations. Note that - // R_TPREL and R_TPREL_NEG relocations are resolved in processRelocAux. - if (expr == R_TPREL || expr == R_TPREL_NEG) { - if (config->shared) { - errorOrWarn("relocation " + toString(type) + " against " + toString(sym) + - " cannot be used with -shared" + - getLocation(sec, sym, offset)); + // TODO adjustGotPcExpr + sym.exportDynamic = true; + mainPart->relaDyn->addSymbolReloc(type, &sec, offset, sym, addend, type); return; } - } else if (unsigned processed = handleTlsRelocation( - type, sym, sec, offset, addend, expr)) { - i += (processed - 1); - return; - } - // We were asked not to generate PLT entries for ifuncs. Instead, pass the - // direct relocation on through. - if (sym.isGnuIFunc() && config->zIfuncNoplt) { - sym.exportDynamic = true; - 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); - } - } - } else { // Handle a reference to a non-preemptible ifunc. These are special in a // few ways: // @@ -1482,56 +1356,272 @@ // 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(cast(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(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. + if (!sym.isPreemptible) { + 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(cast(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. // - // 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); + // 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(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); + } } + processRelocAux(sec, expr, type, offset, sym, addend); + return; + } + } + +#define OPTIMIZE_PLT (!sym.isPreemptible && !sym.isGnuIFunc()) + + enum Action { RELOCATE, IGNORE, CUSTOM }; + Action action = RELOCATE; + switch (expr) { + case R_NONE: + action = IGNORE; + break; + + case R_ABS: + case R_SIZE: + case R_PC: + case R_AARCH64_PAGE_PC: + action = CUSTOM; + break; + + //*** GOT + case R_GOT_PC: + if (!sym.isPreemptible && !isAbsoluteValue(sym)) + expr = target->adjustGotPcExpr(type, addend, relocatedAddr); + if (expr != R_GOT_PC) + action = CUSTOM; + else if (!sym.isInGot()) + addGotEntry(sym); + break; + + case R_GOT: + if (!sym.isInGot()) + addGotEntry(sym); + action = CUSTOM; + break; + case R_GOT_OFF: + case R_GOTPLT: + case R_AARCH64_GOT_PAGE_PC: + case R_AARCH64_GOT_PAGE: + if (expr == R_GOTPLT) + in.gotPlt->hasGotPltOffRel = true; + if (!sym.isInGot()) + addGotEntry(sym); + break; + + case R_GOTONLY_PC: + in.got->hasGotOffRel = true; + break; + case R_PPC64_TOCBASE: + in.got->hasGotOffRel = true; + action = CUSTOM; + break; + case R_GOTREL: + if (config->emachine == EM_PPC64) { + // We can separate the small code model relocations into 2 categories: + // 1) Those that access the compiler generated .toc sections. + // 2) Those that access the linker allocated got entries. + // lld allocates got entries to symbols on demand. Since we don't try to + // sort the got entries in any way, we don't have to track which objects + // 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 (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 InputSectionBase::relocateAlloc(). + if (type == R_PPC64_TOC16_LO && sym.isSection() && isa(sym) && + cast(sym).section->name == ".toc") + ppc64noTocRelax.insert({&sym, addend}); } + in.got->hasGotOffRel = true; + break; + case R_PPC64_RELAX_TOC: + in.got->hasGotOffRel = true; + break; + + case R_MIPS_GOT_LOCAL_PAGE: + case R_MIPS_GOT_OFF: + case R_MIPS_GOT_OFF32: + // 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); + break; + + //*** .got.plt + case R_GOTPLTONLY_PC: + case R_GOTPLTREL: + in.gotPlt->hasGotPltOffRel = true; + break; + + //*** PLT + case R_PLT: + case R_PLT_PC: + case R_PLT_GOTPLT: + case R_PPC64_CALL_PLT: + if (expr == R_PLT_GOTPLT) + in.gotPlt->hasGotPltOffRel = true; + if (OPTIMIZE_PLT) { + if (config->emachine == EM_HEXAGON && + (type == R_HEX_GD_PLT_B22_PCREL || type == R_HEX_GD_PLT_B22_PCREL_X || + type == R_HEX_GD_PLT_B32_PCREL_X)) { + if (!sym.isInPlt()) + addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); + } else { + expr = fromPlt(expr); + action = CUSTOM; // TODO R_PC vs SHN_ABS + } + } else { + if (!sym.isInPlt()) + addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); + } + break; + case R_PPC32_PLTREL: + if (OPTIMIZE_PLT) { + expr = R_PC; + addend &= ~0x8000; + } else if (!sym.isInPlt()) { + addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym); + } + break; + + //*** TPREL + case R_TPREL: + case R_TPREL_NEG: + if (config->shared) { + errorOrWarn("relocation " + toString(type) + " against " + toString(sym) + + " cannot be used with -shared" + + getLocation(sec, sym, offset)); + return; + } + if (!sym.isDefined()) + action = CUSTOM; + break; + + //*** TLS (non-TPREL) + case R_TLSDESC: + case R_TLSDESC_PC: + case R_AARCH64_TLSDESC_PAGE: + case R_TLSGD_GOT: + case R_TLSGD_PC: + case R_TLSLD_GOT: + case R_TLSLD_GOTPLT: + case R_TLSLD_PC: + case R_MIPS_TLSGD: + case R_MIPS_TLSLD: + if (config->emachine == EM_MIPS) + handleMipsTlsRelocation(type, sym, sec, offset, addend, expr); + else + i += handleTlsRelocationNonIE(type, sym, sec, offset, addend, expr); + return; + case R_DTPREL: + if (toExecRelax(sec)) + expr = target->adjustTlsExpr(type, R_RELAX_TLS_LD_TO_LE); + sec.relocations.push_back({expr, type, offset, addend, &sym}); + return; + case R_TLSDESC_CALL: + case R_TLSLD_HINT: + if (config->emachine == EM_PPC64) { + if (i == end) { + errorOrWarn("R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last " + "relocation" + + getLocation(sec, sym, offset)); + return; + } + + // Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC case, + // so we can discern it later from the toc-case. + if (i->getType(false) == R_PPC64_REL24_NOTOC) + ++offset; + } + i += handleTlsRelocationNonIE(type, sym, sec, offset, addend, expr); + return; + + case R_TLSDESC_GOTPLT: + case R_TLSGD_GOTPLT: + in.gotPlt->hasGotPltOffRel = true; + i += handleTlsRelocationNonIE(type, sym, sec, offset, addend, expr); + return; + + case R_TLSLD_GOT_OFF: + // PPC64 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 (!sym.isInGot()) { + in.got->addEntry(sym); + uint64_t off = sym.getGotOffset(); + in.got->relocations.push_back( + {R_ABS, target->tlsOffsetRel, off, 0, &sym}); + } + break; + + case R_TLS_GOT: + case R_TLS_GOT_PC: + case R_TLS_GOT_GOTPLT: + case R_TLSIE_HINT: + case R_AARCH64_TLS_GOT_PAGE_PC: + case R_TLS_GOTOFF: { + if (expr == R_TLS_GOT_GOTPLT) + in.gotPlt->hasGotPltOffRel = true; + handleTlsIe(type, sym, sec, offset, addend, expr, + toExecRelax(sec) && !sym.isPreemptible); + return; + } + + default: + break; } - processRelocAux(sec, expr, type, offset, sym, addend); + if (action == RELOCATE) + sec.relocations.push_back({expr, type, offset, addend, &sym}); + else if (action != IGNORE) + processRelocAux(sec, expr, type, offset, sym, addend); } // R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for