Index: lld/ELF/InputSection.cpp =================================================================== --- lld/ELF/InputSection.cpp +++ lld/ELF/InputSection.cpp @@ -611,7 +611,6 @@ case R_ARM_SBREL: return Sym.getVA(A) - getARMStaticBase(Sym); case R_GOT: - case R_GOT_PLT: case R_RELAX_TLS_GD_TO_IE_ABS: return Sym.getGotVA() + A; case R_GOTONLY_PC: @@ -630,7 +629,6 @@ case R_RELAX_TLS_GD_TO_IE_GOT_OFF: return Sym.getGotOffset() + A; case R_AARCH64_GOT_PAGE_PC: - case R_AARCH64_GOT_PAGE_PC_PLT: case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC: return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P); case R_GOT_PC: Index: lld/ELF/Relocations.h =================================================================== --- lld/ELF/Relocations.h +++ lld/ELF/Relocations.h @@ -33,19 +33,12 @@ R_ABS, R_ADDEND, R_AARCH64_GOT_PAGE_PC, - // The expression is used for IFUNC support. Describes PC-relative - // address of the memory page of GOT entry. This entry is used for - // a redirection to IPLT. - R_AARCH64_GOT_PAGE_PC_PLT, R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC, R_AARCH64_PAGE_PC, R_AARCH64_PLT_PAGE_PC, R_AARCH64_TLSDESC_PAGE, R_ARM_SBREL, R_GOT, - // The expression is used for IFUNC support. Evaluates to GOT entry, - // containing redirection to the IPLT. - R_GOT_PLT, R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, Index: lld/ELF/Relocations.cpp =================================================================== --- lld/ELF/Relocations.cpp +++ lld/ELF/Relocations.cpp @@ -336,8 +336,8 @@ // Returns true if Expr refers a PLT entry. static bool needsPlt(RelExpr Expr) { - return isRelExprOneOf(Expr); + return isRelExprOneOf( + Expr); } // Returns true if Expr refers a GOT entry. Note that this function @@ -346,8 +346,7 @@ static bool needsGot(RelExpr Expr) { return isRelExprOneOf(Expr); + R_GOT_PC, R_GOT_FROM_END>(Expr); } // True if this expression is of the form Sym - X, where X is a position in the @@ -373,8 +372,8 @@ if (isRelExprOneOf(E)) @@ -382,7 +381,7 @@ // 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_GOT_PLT || E == R_PLT || E == R_TLSDESC) + if (E == R_GOT || E == R_PLT || E == R_TLSDESC) return Target->usesOnlyLowPageBits(Type) || !Config->Pic; if (Sym.IsPreemptible) @@ -430,12 +429,8 @@ return R_PLT_PC; case R_AARCH64_PAGE_PC: return R_AARCH64_PLT_PAGE_PC; - case R_AARCH64_GOT_PAGE_PC: - return R_AARCH64_GOT_PAGE_PC_PLT; case R_ABS: return R_PLT; - case R_GOT: - return R_GOT_PLT; default: return Expr; } @@ -767,14 +762,7 @@ template static void addGotEntry(Symbol &Sym) { In.Got->addEntry(Sym); - RelExpr Expr; - if (Sym.isTls()) - Expr = R_TLS; - else if (Sym.isGnuIFunc()) - Expr = R_PLT; - else - Expr = R_ABS; - + RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS; uint64_t Off = Sym.getGotOffset(); // If a GOT slot value can be calculated at link-time, which is now, @@ -1014,21 +1002,11 @@ // all dynamic symbols that can be resolved within the executable will // actually be resolved that way at runtime, because the main exectuable // is always at the beginning of a search list. We can leverage that fact. - if (Sym.isGnuIFunc()) { - if (!Config->ZText && Config->WarnIfuncTextrel) { - warn("using ifunc symbols when text relocations are allowed may produce " - "a binary that will segfault, if the object file is linked with " - "old version of glibc (glibc 2.28 and earlier). If this applies to " - "you, consider recompiling the object files without -fPIC and " - "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to " - "turn off this warning." + - getLocation(Sec, Sym, Offset)); - } - Expr = toPlt(Expr); - } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) { - Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); - } else if (!Sym.IsPreemptible) { - Expr = fromPlt(Expr); + if (!Sym.IsPreemptible && !Sym.isGnuIFunc()) { + if (Expr == R_GOT_PC && !isAbsoluteValue(Sym)) + Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); + else + Expr = fromPlt(Expr); } // This relocation does not require got entry, but it is relative to got and @@ -1048,28 +1026,61 @@ return; } - // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. - if (needsPlt(Expr) && !Sym.isInPlt()) { - if (Sym.isGnuIFunc() && !Sym.IsPreemptible) + if (Sym.isGnuIFunc() && !Sym.IsPreemptible) { + // Unlike GOT references to regular symbols, GOT references to + // non-preemptible ifuncs use .got.plt and not the regular GOT, even with -z + // now. This works because dynamic loaders evaluate IRELATIVE relocs + // eagerly. + if (!Sym.isInPlt()) { + // Create a copy of the symbol for the iplt in case we create a canonical + // plt 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, - Sym); - else + *DirectSym); + Sym.PltIndex = DirectSym->PltIndex; + Sym.IsInIplt = Sym.IsInIgot = true; + } + if (!needsPlt(Expr) && !needsGot(Expr)) { + // Create a canonical plt entry for the ifunc and redirect all references + // to point to it. + // + // FIXME: We don't always need the indirection here. Absolute non-PLT + // non-GOT relocations could be turned into an IRELATIVE. + unsigned EntryOffset = Sym.PltIndex * Target->PltEntrySize; + if (Config->ZRetpolineplt) + EntryOffset += Target->PltHeaderSize; + + Symbol Old = Sym; + replaceSymbol(&Sym, Sym.File, Sym.getName(), Sym.Binding, + Sym.StOther, STT_FUNC, EntryOffset, 0, In.Iplt); + Sym.PltIndex = Old.PltIndex; + Sym.GotIndex = Old.GotIndex; + Sym.VerdefIndex = Old.VerdefIndex; + Sym.PPC64BranchltIndex = Old.PPC64BranchltIndex; + } + } else { + // 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); + // 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); + } } } Index: lld/ELF/Symbols.cpp =================================================================== --- lld/ELF/Symbols.cpp +++ lld/ELF/Symbols.cpp @@ -120,7 +120,11 @@ return OutVA + Addend; } -uint64_t Symbol::getGotVA() const { return In.Got->getVA() + getGotOffset(); } +uint64_t Symbol::getGotVA() const { + if (GotIndex == -1u) + return getGotPltVA(); + return In.Got->getVA() + getGotOffset(); +} uint64_t Symbol::getGotOffset() const { return GotIndex * Target->GotEntrySize;