diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 7f2bfefa5578a..f09d4a8febf8e 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -41,6 +41,8 @@ class RISCV final : public TargetInfo { RelType getDynRel(RelType type) const override; RelExpr getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const override; + RelExpr getVendorRelExpr(RelType type, const Symbol &s, const uint8_t *loc, + StringRef vendor) const override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override; @@ -338,6 +340,8 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, case R_RISCV_SET_ULEB128: case R_RISCV_SUB_ULEB128: return RE_RISCV_LEB128; + case R_RISCV_VENDOR: + return R_NONE; default: Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v << ") against symbol " << &s; @@ -555,6 +559,15 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { } } +RelExpr RISCV::getVendorRelExpr(const RelType type, const Symbol &s, + const uint8_t *loc, StringRef vendor) const { + // TODO: Dispatch to vendor-specific relocation handling. + Err(ctx) << getErrorLoc(ctx, loc) << "unknown vendor-specific relocation (" + << type.v << ") in vendor namespace \"" << vendor + << "\" against symbol " << &s; + return R_NONE; +} + static bool relaxable(ArrayRef relocs, size_t i) { return i + 1 != relocs.size() && relocs[i + 1].type == R_RISCV_RELAX; } diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 6f55bac2ecf16..178dd9f05278f 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -457,6 +457,7 @@ class RelocationScanner { Ctx &ctx; InputSectionBase *sec; OffsetGetter getter; + StringRef rvVendor; // End of relocations, used by Mips/PPC64. const void *end = nullptr; @@ -1510,13 +1511,25 @@ void RelocationScanner::scanOne(typename Relocs::const_iterator &i) { ++i; } } + + // Stash the RISCV vendor namespace for the subsequent relocation. + if (LLVM_UNLIKELY(ctx.arg.emachine == EM_RISCV && type == R_RISCV_VENDOR)) { + rvVendor = sym.getName(); + return; + } + // Get an offset in an output section this relocation is applied to. uint64_t offset = getter.get(ctx, rel.r_offset); if (offset == uint64_t(-1)) return; - RelExpr expr = - ctx.target->getRelExpr(type, sym, sec->content().data() + offset); + RelExpr expr; + if (LLVM_LIKELY(rvVendor.empty())) { + expr = ctx.target->getRelExpr(type, sym, sec->content().data() + offset); + } else { + expr = ctx.target->getVendorRelExpr( + type, sym, sec->content().data() + offset, rvVendor); + } int64_t addend = RelTy::HasAddend ? getAddend(rel) : ctx.target->getImplicitAddend( @@ -1526,6 +1539,9 @@ void RelocationScanner::scanOne(typename Relocs::const_iterator &i) { else if (ctx.arg.emachine == EM_PPC64 && ctx.arg.isPic && type == R_PPC64_TOC) addend += getPPC64TocBase(ctx); + // A RISCV vendor namespace only applies to a single relocation. + rvVendor = ""; + // Ignore R_*_NONE and other marker relocations. if (expr == R_NONE) return; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index bb8c24f052aa2..8e58681db44f1 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -33,6 +33,11 @@ class TargetInfo { virtual uint32_t calcEFlags() const { return 0; } virtual RelExpr getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const = 0; + virtual RelExpr getVendorRelExpr(RelType type, const Symbol &s, + const uint8_t *loc, StringRef vendor) const { + Err(ctx) << "target doesn't support vendor-specific relocations"; + return R_NONE; + }; virtual RelType getDynRel(RelType type) const { return 0; } virtual void writeGotPltHeader(uint8_t *buf) const {} virtual void writeGotHeader(uint8_t *buf) const {} diff --git a/lld/test/ELF/riscv-vendor-relocations.s b/lld/test/ELF/riscv-vendor-relocations.s new file mode 100644 index 0000000000000..d9bc641a38e7d --- /dev/null +++ b/lld/test/ELF/riscv-vendor-relocations.s @@ -0,0 +1,16 @@ +# 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_CUSTOM255, TARGET +1: + nop + +# CHECK: error: {{.*}} unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET