aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools')
-rw-r--r--contrib/llvm/tools/lld/ELF/Config.h2
-rw-r--r--contrib/llvm/tools/lld/ELF/Driver.cpp8
-rw-r--r--contrib/llvm/tools/lld/ELF/InputSection.cpp6
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.cpp264
-rw-r--r--contrib/llvm/tools/lld/ELF/Relocations.h10
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.cpp10
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.h10
-rw-r--r--contrib/llvm/tools/lld/ELF/SyntheticSections.cpp5
-rw-r--r--contrib/llvm/tools/lld/ELF/Writer.cpp10
9 files changed, 215 insertions, 110 deletions
diff --git a/contrib/llvm/tools/lld/ELF/Config.h b/contrib/llvm/tools/lld/ELF/Config.h
index e8bb6bf70ee0..096396ee4b82 100644
--- a/contrib/llvm/tools/lld/ELF/Config.h
+++ b/contrib/llvm/tools/lld/ELF/Config.h
@@ -191,7 +191,7 @@ struct Configuration {
bool ZExecstack;
bool ZGlobal;
bool ZHazardplt;
- bool ZIfuncnoplt;
+ bool ZIfuncNoplt;
bool ZInitfirst;
bool ZInterpose;
bool ZKeepTextSectionPrefix;
diff --git a/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp
index 3e565bcb8732..fcf304f1814f 100644
--- a/contrib/llvm/tools/lld/ELF/Driver.cpp
+++ b/contrib/llvm/tools/lld/ELF/Driver.cpp
@@ -299,6 +299,9 @@ static void checkOptions() {
if (!Config->Relocatable && !Config->DefineCommon)
error("-no-define-common not supported in non relocatable output");
+ if (Config->ZText && Config->ZIfuncNoplt)
+ error("-z text and -z ifunc-noplt may not be used together");
+
if (Config->Relocatable) {
if (Config->Shared)
error("-r and -shared may not be used together");
@@ -348,8 +351,7 @@ static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
static bool isKnownZFlag(StringRef S) {
return S == "combreloc" || S == "copyreloc" || S == "defs" ||
S == "execstack" || S == "global" || S == "hazardplt" ||
- S == "ifunc-noplt" ||
- S == "initfirst" || S == "interpose" ||
+ S == "ifunc-noplt" || S == "initfirst" || S == "interpose" ||
S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" ||
S == "nodelete" || S == "nodlopen" || S == "noexecstack" ||
@@ -875,7 +877,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
Config->ZGlobal = hasZOption(Args, "global");
Config->ZHazardplt = hasZOption(Args, "hazardplt");
- Config->ZIfuncnoplt = hasZOption(Args, "ifunc-noplt");
+ Config->ZIfuncNoplt = hasZOption(Args, "ifunc-noplt");
Config->ZInitfirst = hasZOption(Args, "initfirst");
Config->ZInterpose = hasZOption(Args, "interpose");
Config->ZKeepTextSectionPrefix = getZFlag(
diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp
index ca2f49c07bb7..2dcf48b5758c 100644
--- a/contrib/llvm/tools/lld/ELF/InputSection.cpp
+++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp
@@ -610,7 +610,6 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
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:
@@ -629,7 +628,6 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
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:
@@ -679,10 +677,6 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A);
return getAArch64Page(Val) - getAArch64Page(P);
}
- case R_AARCH64_PLT_PAGE_PC: {
- uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getPltVA() + A;
- return getAArch64Page(Val) - getAArch64Page(P);
- }
case R_RISCV_PC_INDIRECT: {
if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A))
return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(),
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.cpp b/contrib/llvm/tools/lld/ELF/Relocations.cpp
index 1aa58d4356bf..dcb75c3edc7b 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.cpp
+++ b/contrib/llvm/tools/lld/ELF/Relocations.cpp
@@ -337,8 +337,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {
// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC,
- R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
@@ -347,8 +346,7 @@ static bool needsPlt(RelExpr Expr) {
static bool needsGot(RelExpr Expr) {
return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
- R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END,
- R_GOT_PLT>(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
@@ -356,7 +354,7 @@ static bool needsGot(RelExpr Expr) {
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC,
- R_AARCH64_PLT_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+ R_RELAX_GOT_PC>(Expr);
}
// Returns true if a given relocation can be computed at link-time.
@@ -374,20 +372,16 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, 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_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC,
- R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
+ R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+ R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT,
R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT,
R_TLSLD_HINT, R_TLSIE_HINT>(E))
return true;
- // The computation involves output from the ifunc resolver.
- if (Sym.isGnuIFunc() && Config->ZIfuncnoplt)
- return false;
-
// 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)
@@ -433,14 +427,8 @@ static RelExpr toPlt(RelExpr Expr) {
return R_PPC_CALL_PLT;
case R_PC:
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;
}
@@ -772,14 +760,7 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
template <class ELFT> 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,
@@ -848,10 +829,6 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return;
}
- if (Sym.isGnuIFunc() && Config->ZIfuncnoplt) {
- In.RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
- return;
- }
bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
if (CanWrite) {
// R_GOT refers to a position in the got, even if the symbol is preemptible.
@@ -978,6 +955,15 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
getLocation(Sec, Sym, Offset));
}
+struct IRelativeReloc {
+ RelType Type;
+ InputSectionBase *Sec;
+ uint64_t Offset;
+ Symbol *Sym;
+};
+
+static std::vector<IRelativeReloc> IRelativeRelocs;
+
template <class ELFT, class RelTy>
static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
RelTy *End) {
@@ -1009,32 +995,29 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
return;
- // Strenghten or relax relocations.
- //
- // GNU ifunc symbols must be accessed via PLT because their addresses
- // are determined by runtime.
+ if (Sym.isGnuIFunc() && !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));
+ }
+
+ // Relax relocations.
//
- // On the other hand, 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 exectuable,
- // 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() && !Config->ZIfuncnoplt) {
- 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 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 exectuable, 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.IsPreemptible && (!Sym.isGnuIFunc() || Config->ZIfuncNoplt)) {
+ 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
@@ -1054,28 +1037,144 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
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)
- addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel,
- Sym);
- else
- addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
+ // 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;
+ In.RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
+ return;
}
- // 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<ELFT>(Sym);
+ // 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<ELFT>(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<ELFT>(Sym);
+ }
+ }
+ } 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}.
+ //
+ // - An absolute relocation to a non-preemptible ifunc (such as a global
+ // variable containing a pointer to the ifunc) needs to be relocated in
+ // the exact same way as a GOT entry, so we can avoid needing to make the
+ // PLT entry canonical by translating such relocations into IRELATIVE
+ // relocations in the RelaIplt.
+ 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<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel,
+ *DirectSym);
+ Sym.PltIndex = DirectSym->PltIndex;
+ }
+ if (Expr == R_ABS && Addend == 0 && (Sec.Flags & SHF_WRITE)) {
+ // We might be able to represent this as an IRELATIVE. But we don't know
+ // yet whether some later relocation will make the symbol point to a
+ // canonical PLT, which would make this either a dynamic RELATIVE (PIC) or
+ // static (non-PIC) relocation. So we keep a record of the information
+ // required to process the relocation, and after scanRelocs() has been
+ // called on all relocations, the relocation is resolved by
+ // addIRelativeRelocs().
+ IRelativeRelocs.push_back({Type, &Sec, Offset, &Sym});
+ return;
+ }
+ 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.
+ unsigned EntryOffset = Sym.PltIndex * Target->PltEntrySize;
+ if (Config->ZRetpolineplt)
+ EntryOffset += Target->PltHeaderSize;
+
+ auto &D = cast<Defined>(Sym);
+ D.Section = In.Iplt;
+ D.Value = EntryOffset;
+ 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<ELFT>(Sym);
+ }
}
}
@@ -1105,6 +1204,21 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
scanRelocs<ELFT>(S, S.rels<ELFT>());
}
+// Figure out which representation to use for any absolute relocs to
+// non-preemptible ifuncs that we visited during scanRelocs().
+void elf::addIRelativeRelocs() {
+ for (IRelativeReloc &R : IRelativeRelocs) {
+ if (R.Sym->Type == STT_GNU_IFUNC)
+ In.RelaIplt->addReloc(
+ {Target->IRelativeRel, R.Sec, R.Offset, true, R.Sym, 0});
+ else if (Config->Pic)
+ addRelativeReloc(R.Sec, R.Offset, R.Sym, 0, R_ABS, R.Type);
+ else
+ R.Sec->Relocations.push_back({R_ABS, R.Type, R.Offset, 0, R.Sym});
+ }
+ IRelativeRelocs.clear();
+}
+
static bool mergeCmp(const InputSection *A, const InputSection *B) {
// std::merge requires a strict weak ordering.
if (A->OutSecOff < B->OutSecOff)
diff --git a/contrib/llvm/tools/lld/ELF/Relocations.h b/contrib/llvm/tools/lld/ELF/Relocations.h
index d00e68bd36e6..6b5d607fbeff 100644
--- a/contrib/llvm/tools/lld/ELF/Relocations.h
+++ b/contrib/llvm/tools/lld/ELF/Relocations.h
@@ -34,19 +34,11 @@ enum RelExpr {
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,
@@ -155,6 +147,8 @@ struct RelocationOffsetComparator {
template <class ELFT> void scanRelocations(InputSectionBase &);
+void addIRelativeRelocs();
+
class ThunkSection;
class Thunk;
struct InputSectionDescription;
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.cpp b/contrib/llvm/tools/lld/ELF/Symbols.cpp
index a713ec539d82..8956496e7e0f 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.cpp
+++ b/contrib/llvm/tools/lld/ELF/Symbols.cpp
@@ -121,20 +121,24 @@ uint64_t Symbol::getVA(int64_t Addend) const {
return OutVA + Addend;
}
-uint64_t Symbol::getGotVA() const { return In.Got->getVA() + getGotOffset(); }
+uint64_t Symbol::getGotVA() const {
+ if (GotInIgot)
+ return In.IgotPlt->getVA() + getGotPltOffset();
+ return In.Got->getVA() + getGotOffset();
+}
uint64_t Symbol::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
}
uint64_t Symbol::getGotPltVA() const {
- if (this->IsInIgot)
+ if (IsInIplt)
return In.IgotPlt->getVA() + getGotPltOffset();
return In.GotPlt->getVA() + getGotPltOffset();
}
uint64_t Symbol::getGotPltOffset() const {
- if (IsInIgot)
+ if (IsInIplt)
return PltIndex * Target->GotPltEntrySize;
return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
}
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.h b/contrib/llvm/tools/lld/ELF/Symbols.h
index 4d55405d8936..dacba133ee8d 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.h
+++ b/contrib/llvm/tools/lld/ELF/Symbols.h
@@ -182,7 +182,7 @@ protected:
uint8_t StOther, uint8_t Type)
: File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
- IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+ IsInIplt(false), GotInIgot(false), IsPreemptible(false),
Used(!Config->GcSections), NeedsTocRestore(false),
ScriptDefined(false) {}
@@ -191,11 +191,13 @@ public:
// For SharedSymbol only.
unsigned NeedsPltAddr : 1;
- // True if this symbol is in the Iplt sub-section of the Plt.
+ // True if this symbol is in the Iplt sub-section of the Plt and the Igot
+ // sub-section of the .got.plt or .got.
unsigned IsInIplt : 1;
- // True if this symbol is in the Igot sub-section of the .got.plt or .got.
- unsigned IsInIgot : 1;
+ // True if this symbol needs a GOT entry and its GOT entry is actually in
+ // Igot. This will be true only for certain non-preemptible ifuncs.
+ unsigned GotInIgot : 1;
// True if this symbol is preemptible at load time.
unsigned IsPreemptible : 1;
diff --git a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
index 13344949b2a0..ac6703e72f34 100644
--- a/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
+++ b/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
@@ -1133,7 +1133,6 @@ IgotPltSection::IgotPltSection()
Target->GotPltEntrySize, getIgotPltName()) {}
void IgotPltSection::addEntry(Symbol &Sym) {
- Sym.IsInIgot = true;
assert(Sym.PltIndex == Entries.size());
Entries.push_back(&Sym);
}
@@ -2340,10 +2339,8 @@ void PltSection::writeTo(uint8_t *Buf) {
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
Sym.PltIndex = Entries.size();
RelocationBaseSection *PltRelocSection = In.RelaPlt;
- if (IsIplt) {
+ if (IsIplt)
PltRelocSection = In.RelaIplt;
- Sym.IsInIplt = true;
- }
unsigned RelOff =
static_cast<RelocationSection<ELFT> *>(PltRelocSection)->getRelocOffset();
Entries.push_back(std::make_pair(&Sym, RelOff));
diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp
index 75d9dcabb407..5c64bedb15ac 100644
--- a/contrib/llvm/tools/lld/ELF/Writer.cpp
+++ b/contrib/llvm/tools/lld/ELF/Writer.cpp
@@ -1656,18 +1656,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// earlier.
finalizeSynthetic(In.EhFrame);
- for (Symbol *S : Symtab->getSymbols()) {
- if (!S->IsPreemptible)
- S->IsPreemptible = computeIsPreemptible(*S);
- if (S->isGnuIFunc() && Config->ZIfuncnoplt)
- S->ExportDynamic = true;
- }
+ for (Symbol *S : Symtab->getSymbols())
+ S->IsPreemptible |= computeIsPreemptible(*S);
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
if (!Config->Relocatable)
forEachRelSec(scanRelocations<ELFT>);
+ addIRelativeRelocs();
+
if (In.Plt && !In.Plt->empty())
In.Plt->addSymbols();
if (In.Iplt && !In.Iplt->empty())