Skip to content

Commit ea15b86

Browse files
committed
Revert D114783 [ELF] Split scanRelocations into scanRelocations/postScanRelocations
May cause a failure for non-preemptible `bcmp` in a glibc -static link.
1 parent 8bd106a commit ea15b86

28 files changed

+266
-304
lines changed

lld/ELF/Arch/AArch64.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,11 +690,11 @@ void AArch64BtiPac::writePlt(uint8_t *buf, const Symbol &sym,
690690
};
691691
const uint8_t nopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
692692

693-
// needsCopy indicates a non-ifunc canonical PLT entry whose address may
693+
// needsPltAddr indicates a non-ifunc canonical PLT entry whose address may
694694
// escape to shared objects. isInIplt indicates a non-preemptible ifunc. Its
695695
// address may escape if referenced by a direct relocation. The condition is
696696
// conservative.
697-
bool hasBti = btiHeader && (sym.needsCopy || sym.isInIplt);
697+
bool hasBti = btiHeader && (sym.needsPltAddr || sym.isInIplt);
698698
if (hasBti) {
699699
memcpy(buf, btiData, sizeof(btiData));
700700
buf += sizeof(btiData);

lld/ELF/MapFile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static std::vector<Defined *> getSymbols() {
5858
for (Symbol *b : file->getSymbols())
5959
if (auto *dr = dyn_cast<Defined>(b))
6060
if (!dr->isSection() && dr->section && dr->section->isLive() &&
61-
(dr->file == file || dr->needsCopy || dr->section->bss))
61+
(dr->file == file || dr->needsPltAddr || dr->section->bss))
6262
v.push_back(dr);
6363
return v;
6464
}

lld/ELF/Relocations.cpp

Lines changed: 124 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,6 @@ static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value,
307307
sym.verdefIndex = old.verdefIndex;
308308
sym.exportDynamic = true;
309309
sym.isUsedInRegularObj = true;
310-
// A copy relocated alias may need a GOT entry.
311-
sym.needsGot = old.needsGot;
312310
}
313311

314312
// Reserve space in .bss or .bss.rel.ro for copy relocation.
@@ -353,7 +351,7 @@ static void replaceWithDefined(Symbol &sym, SectionBase *sec, uint64_t value,
353351
// to the variable in .bss. This kind of issue is sometimes very hard to
354352
// debug. What's a solution? Instead of exporting a variable V from a DSO,
355353
// define an accessor getV().
356-
template <class ELFT> static void addCopyRelSymbolImpl(SharedSymbol &ss) {
354+
template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
357355
// Copy relocation against zero-sized symbol doesn't make sense.
358356
uint64_t symSize = ss.getSize();
359357
if (symSize == 0 || ss.alignment == 0)
@@ -384,26 +382,6 @@ template <class ELFT> static void addCopyRelSymbolImpl(SharedSymbol &ss) {
384382
mainPart->relaDyn->addSymbolReloc(target->copyRel, sec, 0, ss);
385383
}
386384

387-
static void addCopyRelSymbol(SharedSymbol &ss) {
388-
const SharedFile &file = ss.getFile();
389-
switch (file.ekind) {
390-
case ELF32LEKind:
391-
addCopyRelSymbolImpl<ELF32LE>(ss);
392-
break;
393-
case ELF32BEKind:
394-
addCopyRelSymbolImpl<ELF32BE>(ss);
395-
break;
396-
case ELF64LEKind:
397-
addCopyRelSymbolImpl<ELF64LE>(ss);
398-
break;
399-
case ELF64BEKind:
400-
addCopyRelSymbolImpl<ELF64BE>(ss);
401-
break;
402-
default:
403-
llvm_unreachable("");
404-
}
405-
}
406-
407385
// MIPS has an odd notion of "paired" relocations to calculate addends.
408386
// For example, if a relocation is of R_MIPS_HI16, there must be a
409387
// R_MIPS_LO16 relocation after that, and an addend is calculated using
@@ -1067,7 +1045,7 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
10671045
" against symbol '" + toString(*ss) +
10681046
"'; recompile with -fPIC or remove '-z nocopyreloc'" +
10691047
getLocation(sec, sym, offset));
1070-
sym.needsCopy = true;
1048+
addCopyRelSymbol<ELFT>(*ss);
10711049
}
10721050
sec.relocations.push_back({expr, type, offset, addend, &sym});
10731051
return;
@@ -1105,8 +1083,20 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
11051083
errorOrWarn("symbol '" + toString(sym) +
11061084
"' cannot be preempted; recompile with -fPIE" +
11071085
getLocation(sec, sym, offset));
1108-
sym.needsCopy = true;
1109-
sym.needsPlt = true;
1086+
if (!sym.isInPlt())
1087+
addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
1088+
if (!sym.isDefined()) {
1089+
replaceWithDefined(
1090+
sym, in.plt,
1091+
target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
1092+
if (config->emachine == EM_PPC) {
1093+
// PPC32 canonical PLT entries are at the beginning of .glink
1094+
cast<Defined>(sym).value = in.plt->headerSize;
1095+
in.plt->headerSize += 16;
1096+
cast<PPC32GlinkSection>(in.plt)->canonical_plts.push_back(&sym);
1097+
}
1098+
}
1099+
sym.needsPltAddr = true;
11101100
sec.relocations.push_back({expr, type, offset, addend, &sym});
11111101
return;
11121102
}
@@ -1435,23 +1425,116 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
14351425
return;
14361426
}
14371427

1438-
if (needsGot(expr)) {
1439-
if (config->emachine == EM_MIPS) {
1440-
// MIPS ABI has special rules to process GOT entries and doesn't
1441-
// require relocation entries for them. A special case is TLS
1442-
// relocations. In that case dynamic loader applies dynamic
1443-
// relocations to initialize TLS GOT entries.
1444-
// See "Global Offset Table" in Chapter 5 in the following document
1445-
// for detailed description:
1446-
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
1447-
in.mipsGot->addEntry(*sec.file, sym, addend, expr);
1448-
} else {
1449-
sym.needsGot = true;
1428+
// Non-preemptible ifuncs require special handling. First, handle the usual
1429+
// case where the symbol isn't one of these.
1430+
if (!sym.isGnuIFunc() || sym.isPreemptible) {
1431+
// If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
1432+
if (needsPlt(expr) && !sym.isInPlt())
1433+
addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
1434+
1435+
// Create a GOT slot if a relocation needs GOT.
1436+
if (needsGot(expr)) {
1437+
if (config->emachine == EM_MIPS) {
1438+
// MIPS ABI has special rules to process GOT entries and doesn't
1439+
// require relocation entries for them. A special case is TLS
1440+
// relocations. In that case dynamic loader applies dynamic
1441+
// relocations to initialize TLS GOT entries.
1442+
// See "Global Offset Table" in Chapter 5 in the following document
1443+
// for detailed description:
1444+
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
1445+
in.mipsGot->addEntry(*sec.file, sym, addend, expr);
1446+
} else if (!sym.isInGot()) {
1447+
addGotEntry(sym);
1448+
}
14501449
}
1451-
} else if (needsPlt(expr)) {
1452-
sym.needsPlt = true;
14531450
} else {
1454-
sym.hasDirectReloc = true;
1451+
// Handle a reference to a non-preemptible ifunc. These are special in a
1452+
// few ways:
1453+
//
1454+
// - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
1455+
// a fixed value. But assuming that all references to the ifunc are
1456+
// GOT-generating or PLT-generating, the handling of an ifunc is
1457+
// relatively straightforward. We create a PLT entry in Iplt, which is
1458+
// usually at the end of .plt, which makes an indirect call using a
1459+
// matching GOT entry in igotPlt, which is usually at the end of .got.plt.
1460+
// The GOT entry is relocated using an IRELATIVE relocation in relaIplt,
1461+
// which is usually at the end of .rela.plt. Unlike most relocations in
1462+
// .rela.plt, which may be evaluated lazily without -z now, dynamic
1463+
// loaders evaluate IRELATIVE relocs eagerly, which means that for
1464+
// IRELATIVE relocs only, GOT-generating relocations can point directly to
1465+
// .got.plt without requiring a separate GOT entry.
1466+
//
1467+
// - Despite the fact that an ifunc does not have a fixed value, compilers
1468+
// that are not passed -fPIC will assume that they do, and will emit
1469+
// direct (non-GOT-generating, non-PLT-generating) relocations to the
1470+
// symbol. This means that if a direct relocation to the symbol is
1471+
// seen, the linker must set a value for the symbol, and this value must
1472+
// be consistent no matter what type of reference is made to the symbol.
1473+
// This can be done by creating a PLT entry for the symbol in the way
1474+
// described above and making it canonical, that is, making all references
1475+
// point to the PLT entry instead of the resolver. In lld we also store
1476+
// the address of the PLT entry in the dynamic symbol table, which means
1477+
// that the symbol will also have the same value in other modules.
1478+
// Because the value loaded from the GOT needs to be consistent with
1479+
// the value computed using a direct relocation, a non-preemptible ifunc
1480+
// may end up with two GOT entries, one in .got.plt that points to the
1481+
// address returned by the resolver and is used only by the PLT entry,
1482+
// and another in .got that points to the PLT entry and is used by
1483+
// GOT-generating relocations.
1484+
//
1485+
// - The fact that these symbols do not have a fixed value makes them an
1486+
// exception to the general rule that a statically linked executable does
1487+
// not require any form of dynamic relocation. To handle these relocations
1488+
// correctly, the IRELATIVE relocations are stored in an array which a
1489+
// statically linked executable's startup code must enumerate using the
1490+
// linker-defined symbols __rela?_iplt_{start,end}.
1491+
if (!sym.isInPlt()) {
1492+
// Create PLT and GOTPLT slots for the symbol.
1493+
sym.isInIplt = true;
1494+
1495+
// Create a copy of the symbol to use as the target of the IRELATIVE
1496+
// relocation in the igotPlt. This is in case we make the PLT canonical
1497+
// later, which would overwrite the original symbol.
1498+
//
1499+
// FIXME: Creating a copy of the symbol here is a bit of a hack. All
1500+
// that's really needed to create the IRELATIVE is the section and value,
1501+
// so ideally we should just need to copy those.
1502+
auto *directSym = make<Defined>(cast<Defined>(sym));
1503+
addPltEntry(in.iplt, in.igotPlt, in.relaIplt, target->iRelativeRel,
1504+
*directSym);
1505+
sym.pltIndex = directSym->pltIndex;
1506+
}
1507+
if (needsGot(expr)) {
1508+
// Redirect GOT accesses to point to the Igot.
1509+
//
1510+
// This field is also used to keep track of whether we ever needed a GOT
1511+
// entry. If we did and we make the PLT canonical later, we'll need to
1512+
// create a GOT entry pointing to the PLT entry for Sym.
1513+
sym.gotInIgot = true;
1514+
} else if (!needsPlt(expr)) {
1515+
// Make the ifunc's PLT entry canonical by changing the value of its
1516+
// symbol to redirect all references to point to it.
1517+
auto &d = cast<Defined>(sym);
1518+
d.section = in.iplt;
1519+
d.value = sym.pltIndex * target->ipltEntrySize;
1520+
d.size = 0;
1521+
// It's important to set the symbol type here so that dynamic loaders
1522+
// don't try to call the PLT as if it were an ifunc resolver.
1523+
d.type = STT_FUNC;
1524+
1525+
if (sym.gotInIgot) {
1526+
// We previously encountered a GOT generating reference that we
1527+
// redirected to the Igot. Now that the PLT entry is canonical we must
1528+
// clear the redirection to the Igot and add a GOT entry. As we've
1529+
// changed the symbol type to STT_FUNC future GOT generating references
1530+
// will naturally use this GOT entry.
1531+
//
1532+
// We don't need to worry about creating a MIPS GOT here because ifuncs
1533+
// aren't a thing on MIPS.
1534+
sym.gotInIgot = false;
1535+
addGotEntry(sym);
1536+
}
1537+
}
14551538
}
14561539

14571540
processRelocAux<ELFT>(sec, expr, type, offset, sym, addend);
@@ -1532,121 +1615,6 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
15321615
scanRelocs<ELFT>(s, rels.relas);
15331616
}
15341617

1535-
static bool handleNonPreemptibleIfunc(Symbol &sym) {
1536-
// Handle a reference to a non-preemptible ifunc. These are special in a
1537-
// few ways:
1538-
//
1539-
// - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
1540-
// a fixed value. But assuming that all references to the ifunc are
1541-
// GOT-generating or PLT-generating, the handling of an ifunc is
1542-
// relatively straightforward. We create a PLT entry in Iplt, which is
1543-
// usually at the end of .plt, which makes an indirect call using a
1544-
// matching GOT entry in igotPlt, which is usually at the end of .got.plt.
1545-
// The GOT entry is relocated using an IRELATIVE relocation in relaIplt,
1546-
// which is usually at the end of .rela.plt. Unlike most relocations in
1547-
// .rela.plt, which may be evaluated lazily without -z now, dynamic
1548-
// loaders evaluate IRELATIVE relocs eagerly, which means that for
1549-
// IRELATIVE relocs only, GOT-generating relocations can point directly to
1550-
// .got.plt without requiring a separate GOT entry.
1551-
//
1552-
// - Despite the fact that an ifunc does not have a fixed value, compilers
1553-
// that are not passed -fPIC will assume that they do, and will emit
1554-
// direct (non-GOT-generating, non-PLT-generating) relocations to the
1555-
// symbol. This means that if a direct relocation to the symbol is
1556-
// seen, the linker must set a value for the symbol, and this value must
1557-
// be consistent no matter what type of reference is made to the symbol.
1558-
// This can be done by creating a PLT entry for the symbol in the way
1559-
// described above and making it canonical, that is, making all references
1560-
// point to the PLT entry instead of the resolver. In lld we also store
1561-
// the address of the PLT entry in the dynamic symbol table, which means
1562-
// that the symbol will also have the same value in other modules.
1563-
// Because the value loaded from the GOT needs to be consistent with
1564-
// the value computed using a direct relocation, a non-preemptible ifunc
1565-
// may end up with two GOT entries, one in .got.plt that points to the
1566-
// address returned by the resolver and is used only by the PLT entry,
1567-
// and another in .got that points to the PLT entry and is used by
1568-
// GOT-generating relocations.
1569-
//
1570-
// - The fact that these symbols do not have a fixed value makes them an
1571-
// exception to the general rule that a statically linked executable does
1572-
// not require any form of dynamic relocation. To handle these relocations
1573-
// correctly, the IRELATIVE relocations are stored in an array which a
1574-
// statically linked executable's startup code must enumerate using the
1575-
// linker-defined symbols __rela?_iplt_{start,end}.
1576-
if (!sym.isGnuIFunc() || sym.isPreemptible || config->zIfuncNoplt)
1577-
return false;
1578-
1579-
sym.isInIplt = true;
1580-
1581-
// Create an Iplt and the associated IRELATIVE relocation pointing to the
1582-
// original section/value pairs. For non-GOT non-PLT relocation case below, we
1583-
// may alter section/value, so create a copy of the symbol to make
1584-
// section/value fixed.
1585-
auto *directSym = make<Defined>(cast<Defined>(sym));
1586-
addPltEntry(in.iplt, in.igotPlt, in.relaIplt, target->iRelativeRel,
1587-
*directSym);
1588-
sym.pltIndex = directSym->pltIndex;
1589-
1590-
if (sym.hasDirectReloc) {
1591-
// Change the value to the IPLT and redirect all references to it.
1592-
auto &d = cast<Defined>(sym);
1593-
d.section = in.iplt;
1594-
d.value = sym.pltIndex * target->ipltEntrySize;
1595-
d.size = 0;
1596-
// It's important to set the symbol type here so that dynamic loaders
1597-
// don't try to call the PLT as if it were an ifunc resolver.
1598-
d.type = STT_FUNC;
1599-
1600-
if (sym.needsGot)
1601-
addGotEntry(sym);
1602-
} else if (sym.needsGot) {
1603-
// Redirect GOT accesses to point to the Igot.
1604-
sym.gotInIgot = true;
1605-
}
1606-
return true;
1607-
}
1608-
1609-
void elf::postScanRelocations() {
1610-
auto fn = [](Symbol &sym) {
1611-
if (handleNonPreemptibleIfunc(sym))
1612-
return;
1613-
if (sym.needsGot)
1614-
addGotEntry(sym);
1615-
if (sym.needsPlt)
1616-
addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel, sym);
1617-
if (sym.needsCopy) {
1618-
if (sym.isObject()) {
1619-
addCopyRelSymbol(cast<SharedSymbol>(sym));
1620-
// needsCopy is cleared for sym and its aliases so that in later
1621-
// iterations aliases won't cause redundant copies.
1622-
assert(!sym.needsCopy);
1623-
} else {
1624-
assert(sym.isFunc() && sym.needsPlt);
1625-
if (!sym.isDefined()) {
1626-
replaceWithDefined(
1627-
sym, in.plt,
1628-
target->pltHeaderSize + target->pltEntrySize * sym.pltIndex, 0);
1629-
sym.needsCopy = true;
1630-
if (config->emachine == EM_PPC) {
1631-
// PPC32 canonical PLT entries are at the beginning of .glink
1632-
cast<Defined>(sym).value = in.plt->headerSize;
1633-
in.plt->headerSize += 16;
1634-
cast<PPC32GlinkSection>(in.plt)->canonical_plts.push_back(&sym);
1635-
}
1636-
}
1637-
}
1638-
}
1639-
};
1640-
for (Symbol *sym : symtab->symbols())
1641-
fn(*sym);
1642-
1643-
// Local symbols may need the aforementioned non-preemptible ifunc and GOT
1644-
// handling. They don't need regular PLT.
1645-
for (InputFile *file : objectFiles)
1646-
for (Symbol *sym : cast<ELFFileBase>(file)->getLocalSymbols())
1647-
fn(*sym);
1648-
}
1649-
16501618
static bool mergeCmp(const InputSection *a, const InputSection *b) {
16511619
// std::merge requires a strict weak ordering.
16521620
if (a->outSecOff < b->outSecOff)

lld/ELF/Relocations.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ struct JumpInstrMod {
126126
// Call reportUndefinedSymbols() after calling scanRelocations() to emit
127127
// the diagnostics.
128128
template <class ELFT> void scanRelocations(InputSectionBase &);
129-
void postScanRelocations();
130129

131130
template <class ELFT> void reportUndefinedSymbols();
132131

lld/ELF/Symbols.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ static uint64_t getSymVA(const Symbol &sym, int64_t addend) {
120120
// field etc) do the same trick as compiler uses to mark microMIPS
121121
// for CPU - set the less-significant bit.
122122
if (config->emachine == EM_MIPS && isMicroMips() &&
123-
((sym.stOther & STO_MIPS_MICROMIPS) || sym.needsCopy))
123+
((sym.stOther & STO_MIPS_MICROMIPS) || sym.needsPltAddr))
124124
va |= 1;
125125

126126
if (d.isTls() && !config->relocatable) {

0 commit comments

Comments
 (0)