[PATCH 2/2] modpost: handle RISC-V relative extable relocations
Jia Wang via B4 Relay <[email protected]> Thu, 16 Jul 2026 13:31:50 +0800
| Newsgroups | org.kernel.vger.linux-kbuild,org.infradead.lists.linux-riscv,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Jia Wang <[email protected]> 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 <[email protected]> --- 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