diff options
Diffstat (limited to 'lld/ELF/Arch')
-rw-r--r-- | lld/ELF/Arch/Mips.cpp | 121 | ||||
-rw-r--r-- | lld/ELF/Arch/PPC64.cpp | 131 |
2 files changed, 252 insertions, 0 deletions
diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index f88b021c..091903b 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" +#include "RelocScan.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -31,6 +32,9 @@ public: void writePltHeader(uint8_t *buf) const override; void writePlt(uint8_t *buf, const Symbol &sym, uint64_t pltEntryAddr) const override; + template <class RelTy> + void scanSectionImpl(InputSectionBase &, Relocs<RelTy>); + void scanSection(InputSectionBase &) override; bool needsThunk(RelExpr expr, RelType type, const InputFile *file, uint64_t branchAddr, const Symbol &s, int64_t a) const override; @@ -570,6 +574,123 @@ static uint64_t fixupCrossModeJump(Ctx &ctx, uint8_t *loc, RelType type, return val; } +template <class RelTy> +static RelType getMipsN32RelType(Ctx &ctx, RelTy *&rel, RelTy *end) { + uint32_t type = 0; + uint64_t offset = rel->r_offset; + int n = 0; + while (rel != end && rel->r_offset == offset) + type |= (rel++)->getType(ctx.arg.isMips64EL) << (8 * n++); + return type; +} + +static RelType getMipsPairType(RelType type, bool isLocal) { + switch (type) { + case R_MIPS_HI16: + return R_MIPS_LO16; + case R_MIPS_GOT16: + // In case of global symbol, the R_MIPS_GOT16 relocation does not + // have a pair. Each global symbol has a unique entry in the GOT + // and a corresponding instruction with help of the R_MIPS_GOT16 + // relocation loads an address of the symbol. In case of local + // symbol, the R_MIPS_GOT16 relocation creates a GOT entry to hold + // the high 16 bits of the symbol's value. A paired R_MIPS_LO16 + // relocations handle low 16 bits of the address. That allows + // to allocate only one GOT entry for every 64 KiB of local data. + return isLocal ? R_MIPS_LO16 : R_MIPS_NONE; + case R_MICROMIPS_GOT16: + return isLocal ? R_MICROMIPS_LO16 : R_MIPS_NONE; + case R_MIPS_PCHI16: + return R_MIPS_PCLO16; + case R_MICROMIPS_HI16: + return R_MICROMIPS_LO16; + default: + return R_MIPS_NONE; + } +} + +template <class ELFT> +template <class RelTy> +void MIPS<ELFT>::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { + RelocScan rs(ctx, &sec); + sec.relocations.reserve(rels.size()); + RelType type; + for (auto it = rels.begin(); it != rels.end();) { + const RelTy &rel = *it; + uint64_t offset = rel.r_offset; + if constexpr (ELFT::Is64Bits) { + type = it->getType(ctx.arg.isMips64EL); + ++it; + } else { + if (ctx.arg.mipsN32Abi) { + type = getMipsN32RelType(ctx, it, rels.end()); + } else { + type = it->getType(ctx.arg.isMips64EL); + ++it; + } + } + + uint32_t symIdx = rel.getSymbol(ctx.arg.isMips64EL); + Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIdx); + RelExpr expr = + ctx.target->getRelExpr(type, sym, sec.content().data() + rel.r_offset); + if (expr == R_NONE) + continue; + if (sym.isUndefined() && symIdx != 0 && + rs.maybeReportUndefined(cast<Undefined>(sym), offset)) + continue; + + auto addend = rs.getAddend<ELFT>(rel, type); + if (expr == RE_MIPS_GOTREL && sym.isLocal()) { + addend += sec.getFile<ELFT>()->mipsGp0; + } else if (!RelTy::HasAddend) { + // MIPS has an odd notion of "paired" relocations to calculate addends. + // For example, if a relocation is of R_MIPS_HI16, there must be a + // R_MIPS_LO16 relocation after that, and an addend is calculated using + // the two relocations. + RelType pairTy = getMipsPairType(type, sym.isLocal()); + if (pairTy != R_MIPS_NONE) { + const uint8_t *buf = sec.content().data(); + // To make things worse, paired relocations might not be contiguous in + // the relocation table, so we need to do linear search. *sigh* + bool found = false; + for (auto *ri = &rel; ri != rels.end(); ++ri) { + if (ri->getType(ctx.arg.isMips64EL) == pairTy && + ri->getSymbol(ctx.arg.isMips64EL) == symIdx) { + addend += ctx.target->getImplicitAddend(buf + ri->r_offset, pairTy); + found = true; + break; + } + } + + if (!found) + Warn(ctx) << "can't find matching " << pairTy << " relocation for " + << type; + } + } + + if (expr == RE_MIPS_TLSLD) { + ctx.in.mipsGot->addTlsIndex(*sec.file); + sec.addReloc({expr, type, offset, addend, &sym}); + } else if (expr == RE_MIPS_TLSGD) { + ctx.in.mipsGot->addDynTlsEntry(*sec.file, sym); + sec.addReloc({expr, type, offset, addend, &sym}); + } else { + if (expr == R_TPREL && rs.checkTlsLe(offset, sym, type)) + continue; + rs.process(expr, type, offset, sym, addend); + } + } +} + +template <class ELFT> void MIPS<ELFT>::scanSection(InputSectionBase &sec) { + auto relocs = sec.template relsOrRelas<ELFT>(); + if (relocs.areRelocsRel()) + scanSectionImpl(sec, relocs.rels); + else + scanSectionImpl(sec, relocs.relas); +} + template <class ELFT> void MIPS<ELFT>::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index 550c091..6528cc5 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -8,6 +8,7 @@ #include "InputFiles.h" #include "OutputSections.h" +#include "RelocScan.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -178,6 +179,10 @@ public: uint64_t pltEntryAddr) const override; void writeIplt(uint8_t *buf, const Symbol &sym, uint64_t pltEntryAddr) const override; + template <class ELFT, class RelTy> + void scanSectionImpl(InputSectionBase &, Relocs<RelTy>); + template <class ELFT> void scanSection1(InputSectionBase &); + void scanSection(InputSectionBase &) override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; void writeGotHeader(uint8_t *buf) const override; @@ -1257,6 +1262,132 @@ static bool isTocOptType(RelType type) { } } +// R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for +// General Dynamic/Local Dynamic code sequences. If a GD/LD GOT relocation is +// found but no R_PPC64_TLSGD/R_PPC64_TLSLD is seen, we assume that the +// instructions are generated by very old IBM XL compilers. Work around the +// issue by disabling GD/LD to IE/LE relaxation. +template <class RelTy> +static void checkPPC64TLSRelax(InputSectionBase &sec, Relocs<RelTy> rels) { + // Skip if sec is synthetic (sec.file is null) or if sec has been marked. + if (!sec.file || sec.file->ppc64DisableTLSRelax) + return; + bool hasGDLD = false; + for (const RelTy &rel : rels) { + RelType type = rel.getType(false); + switch (type) { + case R_PPC64_TLSGD: + case R_PPC64_TLSLD: + return; // Found a marker + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TLSLD16: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSLD16_HI: + case R_PPC64_GOT_TLSLD16_LO: + hasGDLD = true; + break; + } + } + if (hasGDLD) { + sec.file->ppc64DisableTLSRelax = true; + Warn(sec.file->ctx) + << sec.file + << ": disable TLS relaxation due to R_PPC64_GOT_TLS* relocations " + "without " + "R_PPC64_TLSGD/R_PPC64_TLSLD relocations"; + } +} + +template <class ELFT, class RelTy> +void PPC64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { + RelocScan rs(ctx, &sec); + sec.relocations.reserve(rels.size()); + checkPPC64TLSRelax<RelTy>(sec, rels); + for (auto it = rels.begin(); it != rels.end(); ++it) { + const RelTy &rel = *it; + uint64_t offset = rel.r_offset; + uint32_t symIdx = rel.getSymbol(false); + Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIdx); + RelType type = rel.getType(false); + RelExpr expr = + ctx.target->getRelExpr(type, sym, sec.content().data() + offset); + if (expr == R_NONE) + continue; + if (sym.isUndefined() && symIdx != 0 && + rs.maybeReportUndefined(cast<Undefined>(sym), offset)) + continue; + + auto addend = getAddend<ELFT>(rel); + if (ctx.arg.isPic && type == R_PPC64_TOC) + addend += getPPC64TocBase(ctx); + + // We can separate the small code model relocations into 2 categories: + // 1) Those that access the compiler generated .toc sections. + // 2) Those that access the linker allocated got entries. + // lld allocates got entries to symbols on demand. Since we don't try to + // sort the got entries in any way, we don't have to track which objects + // have got-based small code model relocs. The .toc sections get placed + // after the end of the linker allocated .got section and we do sort those + // so sections addressed with small code model relocations come first. + if (type == R_PPC64_TOC16 || type == R_PPC64_TOC16_DS) + sec.file->ppc64SmallCodeModelTocRelocs = true; + + // Record the TOC entry (.toc + addend) as not relaxable. See the comment in + // PPC64::relocateAlloc(). + if (type == R_PPC64_TOC16_LO && sym.isSection() && isa<Defined>(sym) && + cast<Defined>(sym).section->name == ".toc") + ctx.ppc64noTocRelax.insert({&sym, addend}); + + if ((type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) || + (type == R_PPC64_TLSLD && expr == R_TLSLD_HINT)) { + auto it1 = it; + ++it1; + if (it1 == rels.end()) { + auto diag = Err(ctx); + diag << "R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last " + "relocation"; + printLocation(diag, sec, sym, offset); + continue; + } + + // Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC + // case, so we can discern it later from the toc-case. + if (it1->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC) + ++offset; + } + + if (oneof<R_GOTREL, RE_PPC64_TOCBASE, RE_PPC64_RELAX_TOC>(expr)) + ctx.in.got->hasGotOffRel.store(true, std::memory_order_relaxed); + + if (sym.isTls()) { + if (unsigned processed = + rs.handleTlsRelocation(expr, type, offset, sym, addend)) { + it += processed - 1; + continue; + } + } + rs.process(expr, type, offset, sym, addend); + } +} + +template <class ELFT> void PPC64::scanSection1(InputSectionBase &sec) { + auto relocs = sec.template relsOrRelas<ELFT>(); + if (relocs.areRelocsCrel()) + scanSectionImpl<ELFT>(sec, relocs.crels); + else + scanSectionImpl<ELFT>(sec, relocs.relas); +} + +void PPC64::scanSection(InputSectionBase &sec) { + if (ctx.arg.isLE) + scanSection1<ELF64LE>(sec); + else + scanSection1<ELF64BE>(sec); +} + void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { RelType type = rel.type; bool shouldTocOptimize = isTocOptType(type); |