diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index dc2ab97e9d9be..6b226255e345b 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -8,6 +8,7 @@ #include "InputFiles.h" #include "OutputSections.h" +#include "RelocScan.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -38,6 +39,10 @@ class RISCV final : public TargetInfo { void writePltHeader(uint8_t *buf) const override; void writePlt(uint8_t *buf, const Symbol &sym, uint64_t pltEntryAddr) const override; + template + void scanSectionImpl(InputSectionBase &, Relocs); + template void scanSection1(InputSectionBase &); + void scanSection(InputSectionBase &) override; RelType getDynRel(RelType type) const override; RelExpr getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const override; @@ -278,6 +283,7 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, const uint8_t *loc) const { switch (type) { case R_RISCV_NONE: + case R_RISCV_VENDOR: return R_NONE; case R_RISCV_32: case R_RISCV_64: @@ -1476,3 +1482,54 @@ void elf::mergeRISCVAttributesSections(Ctx &ctx) { } void elf::setRISCVTargetInfo(Ctx &ctx) { ctx.target.reset(new RISCV(ctx)); } + +template +void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs rels) { + RelocScan rs(ctx, &sec); + // Many relocations end up in sec.relocations. + sec.relocations.reserve(rels.size()); + + StringRef rvVendor; + for (auto it = rels.begin(); it != rels.end(); ++it) { + RelType type = it->getType(false); + uint32_t symIndex = it->getSymbol(false); + Symbol &sym = sec.getFile()->getSymbol(symIndex); + const uint8_t *loc = sec.content().data() + it->r_offset; + + if (type == R_RISCV_VENDOR) { + if (!rvVendor.empty()) + Err(ctx) << getErrorLoc(ctx, loc) + << "malformed consecutive R_RISCV_VENDOR relocations"; + rvVendor = sym.getName(); + continue; + } else if (!rvVendor.empty()) { + Err(ctx) << getErrorLoc(ctx, loc) + << "unknown vendor-specific relocation (" << type.v + << ") in vendor namespace \"" << rvVendor << "\" against symbol " + << &sym; + rvVendor = ""; + continue; + } + + rs.scan(it, type, rs.getAddend(*it, type)); + } + + // Sort relocations by offset for more efficient searching for + // R_RISCV_PCREL_HI20. + llvm::stable_sort(sec.relocs(), + [](const Relocation &lhs, const Relocation &rhs) { + return lhs.offset < rhs.offset; + }); +} + +template void RISCV::scanSection1(InputSectionBase &sec) { + const RelsOrRelas rels = sec.template relsOrRelas(); + if (rels.areRelocsCrel()) + scanSectionImpl(sec, rels.crels); + else + scanSectionImpl(sec, rels.relas); +} + +void RISCV::scanSection(InputSectionBase &sec) { + invokeELFT(scanSection1, sec); +} diff --git a/lld/test/riscv-vendor-relocations.s b/lld/test/riscv-vendor-relocations.s new file mode 100644 index 0000000000000..68a6364ed18b1 --- /dev/null +++ b/lld/test/riscv-vendor-relocations.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc -triple riscv32 %s -filetype=obj -o %t.o +# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck %s + + .option exact + + .global TARGET +TARGET: + nop + +.global INVALID_VENDOR +.reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0 +.reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0 +.reloc 1f, R_RISCV_CUSTOM255, TARGET +1: + nop + +# CHECK: error: {{.*}} malformed consecutive R_RISCV_VENDOR relocations +# CHECK: error: {{.*}} unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET