[PATCH 2/2] modpost: handle RISC-V relative extable relocations

Jia Wang via B4 Relay devnull+wangjia.ultrarisc.com at kernel.org
Wed Jul 15 22:31:50 PDT 2026


From: Jia Wang <wangjia at ultrarisc.com>

RISC-V relative exception tables emit an R_RISCV_ADD32 and
R_RISCV_SUB32 relocation pair for each field. modpost already
ignores the SUB32 half, but still checks the ADD32 symbol section
directly.

After a relocatable link, that ADD32 symbol can name an unrelated
local debug symbol. This makes modpost report that __ex_table
references non-executable .debug* sections even though the original
exception table entry points at text.

Recognize the RISC-V ADD32/SUB32 pair for __ex_table. Ignore ADD32
entries that have been resolved to debug symbols, and otherwise
validate the resolved relative target address against executable
sections.

This was seen with an rv32 randconfig using KCONFIG_SEED=4721 with
CONFIG_MMU=y and CONFIG_DEBUG_INFO=y. The resulting vmlinux.o contains
R_RISCV_ADD32/R_RISCV_SUB32 relocation pairs in __ex_table, and the
fixed modpost run completes without the false .debug* section mismatch
diagnostics.

Signed-off-by: Jia Wang <wangjia at ultrarisc.com>
---
 scripts/mod/modpost.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 6869822446bd..04a12eebb381 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1356,6 +1356,10 @@ static Elf_Addr addend_mips_rel(uint32_t *location, unsigned int r_type)
 #define EM_RISCV		243
 #endif
 
+#ifndef R_RISCV_ADD32
+#define R_RISCV_ADD32		35
+#endif
+
 #ifndef R_RISCV_SUB32
 #define R_RISCV_SUB32		39
 #endif
@@ -1406,6 +1410,76 @@ static void get_rel_type_and_sym(struct elf_info *elf, uint64_t r_info,
 	*r_sym = ELF_R_SYM(r_info);
 }
 
+static bool section_contains_addr(struct elf_info *elf, unsigned int secndx,
+				  Elf_Addr addr)
+{
+	Elf_Shdr *sechdr;
+
+	if (secndx >= elf->num_sections)
+		return false;
+
+	sechdr = &elf->sechdrs[secndx];
+
+	return addr >= sechdr->sh_addr &&
+	       addr - sechdr->sh_addr < sechdr->sh_size;
+}
+
+static bool addr_is_executable(struct elf_info *elf, Elf_Addr addr)
+{
+	unsigned int i;
+
+	for (i = 1; i < elf->num_sections; i++) {
+		if ((elf->sechdrs[i].sh_flags & SHF_EXECINSTR) &&
+		    section_contains_addr(elf, i, addr))
+			return true;
+	}
+
+	return false;
+}
+
+static bool is_debug_section(const char *secname)
+{
+	return match(secname, PATTERNS(".debug*", ".zdebug*"));
+}
+
+static bool riscv_extable_rela_valid(struct elf_info *elf,
+				     const Elf_Rela *start,
+				     const Elf_Rela *stop,
+				     const Elf_Rela *rela,
+				     Elf_Addr r_offset,
+				     Elf_Sym *add_sym)
+{
+	Elf_Addr add_addr, sub_addr, target_addr;
+	unsigned int r_type, r_sym;
+	const Elf_Rela *pair;
+	Elf_Sym *sub_sym;
+
+	/*
+	 * RISC-V relative exception tables emit an ADD32/SUB32 pair for each
+	 * field. After ld -r, the ADD32 symbol may name an unrelated local
+	 * debug symbol. Otherwise, validate the resolved relative target.
+	 */
+	for (pair = start; pair < stop; pair++) {
+		get_rel_type_and_sym(elf, pair->r_info, &r_type, &r_sym);
+		if (TO_NATIVE(pair->r_offset) == r_offset &&
+		    r_type == R_RISCV_SUB32)
+			break;
+	}
+
+	if (pair == stop)
+		return false;
+
+	sub_sym = elf->symtab_start + r_sym;
+	if (is_debug_section(sec_name(elf, get_secindex(elf, add_sym))))
+		return true;
+
+	add_addr = add_sym->st_value + TO_NATIVE(rela->r_addend);
+	sub_addr = sub_sym->st_value + TO_NATIVE(pair->r_addend);
+	target_addr = r_offset + add_addr - sub_addr;
+
+	return addr_is_executable(elf, target_addr);
+}
+
 static void section_rela(struct module *mod, struct elf_info *elf,
 			 unsigned int fsecndx, const char *fromsec,
 			 const Elf_Rela *start, const Elf_Rela *stop)
@@ -1428,6 +1502,11 @@ static void section_rela(struct module *mod, struct elf_info *elf,
 			if (!strcmp("__ex_table", fromsec) &&
 			    r_type == R_RISCV_SUB32)
 				continue;
+			if (!strcmp("__ex_table", fromsec) &&
+			    r_type == R_RISCV_ADD32 &&
+			    riscv_extable_rela_valid(elf, start, stop, rela,
+						     r_offset, tsym))
+				continue;
 			break;
 		case EM_LOONGARCH:
 			switch (r_type) {

-- 
2.34.1





More information about the linux-riscv mailing list