diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -569,6 +569,20 @@ llvm_unreachable("AArch64 pc-relative relocation expected\n"); } +static uint64_t getRISCVUndefinedRelativeWeakVA(uint64_t type, uint64_t p) { + switch (type) { + case R_RISCV_BRANCH: + case R_RISCV_JAL: + case R_RISCV_CALL: + case R_RISCV_CALL_PLT: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + return p; + default: + return 0; + } +} + // ARM SBREL relocations are of the form S + A - B where B is the static base // The ARM ABI defines base to be "addressing origin of the output segment // defining the symbol S". We defined the "addressing origin"/static base to be @@ -765,14 +779,18 @@ // Some PC relative ARM (Thumb) relocations align down the place. p = p & 0xfffffffc; if (sym.isUndefWeak()) { - // On ARM and AArch64 a branch to an undefined weak resolves to the - // next instruction, otherwise the place. + // On ARM and AArch64 a branch to an undefined weak resolves to the next + // instruction, otherwise the place. On RISCV, resolve an undefined weak + // to the same instruction to cause an infinite loop (making the user + // aware of the issue) while ensuring no overflow. if (config->emachine == EM_ARM) dest = getARMUndefinedRelativeWeakVA(type, a, p); else if (config->emachine == EM_AARCH64) dest = getAArch64UndefinedRelativeWeakVA(type, a, p); else if (config->emachine == EM_PPC) dest = p; + else if (config->emachine == EM_RISCV) + dest = getRISCVUndefinedRelativeWeakVA(type, p) + a; else dest = sym.getVA(a); } else { diff --git a/lld/test/ELF/riscv-undefined-weak.s b/lld/test/ELF/riscv-undefined-weak.s --- a/lld/test/ELF/riscv-undefined-weak.s +++ b/lld/test/ELF/riscv-undefined-weak.s @@ -48,21 +48,29 @@ ## Treat them as PC relative relocations. # RELOC: 0x18 R_RISCV_CALL target 0x0 # RELOC-NEXT: 0x20 R_RISCV_JAL target 0x0 +# RELOC-NEXT: 0x24 R_RISCV_BRANCH target 0x0 # PC-LABEL: : -# PC-NEXT: auipc ra, 1048559 -# PC-NEXT: jalr -368(ra) -# PC-NEXT: j 0x0 +# PC-NEXT: auipc ra, 0 +# PC-NEXT: jalr ra +# PC-NEXT: [[#%x,ADDR:]]: +# PC-SAME: j 0x[[#ADDR]] +# PC-NEXT: [[#%x,ADDR:]]: +# PC-SAME: beqz zero, 0x[[#ADDR]] ## If .dynsym exists, an undefined weak symbol is preemptible. ## We create a PLT entry and redirect the reference to it. # PLT-LABEL: : # PLT-NEXT: auipc ra, 0 # PLT-NEXT: jalr 56(ra) -# PLT-NEXT: j 0x0 +# PLT-NEXT: [[#%x,ADDR:]]: +# PLT-SAME: j 0x[[#ADDR]] +# PLT-NEXT: [[#%x,ADDR:]]: +# PLT-SAME: beqz zero, 0x[[#ADDR]] branch: call target jal x0, target + beq x0, x0, target ## Absolute relocations are resolved to 0. # RELOC: 0x0 R_RISCV_64 target 0x3