diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /lld/ELF/Arch/PPC.cpp | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'lld/ELF/Arch/PPC.cpp')
-rw-r--r-- | lld/ELF/Arch/PPC.cpp | 104 |
1 files changed, 60 insertions, 44 deletions
diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp index 3c0b0c290b58..a004cf74ddd8 100644 --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -17,9 +17,8 @@ using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; - -namespace lld { -namespace elf { +using namespace lld; +using namespace lld::elf; namespace { class PPC final : public TargetInfo { @@ -44,14 +43,19 @@ public: int64_t a) const override; uint32_t getThunkSectionSpacing() const override; bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; - void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, RelExpr expr) const override; int getTlsGdRelaxSkip(RelType type) const override; - void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; - void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; + void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; + void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; }; } // namespace @@ -66,7 +70,18 @@ static void writeFromHalf16(uint8_t *loc, uint32_t insn) { write32(config->isLE ? loc : loc - 2, insn); } -void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { +void elf::writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { + // Create canonical PLT entries for non-PIE code. Compilers don't generate + // non-GOT-non-PLT relocations referencing external functions for -fpie/-fPIE. + uint32_t glink = in.plt->getVA(); // VA of .glink + if (!config->isPic) { + for (const Symbol *sym : cast<PPC32GlinkSection>(in.plt)->canonical_plts) { + writePPC32PltCallStub(buf, sym->getGotPltVA(), nullptr, 0); + buf += 16; + glink += 16; + } + } + // On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an // absolute address from a specific .plt slot (usually called .got.plt on // other targets) and jumps there. @@ -85,15 +100,14 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { // computes the PLT index (by computing the distance from the landing b to // itself) and calls _dl_runtime_resolve() (in glibc). uint32_t got = in.got->getVA(); - uint32_t glink = in.plt->getVA(); // VA of .glink const uint8_t *end = buf + 64; if (config->isPic) { - uint32_t afterBcl = in.plt->getSize() - target->pltHeaderSize + 12; + uint32_t afterBcl = 4 * in.plt->getNumEntries() + 12; uint32_t gotBcl = got + 4 - (glink + afterBcl); write32(buf + 0, 0x3d6b0000 | ha(afterBcl)); // addis r11,r11,1f-glink@ha write32(buf + 4, 0x7c0802a6); // mflr r0 write32(buf + 8, 0x429f0005); // bcl 20,30,.+4 - write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-.glink@l + write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-glink@l write32(buf + 16, 0x7d8802a6); // mflr r12 write32(buf + 20, 0x7c0803a6); // mtlr r0 write32(buf + 24, 0x7d6c5850); // sub r11,r11,r12 @@ -113,16 +127,16 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { buf += 56; } else { write32(buf + 0, 0x3d800000 | ha(got + 4)); // lis r12,GOT+4@ha - write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-Glink@ha + write32(buf + 4, 0x3d6b0000 | ha(-glink)); // addis r11,r11,-glink@ha if (ha(got + 4) == ha(got + 8)) write32(buf + 8, 0x800c0000 | lo(got + 4)); // lwz r0,GOT+4@l(r12) else write32(buf + 8, 0x840c0000 | lo(got + 4)); // lwzu r0,GOT+4@l(r12) - write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-Glink@l + write32(buf + 12, 0x396b0000 | lo(-glink)); // addi r11,r11,-glink@l write32(buf + 16, 0x7c0903a6); // mtctr r0 write32(buf + 20, 0x7c0b5a14); // add r0,r11,r11 if (ha(got + 4) == ha(got + 8)) - write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@ha(r12) + write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@l(r12) else write32(buf + 24, 0x818c0000 | 4); // lwz r12,4(r12) write32(buf + 28, 0x7d605a14); // add r11,r0,r11 @@ -136,6 +150,7 @@ void writePPC32GlinkSection(uint8_t *buf, size_t numEntries) { } PPC::PPC() { + copyRel = R_PPC_COPY; gotRel = R_PPC_GLOB_DAT; noneRel = R_PPC_NONE; pltRel = R_PPC_JMP_SLOT; @@ -145,7 +160,7 @@ PPC::PPC() { gotBaseSymInGotPlt = false; gotHeaderEntriesNum = 3; gotPltHeaderEntriesNum = 0; - pltHeaderSize = 64; // size of PLTresolve in .glink + pltHeaderSize = 0; pltEntrySize = 4; ipltEntrySize = 16; @@ -177,25 +192,25 @@ void PPC::writeGotHeader(uint8_t *buf) const { void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const { // Address of the symbol resolver stub in .glink . - write32(buf, in.plt->getVA() + 4 * s.pltIndex); + write32(buf, in.plt->getVA() + in.plt->headerSize + 4 * s.pltIndex); } bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s, int64_t /*a*/) const { - if (type != R_PPC_REL24 && type != R_PPC_PLTREL24) + uint64_t branchAddr, const Symbol &s, int64_t a) const { + if (type != R_PPC_LOCAL24PC && type != R_PPC_REL24 && type != R_PPC_PLTREL24) return false; if (s.isInPlt()) return true; if (s.isUndefWeak()) return false; - return !(expr == R_PC && PPC::inBranchRange(type, branchAddr, s.getVA())); + return !PPC::inBranchRange(type, branchAddr, s.getVA(a)); } uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; } bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { uint64_t offset = dst - src; - if (type == R_PPC_REL24 || type == R_PPC_PLTREL24) + if (type == R_PPC_LOCAL24PC || type == R_PPC_REL24 || type == R_PPC_PLTREL24) return isInt<26>(offset); llvm_unreachable("unsupported relocation type used in branch"); } @@ -218,13 +233,13 @@ RelExpr PPC::getRelExpr(RelType type, const Symbol &s, return R_DTPREL; case R_PPC_REL14: case R_PPC_REL32: - case R_PPC_LOCAL24PC: case R_PPC_REL16_LO: case R_PPC_REL16_HI: case R_PPC_REL16_HA: return R_PC; case R_PPC_GOT16: return R_GOT_OFF; + case R_PPC_LOCAL24PC: case R_PPC_REL24: return R_PLT_PC; case R_PPC_PLTREL24: @@ -277,12 +292,12 @@ static std::pair<RelType, uint64_t> fromDTPREL(RelType type, uint64_t val) { } } -void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { +void PPC::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { RelType newType; - std::tie(newType, val) = fromDTPREL(type, val); + std::tie(newType, val) = fromDTPREL(rel.type, val); switch (newType) { case R_PPC_ADDR16: - checkIntUInt(loc, val, 16, type); + checkIntUInt(loc, val, 16, rel); write16(loc, val); break; case R_PPC_GOT16: @@ -290,7 +305,7 @@ void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_PPC_GOT_TLSLD16: case R_PPC_GOT_TPREL16: case R_PPC_TPREL16: - checkInt(loc, val, 16, type); + checkInt(loc, val, 16, rel); write16(loc, val); break; case R_PPC_ADDR16_HA: @@ -326,8 +341,8 @@ void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { break; case R_PPC_REL14: { uint32_t mask = 0x0000FFFC; - checkInt(loc, val, 16, type); - checkAlignment(loc, val, 4, type); + checkInt(loc, val, 16, rel); + checkAlignment(loc, val, 4, rel); write32(loc, (read32(loc) & ~mask) | (val & mask)); break; } @@ -335,8 +350,8 @@ void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { case R_PPC_LOCAL24PC: case R_PPC_PLTREL24: { uint32_t mask = 0x03FFFFFC; - checkInt(loc, val, 26, type); - checkAlignment(loc, val, 4, type); + checkInt(loc, val, 26, rel); + checkAlignment(loc, val, 4, rel); write32(loc, (read32(loc) & ~mask) | (val & mask)); break; } @@ -368,13 +383,14 @@ int PPC::getTlsGdRelaxSkip(RelType type) const { return 1; } -void PPC::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { case R_PPC_GOT_TLSGD16: { // addi rT, rA, x@got@tlsgd --> lwz rT, x@got@tprel(rA) uint32_t insn = readFromHalf16(loc); writeFromHalf16(loc, 0x80000000 | (insn & 0x03ff0000)); - relocateOne(loc, R_PPC_GOT_TPREL16, val); + relocateNoSym(loc, R_PPC_GOT_TPREL16, val); break; } case R_PPC_TLSGD: @@ -386,8 +402,9 @@ void PPC::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { } } -void PPC::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { case R_PPC_GOT_TLSGD16: // addi r3, r31, x@got@tlsgd --> addis r3, r2, x@tprel@ha writeFromHalf16(loc, 0x3c620000 | ha(val)); @@ -401,8 +418,9 @@ void PPC::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { } } -void PPC::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { case R_PPC_GOT_TLSLD16: // addi r3, rA, x@got@tlsgd --> addis r3, r2, 0 writeFromHalf16(loc, 0x3c620000); @@ -417,15 +435,16 @@ void PPC::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { case R_PPC_DTPREL16_HA: case R_PPC_DTPREL16_HI: case R_PPC_DTPREL16_LO: - relocateOne(loc, type, val); + relocate(loc, rel, val); break; default: llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); } } -void PPC::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { - switch (type) { +void PPC::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, + uint64_t val) const { + switch (rel.type) { case R_PPC_GOT_TPREL16: { // lwz rT, x@got@tprel(rA) --> addis rT, r2, x@tprel@ha uint32_t rt = readFromHalf16(loc) & 0x03e00000; @@ -448,10 +467,7 @@ void PPC::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { } } -TargetInfo *getPPCTargetInfo() { +TargetInfo *elf::getPPCTargetInfo() { static PPC target; return ⌖ } - -} // namespace elf -} // namespace lld |