From c05780ef3c190c2dafbf0be8e65d4f01103ad577 Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Fri, 7 Jul 2023 09:00:51 -0700 Subject: module: Ignore RISC-V mapping symbols too RISC-V has an extended form of mapping symbols that we use to encode the ISA when it changes in the middle of an ELF. This trips up modpost as a build failure, I haven't yet verified it yet but I believe the kallsyms difference should result in stacks looking sane again. Reported-by: Randy Dunlap Closes: https://lore.kernel.org/all/9d9e2902-5489-4bf0-d9cb-556c8e5d71c2@infradead.org/ Signed-off-by: Palmer Dabbelt Reviewed-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Signed-off-by: Luis Chamberlain --- include/linux/module_symbol.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/module_symbol.h b/include/linux/module_symbol.h index 7ace7ba30203..5b799942b243 100644 --- a/include/linux/module_symbol.h +++ b/include/linux/module_symbol.h @@ -3,12 +3,22 @@ #define _LINUX_MODULE_SYMBOL_H /* This ignores the intensely annoying "mapping symbols" found in ELF files. */ -static inline int is_mapping_symbol(const char *str) +static inline int is_mapping_symbol(const char *str, int is_riscv) { if (str[0] == '.' && str[1] == 'L') return true; if (str[0] == 'L' && str[1] == '0') return true; + /* + * RISC-V defines various special symbols that start with "$".  The + * mapping symbols, which exist to differentiate between incompatible + * instruction encodings when disassembling, show up all over the place + * and are generally not meant to be treated like other symbols.  So + * just ignore any of the special symbols. + */ + if (is_riscv) + return str[0] == '$'; + return str[0] == '$' && (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x') && (str[2] == '\0' || str[2] == '.'); -- cgit v1.2.3 From ff09f6fd297293175eaa0ed492495e36b3eb1a8e Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Fri, 21 Jul 2023 08:01:48 -0700 Subject: modpost, kallsyms: Treat add '$'-prefixed symbols as mapping symbols Trying to restrict the '$'-prefix change to RISC-V caused some fallout, so let's just treat all those symbols as special. Fixes: c05780ef3c190 ("module: Ignore RISC-V mapping symbols too") Link: https://lore.kernel.org/all/20230712015747.77263-1-wangkefeng.wang@huawei.com/ Signed-off-by: Palmer Dabbelt Reviewed-by: Masahiro Yamada Signed-off-by: Luis Chamberlain --- include/linux/module_symbol.h | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module_symbol.h b/include/linux/module_symbol.h index 5b799942b243..1269543d0634 100644 --- a/include/linux/module_symbol.h +++ b/include/linux/module_symbol.h @@ -3,25 +3,13 @@ #define _LINUX_MODULE_SYMBOL_H /* This ignores the intensely annoying "mapping symbols" found in ELF files. */ -static inline int is_mapping_symbol(const char *str, int is_riscv) +static inline int is_mapping_symbol(const char *str) { if (str[0] == '.' && str[1] == 'L') return true; if (str[0] == 'L' && str[1] == '0') return true; - /* - * RISC-V defines various special symbols that start with "$".  The - * mapping symbols, which exist to differentiate between incompatible - * instruction encodings when disassembling, show up all over the place - * and are generally not meant to be treated like other symbols.  So - * just ignore any of the special symbols. - */ - if (is_riscv) - return str[0] == '$'; - - return str[0] == '$' && - (str[1] == 'a' || str[1] == 'd' || str[1] == 't' || str[1] == 'x') - && (str[2] == '\0' || str[2] == '.'); + return str[0] == '$'; } #endif /* _LINUX_MODULE_SYMBOL_H */ -- cgit v1.2.3 From 2abcc4b5a64a65a2d2287ba0be5c2871c1552416 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 1 Aug 2023 14:54:07 +0000 Subject: module: Expose module_init_layout_section() module_init_layout_section() choses whether the core module loader considers a section as init or not. This affects the placement of the exit section when module unloading is disabled. This code will never run, so it can be free()d once the module has been initialised. arm and arm64 need to count the number of PLTs they need before applying relocations based on the section name. The init PLTs are stored separately so they can be free()d. arm and arm64 both use within_module_init() to decide which list of PLTs to use when applying the relocation. Because within_module_init()'s behaviour changes when module unloading is disabled, both architecture would need to take this into account when counting the PLTs. Today neither architecture does this, meaning when module unloading is disabled there are insufficient PLTs in the init section to load some modules, resulting in warnings: | WARNING: CPU: 2 PID: 51 at arch/arm64/kernel/module-plts.c:99 module_emit_plt_entry+0x184/0x1cc | Modules linked in: crct10dif_common | CPU: 2 PID: 51 Comm: modprobe Not tainted 6.5.0-rc4-yocto-standard-dirty #15208 | Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 | pstate: 20400005 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) | pc : module_emit_plt_entry+0x184/0x1cc | lr : module_emit_plt_entry+0x94/0x1cc | sp : ffffffc0803bba60 [...] | Call trace: | module_emit_plt_entry+0x184/0x1cc | apply_relocate_add+0x2bc/0x8e4 | load_module+0xe34/0x1bd4 | init_module_from_file+0x84/0xc0 | __arm64_sys_finit_module+0x1b8/0x27c | invoke_syscall.constprop.0+0x5c/0x104 | do_el0_svc+0x58/0x160 | el0_svc+0x38/0x110 | el0t_64_sync_handler+0xc0/0xc4 | el0t_64_sync+0x190/0x194 Instead of duplicating module_init_layout_section()s logic, expose it. Reported-by: Adam Johnston Fixes: 055f23b74b20 ("module: check for exit sections in layout_sections() instead of module_init_section()") Cc: stable@vger.kernel.org Signed-off-by: James Morse Signed-off-by: Luis Chamberlain --- include/linux/moduleloader.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h index 03be088fb439..001b2ce83832 100644 --- a/include/linux/moduleloader.h +++ b/include/linux/moduleloader.h @@ -42,6 +42,11 @@ bool module_init_section(const char *name); */ bool module_exit_section(const char *name); +/* Describes whether within_module_init() will consider this an init section + * or not. This behaviour changes with CONFIG_MODULE_UNLOAD. + */ +bool module_init_layout_section(const char *sname); + /* * Apply the given relocation to the (simplified) ELF. Return -error * or 0. -- cgit v1.2.3