diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp index 85f49c926056..19baa6119f23 100644 --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -278,17 +278,15 @@ RelType RISCV::getDynRel(RelType type) const { : static_cast(R_RISCV_NONE); } +// Only needed to support relocations used by relocateNonAlloc and +// preprocessRelocs. 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: - case R_RISCV_HI20: - case R_RISCV_LO12_I: - case R_RISCV_LO12_S: return R_ABS; case R_RISCV_ADD8: case R_RISCV_ADD16: @@ -304,42 +302,8 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s, case R_RISCV_SUB32: case R_RISCV_SUB64: return RE_RISCV_ADD; - case R_RISCV_JAL: - case R_RISCV_BRANCH: - case R_RISCV_PCREL_HI20: - case R_RISCV_RVC_BRANCH: - case R_RISCV_RVC_JUMP: case R_RISCV_32_PCREL: return R_PC; - case R_RISCV_CALL: - case R_RISCV_CALL_PLT: - case R_RISCV_PLT32: - return R_PLT_PC; - case R_RISCV_GOT_HI20: - case R_RISCV_GOT32_PCREL: - return R_GOT_PC; - case R_RISCV_PCREL_LO12_I: - case R_RISCV_PCREL_LO12_S: - return RE_RISCV_PC_INDIRECT; - case R_RISCV_TLSDESC_HI20: - case R_RISCV_TLSDESC_LOAD_LO12: - case R_RISCV_TLSDESC_ADD_LO12: - return R_TLSDESC_PC; - case R_RISCV_TLSDESC_CALL: - return R_TLSDESC_CALL; - case R_RISCV_TLS_GD_HI20: - return R_TLSGD_PC; - case R_RISCV_TLS_GOT_HI20: - return R_GOT_PC; - case R_RISCV_TPREL_HI20: - case R_RISCV_TPREL_LO12_I: - case R_RISCV_TPREL_LO12_S: - return R_TPREL; - case R_RISCV_ALIGN: - return R_RELAX_HINT; - case R_RISCV_TPREL_ADD: - case R_RISCV_RELAX: - return ctx.arg.relax ? R_RELAX_HINT : R_NONE; case R_RISCV_SET_ULEB128: case R_RISCV_SUB_ULEB128: return RE_RISCV_LEB128; @@ -356,29 +320,152 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs rels) { // Many relocations end up in sec.relocations. sec.relocations.reserve(rels.size()); - StringRef rvVendor; + StringRef vendor; 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(); + uint64_t offset = it->r_offset; + if (sym.isUndefined() && symIndex != 0 && + rs.maybeReportUndefined(cast(sym), offset)) continue; - } else if (!rvVendor.empty()) { - Err(ctx) << getErrorLoc(ctx, loc) - << "unknown vendor-specific relocation (" << type.v - << ") in namespace '" << rvVendor << "' against symbol '" << &sym - << "'"; - rvVendor = ""; + int64_t addend = rs.getAddend(*it, type); + RelExpr expr; + // Relocation types that only need a RelExpr set `expr` and break out of + // the switch to reach rs.process(). Types that need special handling + // (fast-path helpers, TLS) call a handler and use `continue`. + switch (type) { + case R_RISCV_NONE: + continue; + + // Absolute relocations: + case R_RISCV_32: + case R_RISCV_64: + case R_RISCV_HI20: + case R_RISCV_LO12_I: + case R_RISCV_LO12_S: + expr = R_ABS; + break; + + // PC-relative relocations: + case R_RISCV_JAL: + case R_RISCV_BRANCH: + case R_RISCV_PCREL_HI20: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + case R_RISCV_32_PCREL: + rs.processR_PC(type, offset, addend, sym); + continue; + case R_RISCV_PCREL_LO12_I: + case R_RISCV_PCREL_LO12_S: + expr = RE_RISCV_PC_INDIRECT; + break; + + // PLT-generating relocations: + case R_RISCV_CALL: + case R_RISCV_CALL_PLT: + case R_RISCV_PLT32: + rs.processR_PLT_PC(type, offset, addend, sym); + continue; + + // GOT-generating relocations: + case R_RISCV_GOT_HI20: + case R_RISCV_GOT32_PCREL: + expr = R_GOT_PC; + break; + + // TLS relocations: + case R_RISCV_TPREL_HI20: + case R_RISCV_TPREL_LO12_I: + case R_RISCV_TPREL_LO12_S: + if (rs.checkTlsLe(offset, sym, type)) + continue; + expr = R_TPREL; + break; + case R_RISCV_TLS_GOT_HI20: + // There is no IE to LE optimization. + rs.handleTlsIe(R_GOT_PC, type, offset, addend, sym); + continue; + case R_RISCV_TLS_GD_HI20: + // There is no GD to IE/LE optimization. + rs.handleTlsGd(R_TLSGD_PC, R_NONE, R_NONE, type, offset, addend, sym); + continue; + + // TLSDESC relocations: + case R_RISCV_TLSDESC_HI20: + rs.handleTlsDesc(R_TLSDESC_PC, R_GOT_PC, type, offset, addend, sym); + continue; + case R_RISCV_TLSDESC_LOAD_LO12: + case R_RISCV_TLSDESC_ADD_LO12: + // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12,CALL} reference a label, not the + // TLS symbol, so we cannot use handleTlsDesc (which sets NEEDS_TLSDESC). + // For TLSDESC->IE, use R_TPREL as well, but relocateAlloc uses isToLe + // (from HI20) to select the correct transform. + sec.addReloc({ctx.arg.shared ? R_TLSDESC_PC : R_TPREL, type, offset, + addend, &sym}); + continue; + case R_RISCV_TLSDESC_CALL: + if (!ctx.arg.shared) + sec.addReloc({R_TPREL, type, offset, addend, &sym}); + continue; + + // Relaxation hints: + case R_RISCV_ALIGN: + sec.addReloc({R_RELAX_HINT, type, offset, addend, &sym}); + continue; + case R_RISCV_TPREL_ADD: + case R_RISCV_RELAX: + if (ctx.arg.relax) + sec.addReloc({R_RELAX_HINT, type, offset, addend, &sym}); + continue; + + // Misc relocations: + case R_RISCV_ADD8: + case R_RISCV_ADD16: + case R_RISCV_ADD32: + case R_RISCV_ADD64: + case R_RISCV_SET6: + case R_RISCV_SET8: + case R_RISCV_SET16: + case R_RISCV_SET32: + case R_RISCV_SUB6: + case R_RISCV_SUB8: + case R_RISCV_SUB16: + case R_RISCV_SUB32: + case R_RISCV_SUB64: + expr = RE_RISCV_ADD; + break; + case R_RISCV_SET_ULEB128: + case R_RISCV_SUB_ULEB128: + expr = RE_RISCV_LEB128; + break; + + case R_RISCV_VENDOR: { + auto it1 = it; + ++it1; + if (it1 == rels.end() || it1->getType(false) - 192u > 63u) { + Err(ctx) << getErrorLoc(ctx, sec.content().data() + offset) + << "R_RISCV_VENDOR is not followed by a relocation of code " + "192 to 255"; + continue; + } + vendor = sym.getName(); + } + continue; + default: + auto diag = Err(ctx); + diag << getErrorLoc(ctx, sec.content().data() + offset); + if (!vendor.empty()) { + diag << "unknown vendor-specific relocation (" << type.v + << ") in namespace '" << vendor << "' against symbol '" << &sym + << "'"; + vendor = ""; + } else { + diag << "unknown relocation (" << type.v << ") against symbol " << &sym; + } continue; } - - rs.scan(it, type, rs.getAddend(*it, type)); + rs.process(expr, type, offset, sym, addend); } // Sort relocations by offset for more efficient searching for @@ -664,47 +751,52 @@ void RISCV::relocateAlloc(InputSection &sec, uint8_t *buf) const { uint8_t *loc = buf + rel.offset; uint64_t val = sec.getRelocTargetVA(ctx, rel, secAddr + rel.offset); - switch (rel.expr) { - case R_RELAX_HINT: + switch (rel.type) { + case R_RISCV_ALIGN: + case R_RISCV_RELAX: + case R_RISCV_TPREL_ADD: continue; - case R_TLSDESC_PC: - // For R_RISCV_TLSDESC_HI20, store &got(sym)-PC to be used by the - // following two instructions L[DW] and ADDI. - if (rel.type == R_RISCV_TLSDESC_HI20) + case R_RISCV_TLSDESC_HI20: + if (rel.expr == R_TLSDESC_PC) { + // Shared object: store &got(sym)-PC for the following L[DW]/ADDI. tlsdescVal = val; - else - val = tlsdescVal; - break; - case R_RELAX_TLS_GD_TO_IE: - // Only R_RISCV_TLSDESC_HI20 reaches here. tlsdescVal will be finalized - // after we see R_RISCV_TLSDESC_ADD_LO12 in the R_RELAX_TLS_GD_TO_LE case. - // The net effect is that tlsdescVal will be smaller than `val` to take - // into account of NOP instructions (in the absence of R_RISCV_RELAX) - // before AUIPC. - tlsdescVal = val + rel.offset; - isToLe = false; - tlsdescRelax = relaxable(relocs, i); - if (!tlsdescRelax) - tlsdescToIe(ctx, loc, rel, val); - continue; - case R_RELAX_TLS_GD_TO_LE: - // See the comment in handleTlsRelocation. For TLSDESC=>IE, - // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12,CALL} also reach here. If isToLe is - // false, this is actually TLSDESC=>IE optimization. - if (rel.type == R_RISCV_TLSDESC_HI20) { - tlsdescVal = val; - isToLe = true; - tlsdescRelax = relaxable(relocs, i); - } else { - if (!isToLe && rel.type == R_RISCV_TLSDESC_ADD_LO12) - tlsdescVal -= rel.offset; - val = tlsdescVal; + break; } + // Executable: TLSDESC->LE (R_TPREL) or TLSDESC->IE (R_GOT_PC). + isToLe = rel.expr == R_TPREL; + if (isToLe) { + tlsdescVal = val; + } else { + // tlsdescVal will be finalized after we see R_RISCV_TLSDESC_ADD_LO12. + // The net effect is that tlsdescVal will be smaller than `val` to + // take into account of NOP instructions (in the absence of + // R_RISCV_RELAX) before AUIPC. + tlsdescVal = val + rel.offset; + } + tlsdescRelax = relaxable(relocs, i); + if (!tlsdescRelax) { + if (isToLe) + tlsdescToLe(loc, rel, val); + else + tlsdescToIe(ctx, loc, rel, val); + } + continue; + case R_RISCV_TLSDESC_LOAD_LO12: + case R_RISCV_TLSDESC_ADD_LO12: + case R_RISCV_TLSDESC_CALL: + if (rel.expr == R_TLSDESC_PC) { + // Shared object: propagate the stored GOT value. + val = tlsdescVal; + break; + } + // Executable: IE or LE instruction rewrite. + if (!isToLe && rel.type == R_RISCV_TLSDESC_ADD_LO12) + tlsdescVal -= rel.offset; + val = tlsdescVal; // When NOP conversion is eligible and relaxation applies, don't write a // NOP in case an unrelated instruction follows the current instruction. if (tlsdescRelax && - (rel.type == R_RISCV_TLSDESC_HI20 || - rel.type == R_RISCV_TLSDESC_LOAD_LO12 || + (rel.type == R_RISCV_TLSDESC_LOAD_LO12 || (rel.type == R_RISCV_TLSDESC_ADD_LO12 && isToLe && !hi20(val)))) continue; if (isToLe) @@ -712,11 +804,10 @@ void RISCV::relocateAlloc(InputSection &sec, uint8_t *buf) const { else tlsdescToIe(ctx, loc, rel, val); continue; - case RE_RISCV_LEB128: + case R_RISCV_SET_ULEB128: if (i + 1 < size) { const Relocation &rel1 = relocs[i + 1]; - if (rel.type == R_RISCV_SET_ULEB128 && - rel1.type == R_RISCV_SUB_ULEB128 && rel.offset == rel1.offset) { + if (rel1.type == R_RISCV_SUB_ULEB128 && rel.offset == rel1.offset) { auto val = rel.sym->getVA(ctx, rel.addend) - rel1.sym->getVA(ctx, rel1.addend); if (overwriteULEB128(loc, val) >= 0x80) @@ -728,7 +819,7 @@ void RISCV::relocateAlloc(InputSection &sec, uint8_t *buf) const { } } Err(ctx) << sec.getLocation(rel.offset) - << ": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128"; + << ": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_ULEB128"; return; default: break; @@ -956,7 +1047,7 @@ static bool relax(Ctx &ctx, int pass, InputSection &sec) { case R_RISCV_TLSDESC_HI20: // For TLSDESC=>LE, we can use the short form if hi20 is zero. tlsdescRelax = relaxable(relocs, i); - toLeShortForm = tlsdescRelax && r.expr == R_RELAX_TLS_GD_TO_LE && + toLeShortForm = tlsdescRelax && r.expr == R_TPREL && !hi20(r.sym->getVA(ctx, r.addend)); [[fallthrough]]; case R_RISCV_TLSDESC_LOAD_LO12: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 3245191a4074..4396871f1d3f 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1101,7 +1101,7 @@ void InputSection::relocateNonAlloc(Ctx &ctx, uint8_t *buf, continue; } Err(ctx) << getLocation(offset) - << ": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128"; + << ": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_ULEB128"; return; } diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index da6d36cc114c..b71f20921e1e 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1136,35 +1136,24 @@ unsigned RelocScan::handleTlsRelocation(RelExpr expr, RelType type, if (expr == R_TPREL || expr == R_TPREL_NEG) return checkTlsLe(offset, sym, type) ? 1 : 0; - bool isRISCV = ctx.arg.emachine == EM_RISCV; - if (oneof(expr) && ctx.arg.shared) { - // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12_I,CALL} reference a label. Do not - // set NEEDS_TLSDESC on the label. if (expr != R_TLSDESC_CALL) { - if (!isRISCV || type == R_RISCV_TLSDESC_HI20) - sym.setFlags(NEEDS_TLSDESC); + sym.setFlags(NEEDS_TLSDESC); sec->addReloc({expr, type, offset, addend, &sym}); } return 1; } - // RISC-V does not support GD/LD to IE/LE optimizations. - // RISC-V supports TLSDESC to IE/LE optimizations. - // For PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable - // optimization as well. - bool execOptimize = - !ctx.arg.shared && - !(isRISCV && expr != R_TLSDESC_PC && expr != R_TLSDESC_CALL); + bool execOptimize = !ctx.arg.shared; // If we are producing an executable and the symbol is non-preemptable, it // must be defined and the code sequence can be optimized to use Local-Exec. // - // RISC-V does not support any relaxations for TLS relocations, however, we - // can omit the DTPMOD dynamic relocations and resolve them at link time - // because them are always 1. This may be necessary for static linking as - // DTPMOD may not be expected at load time. + // While some targets do not have TLS optimizations, we can omit the + // DTPMOD dynamic relocations and resolve them at link time because them + // are always 1. This may be necessary for static linking as DTPMOD may + // not be expected at load time. bool isLocalInExecutable = !sym.isPreemptible && !ctx.arg.shared; // Local Dynamic is for access to module local TLS variables, while still @@ -1203,10 +1192,6 @@ unsigned RelocScan::handleTlsRelocation(RelExpr expr, RelType type, // Global-Dynamic/TLSDESC can be optimized to Initial-Exec or Local-Exec // depending on the symbol being locally defined or not. - // - // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12_I,CALL} reference a non-preemptible - // label, so TLSDESC=>IE will be categorized as R_RELAX_TLS_GD_TO_LE. We fix - // the categorization in RISCV::relocateAlloc. if (sym.isPreemptible) { sym.setFlags(NEEDS_TLSIE); sec->addReloc({ctx.target->adjustTlsExpr(type, R_RELAX_TLS_GD_TO_IE), diff --git a/lld/test/ELF/riscv-reloc-leb128.s b/lld/test/ELF/riscv-reloc-leb128.s index 0bdc1eb18269..3c84ca7d04da 100644 --- a/lld/test/ELF/riscv-reloc-leb128.s +++ b/lld/test/ELF/riscv-reloc-leb128.s @@ -64,8 +64,8 @@ # RUN: not ld.lld -shared --threads=1 unpaired2.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired3.s -o unpaired3.o # RUN: not ld.lld -shared --threads=1 unpaired3.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED -# UNPAIRED: error: {{.*}}.o:(.alloc+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128 -# UNPAIRED: error: {{.*}}.o:(.debug_rnglists+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128 +# UNPAIRED: error: {{.*}}.o:(.alloc+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_ULEB128 +# UNPAIRED: error: {{.*}}.o:(.debug_rnglists+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_ULEB128 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax overflow.s -o overflow.o # RUN: not ld.lld -shared --threads=1 overflow.o 2>&1 | FileCheck %s --check-prefix=OVERFLOW diff --git a/lld/test/ELF/riscv-vendor-relocations.s b/lld/test/ELF/riscv-vendor-relocations.s index b0f3c4a30d06..892154825bee 100644 --- a/lld/test/ELF/riscv-vendor-relocations.s +++ b/lld/test/ELF/riscv-vendor-relocations.s @@ -8,12 +8,42 @@ 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: +INVALID_VENDOR: +.reloc ., R_RISCV_VENDOR, INVALID_VENDOR+0 +.reloc ., R_RISCV_VENDOR, INVALID_VENDOR+0 +.reloc ., R_RISCV_CUSTOM255, TARGET nop -# CHECK: error: {{.*}}:(.text+0x4): malformed consecutive R_RISCV_VENDOR relocations +# CHECK: error: {{.*}}:(.text+0x4): R_RISCV_VENDOR is not followed by a relocation of code 192 to 255 # CHECK: error: {{.*}}:(.text+0x4): unknown vendor-specific relocation (255) in namespace 'INVALID_VENDOR' against symbol 'TARGET' + +## R_RISCV_VENDOR followed by a standard relocation (not in 192-255 range). +# CHECK: error: {{.*}}:(.text1+0x0): R_RISCV_VENDOR is not followed by a relocation of code 192 to 255 +.section .text1,"ax" +.reloc ., R_RISCV_VENDOR, INVALID_VENDOR +.reloc ., R_RISCV_32, TARGET +nop + +## R_RISCV_VENDOR at end of section (no following relocation). +# CHECK: error: {{.*}}:(.text2+0x0): R_RISCV_VENDOR is not followed by a relocation of code 192 to 255 +.section .text2,"ax" +.reloc ., R_RISCV_VENDOR, INVALID_VENDOR +nop + +## Code 192 and 255 are in the valid range and reach the default case. +# CHECK: error: {{.*}}:(.text3+0x0): unknown vendor-specific relocation (192) in namespace 'INVALID_VENDOR' against symbol 'TARGET' +# CHECK: error: {{.*}}:(.text3+0x0): unknown vendor-specific relocation (255) in namespace 'INVALID_VENDOR' against symbol 'TARGET' +.section .text3,"ax" +.reloc ., R_RISCV_VENDOR, INVALID_VENDOR +.reloc ., R_RISCV_CUSTOM192, TARGET +.reloc ., R_RISCV_VENDOR, INVALID_VENDOR +.reloc ., R_RISCV_CUSTOM255, TARGET +nop + +## The vendor symbol must be defined. If not, don't bother with a better diagnostic. +# CHECK: error: {{.*}}:(.text4+0x0): unknown relocation (255) against symbol TARGET +# CHECK: error: undefined symbol: undef +.section .text4,"ax" +.reloc ., R_RISCV_VENDOR, undef +.reloc ., R_RISCV_CUSTOM255, TARGET +nop diff --git a/lld/test/ELF/riscv-vendor-relocations2.test b/lld/test/ELF/riscv-vendor-relocations2.test new file mode 100644 index 000000000000..1e7ab1f776c6 --- /dev/null +++ b/lld/test/ELF/riscv-vendor-relocations2.test @@ -0,0 +1,32 @@ +# REQUIRES: riscv +## R_RISCV_VENDOR followed by a relocation of code 256 (outside 192-255). +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: {{.*}}:(.text+0x0): R_RISCV_VENDOR is not followed by a relocation of code 192 to 255 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Content: '13000000' + - Name: .rela.text + Type: SHT_RELA + Info: .text + Relocations: + - Type: R_RISCV_VENDOR + Symbol: vendor + - Type: 0x100 # 256, outside 192-255 + Symbol: foo +Symbols: + - Name: vendor + Section: .text + - Name: foo + Section: .text + Binding: STB_GLOBAL