Skip to content

Commit 685b212

Browse files
committed
[ELF] Make relocateAlloc target specific. NFC
The target-specific code (AArch64, PPC64) does not fit into the generic code and adds virtual function overhead. Move relocateAlloc into ELF/Arch/ instead. This removes many virtual functions (relaxTls*). In addition, this helps get rid of getRelocTargetVA dispatch and many RelExpr members in the future.
1 parent 5b9597f commit 685b212

12 files changed

+322
-268
lines changed

lld/ELF/AArch64ErrataFix.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ void Patch843419Section::writeTo(uint8_t *buf) {
412412
write32le(buf, read32le(patchee->rawData.begin() + patcheeOffset));
413413

414414
// Apply any relocation transferred from the original patchee section.
415-
relocateAlloc(buf, buf + getSize());
415+
target->relocateAlloc(*this, buf);
416416

417417
// Return address is the next instruction after the one we have just copied.
418418
uint64_t s = getLDSTAddr() + 4;

lld/ELF/ARMErrataFix.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ void Patch657417Section::writeTo(uint8_t *buf) {
182182
write32le(buf, 0x9000f000);
183183
// If we have a relocation then apply it.
184184
if (!relocations.empty()) {
185-
relocateAlloc(buf, buf + getSize());
185+
target->relocateAlloc(*this, buf);
186186
return;
187187
}
188188

lld/ELF/Arch/AArch64.cpp

+64-16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "OutputSections.h"
910
#include "Symbols.h"
1011
#include "SyntheticSections.h"
1112
#include "Target.h"
@@ -48,12 +49,18 @@ class AArch64 : public TargetInfo {
4849
void relocate(uint8_t *loc, const Relocation &rel,
4950
uint64_t val) const override;
5051
RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
51-
void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
52-
uint64_t val) const override;
53-
void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
54-
uint64_t val) const override;
55-
void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
56-
uint64_t val) const override;
52+
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
53+
54+
private:
55+
void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
56+
void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
57+
void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
58+
void initRelaxer(ArrayRef<Relocation> relocs) const;
59+
bool tryRelaxAdrpAdd(const Relocation &adrpRel, const Relocation &addRel,
60+
uint64_t secAddr, uint8_t *buf) const;
61+
bool tryRelaxAdrpLdr(const Relocation &adrpRel, const Relocation &ldrRel,
62+
uint64_t secAddr, uint8_t *buf) const;
63+
mutable bool safeToRelaxAdrpLdr = false;
5764
};
5865
} // namespace
5966

@@ -587,11 +594,9 @@ void AArch64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
587594
llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
588595
}
589596

590-
AArch64Relaxer::AArch64Relaxer(ArrayRef<Relocation> relocs) {
591-
if (!config->relax || config->emachine != EM_AARCH64) {
592-
safeToRelaxAdrpLdr = false;
597+
void AArch64::initRelaxer(ArrayRef<Relocation> relocs) const {
598+
if (!config->relax)
593599
return;
594-
}
595600
// Check if R_AARCH64_ADR_GOT_PAGE and R_AARCH64_LD64_GOT_LO12_NC
596601
// always appear in pairs.
597602
size_t i = 0;
@@ -610,9 +615,9 @@ AArch64Relaxer::AArch64Relaxer(ArrayRef<Relocation> relocs) {
610615
safeToRelaxAdrpLdr = i == size;
611616
}
612617

613-
bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel,
614-
const Relocation &addRel, uint64_t secAddr,
615-
uint8_t *buf) const {
618+
bool AArch64::tryRelaxAdrpAdd(const Relocation &adrpRel,
619+
const Relocation &addRel, uint64_t secAddr,
620+
uint8_t *buf) const {
616621
// When the address of sym is within the range of ADR then
617622
// we may relax
618623
// ADRP xn, sym
@@ -659,9 +664,9 @@ bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel,
659664
return true;
660665
}
661666

662-
bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
663-
const Relocation &ldrRel, uint64_t secAddr,
664-
uint8_t *buf) const {
667+
bool AArch64::tryRelaxAdrpLdr(const Relocation &adrpRel,
668+
const Relocation &ldrRel, uint64_t secAddr,
669+
uint8_t *buf) const {
665670
if (!safeToRelaxAdrpLdr)
666671
return false;
667672

@@ -734,6 +739,49 @@ bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
734739
return true;
735740
}
736741

742+
void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
743+
uint64_t secAddr = sec.getOutputSection()->addr;
744+
if (auto *s = dyn_cast<InputSection>(&sec))
745+
secAddr += s->outSecOff;
746+
initRelaxer(sec.relocations);
747+
for (size_t i = 0, size = sec.relocations.size(); i != size; ++i) {
748+
const Relocation &rel = sec.relocations[i];
749+
uint8_t *loc = buf + rel.offset;
750+
const uint64_t val =
751+
sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
752+
secAddr + rel.offset, *rel.sym, rel.expr);
753+
switch (rel.expr) {
754+
case R_AARCH64_GOT_PAGE_PC:
755+
if (i + 1 < size &&
756+
tryRelaxAdrpLdr(rel, sec.relocations[i + 1], secAddr, buf)) {
757+
++i;
758+
continue;
759+
}
760+
break;
761+
case R_AARCH64_PAGE_PC:
762+
if (i + 1 < size &&
763+
tryRelaxAdrpAdd(rel, sec.relocations[i + 1], secAddr, buf)) {
764+
++i;
765+
continue;
766+
}
767+
break;
768+
case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
769+
case R_RELAX_TLS_GD_TO_IE_ABS:
770+
relaxTlsGdToIe(loc, rel, val);
771+
continue;
772+
case R_RELAX_TLS_GD_TO_LE:
773+
relaxTlsGdToLe(loc, rel, val);
774+
continue;
775+
case R_RELAX_TLS_IE_TO_LE:
776+
relaxTlsIeToLe(loc, rel, val);
777+
continue;
778+
default:
779+
break;
780+
}
781+
relocate(loc, rel, val);
782+
}
783+
}
784+
737785
// AArch64 may use security features in variant PLT sequences. These are:
738786
// Pointer Authentication (PAC), introduced in armv8.3-a and Branch Target
739787
// Indicator (BTI) introduced in armv8.5-a. The additional instructions used

lld/ELF/Arch/PPC.cpp

+37-8
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,13 @@ class PPC final : public TargetInfo {
5151
uint64_t val) const override;
5252
RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
5353
int getTlsGdRelaxSkip(RelType type) const override;
54-
void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
55-
uint64_t val) const override;
56-
void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
57-
uint64_t val) const override;
58-
void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel,
59-
uint64_t val) const override;
60-
void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
61-
uint64_t val) const override;
54+
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
55+
56+
private:
57+
void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
58+
void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
59+
void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
60+
void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
6261
};
6362
} // namespace
6463

@@ -483,6 +482,36 @@ void PPC::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
483482
}
484483
}
485484

485+
void PPC::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
486+
uint64_t secAddr = sec.getOutputSection()->addr;
487+
if (auto *s = dyn_cast<InputSection>(&sec))
488+
secAddr += s->outSecOff;
489+
for (const Relocation &rel : sec.relocations) {
490+
uint8_t *loc = buf + rel.offset;
491+
const uint64_t val = SignExtend64(
492+
sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
493+
secAddr + rel.offset, *rel.sym, rel.expr),
494+
32);
495+
switch (rel.expr) {
496+
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
497+
relaxTlsGdToIe(loc, rel, val);
498+
break;
499+
case R_RELAX_TLS_GD_TO_LE:
500+
relaxTlsGdToLe(loc, rel, val);
501+
break;
502+
case R_RELAX_TLS_LD_TO_LE_ABS:
503+
relaxTlsLdToLe(loc, rel, val);
504+
break;
505+
case R_RELAX_TLS_IE_TO_LE:
506+
relaxTlsIeToLe(loc, rel, val);
507+
break;
508+
default:
509+
relocate(loc, rel, val);
510+
break;
511+
}
512+
}
513+
}
514+
486515
TargetInfo *elf::getPPCTargetInfo() {
487516
static PPC target;
488517
return &target;

lld/ELF/Arch/PPC64.cpp

+94-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "InputFiles.h"
10+
#include "OutputSections.h"
1011
#include "SymbolTable.h"
1112
#include "Symbols.h"
1213
#include "SyntheticSections.h"
@@ -174,19 +175,17 @@ class PPC64 final : public TargetInfo {
174175
RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
175176
RelExpr adjustGotPcExpr(RelType type, int64_t addend,
176177
const uint8_t *loc) const override;
177-
void relaxGot(uint8_t *loc, const Relocation &rel,
178-
uint64_t val) const override;
179-
void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
180-
uint64_t val) const override;
181-
void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
182-
uint64_t val) const override;
183-
void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel,
184-
uint64_t val) const override;
185-
void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
186-
uint64_t val) const override;
178+
void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const;
179+
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
187180

188181
bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end,
189182
uint8_t stOther) const override;
183+
184+
private:
185+
void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
186+
void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
187+
void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
188+
void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const;
190189
};
191190
} // namespace
192191

@@ -362,7 +361,8 @@ getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) {
362361
// ld/lwa 3, 0(3) # load the value from the address
363362
//
364363
// Returns true if the relaxation is performed.
365-
bool elf::tryRelaxPPC64TocIndirection(const Relocation &rel, uint8_t *bufLoc) {
364+
static bool tryRelaxPPC64TocIndirection(const Relocation &rel,
365+
uint8_t *bufLoc) {
366366
assert(config->tocOptimize);
367367
if (rel.addend < 0)
368368
return false;
@@ -393,7 +393,8 @@ bool elf::tryRelaxPPC64TocIndirection(const Relocation &rel, uint8_t *bufLoc) {
393393
return false;
394394

395395
// Add PPC64TocOffset that will be subtracted by PPC64::relocate().
396-
target->relaxGot(bufLoc, rel, tocRelative + ppc64TocOffset);
396+
static_cast<const PPC64 &>(*target).relaxGot(bufLoc, rel,
397+
tocRelative + ppc64TocOffset);
397398
return true;
398399
}
399400

@@ -1512,6 +1513,87 @@ void PPC64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
15121513
}
15131514
}
15141515

1516+
void PPC64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
1517+
uint64_t secAddr = sec.getOutputSection()->addr;
1518+
if (auto *s = dyn_cast<InputSection>(&sec))
1519+
secAddr += s->outSecOff;
1520+
uint64_t lastPPCRelaxedRelocOff = -1;
1521+
for (const Relocation &rel : sec.relocations) {
1522+
uint8_t *loc = buf + rel.offset;
1523+
const uint64_t val =
1524+
sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
1525+
secAddr + rel.offset, *rel.sym, rel.expr);
1526+
switch (rel.expr) {
1527+
case R_PPC64_RELAX_GOT_PC: {
1528+
// The R_PPC64_PCREL_OPT relocation must appear immediately after
1529+
// R_PPC64_GOT_PCREL34 in the relocations table at the same offset.
1530+
// We can only relax R_PPC64_PCREL_OPT if we have also relaxed
1531+
// the associated R_PPC64_GOT_PCREL34 since only the latter has an
1532+
// associated symbol. So save the offset when relaxing R_PPC64_GOT_PCREL34
1533+
// and only relax the other if the saved offset matches.
1534+
if (rel.type == R_PPC64_GOT_PCREL34)
1535+
lastPPCRelaxedRelocOff = rel.offset;
1536+
if (rel.type == R_PPC64_PCREL_OPT && rel.offset != lastPPCRelaxedRelocOff)
1537+
break;
1538+
relaxGot(loc, rel, val);
1539+
break;
1540+
}
1541+
case R_PPC64_RELAX_TOC:
1542+
// rel.sym refers to the STT_SECTION symbol associated to the .toc input
1543+
// section. If an R_PPC64_TOC16_LO (.toc + addend) references the TOC
1544+
// entry, there may be R_PPC64_TOC16_HA not paired with
1545+
// R_PPC64_TOC16_LO_DS. Don't relax. This loses some relaxation
1546+
// opportunities but is safe.
1547+
if (ppc64noTocRelax.count({rel.sym, rel.addend}) ||
1548+
!tryRelaxPPC64TocIndirection(rel, loc))
1549+
relocate(loc, rel, val);
1550+
break;
1551+
case R_PPC64_CALL:
1552+
// If this is a call to __tls_get_addr, it may be part of a TLS
1553+
// sequence that has been relaxed and turned into a nop. In this
1554+
// case, we don't want to handle it as a call.
1555+
if (read32(loc) == 0x60000000) // nop
1556+
break;
1557+
1558+
// Patch a nop (0x60000000) to a ld.
1559+
if (rel.sym->needsTocRestore) {
1560+
// gcc/gfortran 5.4, 6.3 and earlier versions do not add nop for
1561+
// recursive calls even if the function is preemptible. This is not
1562+
// wrong in the common case where the function is not preempted at
1563+
// runtime. Just ignore.
1564+
if ((rel.offset + 8 > sec.rawData.size() ||
1565+
read32(loc + 4) != 0x60000000) &&
1566+
rel.sym->file != sec.file) {
1567+
// Use substr(6) to remove the "__plt_" prefix.
1568+
errorOrWarn(getErrorLocation(loc) + "call to " +
1569+
lld::toString(*rel.sym).substr(6) +
1570+
" lacks nop, can't restore toc");
1571+
break;
1572+
}
1573+
write32(loc + 4, 0xe8410018); // ld %r2, 24(%r1)
1574+
}
1575+
relocate(loc, rel, val);
1576+
break;
1577+
case R_RELAX_TLS_GD_TO_IE:
1578+
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
1579+
relaxTlsGdToIe(loc, rel, val);
1580+
break;
1581+
case R_RELAX_TLS_GD_TO_LE:
1582+
relaxTlsGdToLe(loc, rel, val);
1583+
break;
1584+
case R_RELAX_TLS_LD_TO_LE_ABS:
1585+
relaxTlsLdToLe(loc, rel, val);
1586+
break;
1587+
case R_RELAX_TLS_IE_TO_LE:
1588+
relaxTlsIeToLe(loc, rel, val);
1589+
break;
1590+
default:
1591+
relocate(loc, rel, val);
1592+
break;
1593+
}
1594+
}
1595+
}
1596+
15151597
// The prologue for a split-stack function is expected to look roughly
15161598
// like this:
15171599
// .Lglobal_entry_point:

0 commit comments

Comments
 (0)