Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

modpost: Create modalias for builtin modules

For some modules, modalias is generated using the modpost utility and
the section is added to the module file.

When a module is added inside vmlinux, modpost does not generate
modalias for such modules and the information is lost.

As a result kmod (which uses modules.builtin.modinfo in userspace)
cannot determine that modalias is handled by a builtin kernel module.

$ cat /sys/devices/pci0000:00/0000:00:14.0/modalias
pci:v00008086d0000A36Dsv00001043sd00008694bc0Csc03i30

$ modinfo xhci_pci
name: xhci_pci
filename: (builtin)
license: GPL
file: drivers/usb/host/xhci-pci
description: xHCI PCI Host Controller Driver

Missing modalias "pci:v*d*sv*sd*bc0Csc03i30*" which will be generated by
modpost if the module is built separately.

To fix this it is necessary to generate the same modalias for vmlinux as
for the individual modules. Fortunately '.vmlinux.export.o' is already
generated from which '.modinfo' can be extracted in the same way as for
vmlinux.o.

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
Signed-off-by: Alexey Gladkov <legion@kernel.org>
Tested-by: Stephen Rothwell <sfr@canb.auug.org.au>
Reviewed-by: Nicolas Schier <nsc@kernel.org>
Link: https://patch.msgid.link/28d4da3b0e3fc8474142746bcf469e03752c3208.1758182101.git.legion@kernel.org
Signed-off-by: Nathan Chancellor <nathan@kernel.org>

authored by

Alexey Gladkov and committed by
Nathan Chancellor
5ab23c79 83fb4938

+41 -6
-4
include/linux/module.h
··· 256 256 __PASTE(type, \ 257 257 __PASTE(__, name))))) 258 258 259 - #ifdef MODULE 260 259 /* Creates an alias so file2alias.c can find device table. */ 261 260 #define MODULE_DEVICE_TABLE(type, name) \ 262 261 static typeof(name) __mod_device_table(type, name) \ 263 262 __attribute__ ((used, alias(__stringify(name)))) 264 - #else /* !MODULE */ 265 - #define MODULE_DEVICE_TABLE(type, name) 266 - #endif 267 263 268 264 /* Version of form [<epoch>:]<version>[-<extra-version>]. 269 265 * Or for CVS/RCS ID version, everything but the number is stripped.
+3 -1
scripts/Makefile.vmlinux
··· 89 89 remove-section-y := .modinfo 90 90 remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*' 91 91 92 + remove-symbols := -w --strip-symbol='__mod_device_table__*' 93 + 92 94 # To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy, 93 95 # it is necessary to remove the PT_LOAD flag from the segment. 94 96 quiet_cmd_strip_relocs = OBJCOPY $@ 95 97 cmd_strip_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \ 96 - $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $@ 98 + $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $@ 97 99 98 100 targets += vmlinux 99 101 vmlinux: vmlinux.unstripped FORCE
+3
scripts/mksysmap
··· 59 59 # EXPORT_SYMBOL (namespace) 60 60 / __kstrtabns_/d 61 61 62 + # MODULE_DEVICE_TABLE (symbol name) 63 + / __mod_device_table__/d 64 + 62 65 # --------------------------------------------------------------------------- 63 66 # Ignored suffixes 64 67 # (do not forget '$' after each pattern)
+18 -1
scripts/mod/file2alias.c
··· 1477 1477 void *symval; 1478 1478 char *zeros = NULL; 1479 1479 const char *type, *name, *modname; 1480 - size_t typelen; 1480 + size_t typelen, modnamelen; 1481 1481 static const char *prefix = "__mod_device_table__"; 1482 1482 1483 1483 /* We're looking for a section relative symbol */ ··· 1500 1500 type = strstr(modname, "__"); 1501 1501 if (!type) 1502 1502 return; 1503 + modnamelen = type - modname; 1503 1504 type += strlen("__"); 1504 1505 1505 1506 name = strstr(type, "__"); ··· 1524 1523 do_table(name, symval, sym->st_size, p->id_size, 1525 1524 p->device_id, p->do_entry, mod); 1526 1525 break; 1526 + } 1527 + } 1528 + 1529 + if (mod->is_vmlinux) { 1530 + struct module_alias *alias; 1531 + 1532 + /* 1533 + * If this is vmlinux, record the name of the builtin module. 1534 + * Traverse the linked list in the reverse order, and set the 1535 + * builtin_modname unless it has already been set in the 1536 + * previous call. 1537 + */ 1538 + list_for_each_entry_reverse(alias, &mod->aliases, node) { 1539 + if (alias->builtin_modname) 1540 + break; 1541 + alias->builtin_modname = xstrndup(modname, modnamelen); 1527 1542 } 1528 1543 } 1529 1544
+15
scripts/mod/modpost.c
··· 2067 2067 static void write_vmlinux_export_c_file(struct module *mod) 2068 2068 { 2069 2069 struct buffer buf = { }; 2070 + struct module_alias *alias, *next; 2070 2071 2071 2072 buf_printf(&buf, 2072 2073 "#include <linux/export-internal.h>\n"); 2073 2074 2074 2075 add_exported_symbols(&buf, mod); 2076 + 2077 + buf_printf(&buf, 2078 + "#include <linux/module.h>\n" 2079 + "#undef __MODULE_INFO_PREFIX\n" 2080 + "#define __MODULE_INFO_PREFIX\n"); 2081 + 2082 + list_for_each_entry_safe(alias, next, &mod->aliases, node) { 2083 + buf_printf(&buf, "MODULE_INFO(%s.alias, \"%s\");\n", 2084 + alias->builtin_modname, alias->str); 2085 + list_del(&alias->node); 2086 + free(alias->builtin_modname); 2087 + free(alias); 2088 + } 2089 + 2075 2090 write_if_changed(&buf, ".vmlinux.export.c"); 2076 2091 free(buf.p); 2077 2092 }
+2
scripts/mod/modpost.h
··· 99 99 * struct module_alias - auto-generated MODULE_ALIAS() 100 100 * 101 101 * @node: linked to module::aliases 102 + * @modname: name of the builtin module (only for vmlinux) 102 103 * @str: a string for MODULE_ALIAS() 103 104 */ 104 105 struct module_alias { 105 106 struct list_head node; 107 + char *builtin_modname; 106 108 char str[]; 107 109 }; 108 110