]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
modpost: Create modalias for builtin modules
authorAlexey Gladkov <legion@kernel.org>
Thu, 18 Sep 2025 08:05:51 +0000 (10:05 +0200)
committerNathan Chancellor <nathan@kernel.org>
Wed, 24 Sep 2025 16:10:45 +0000 (09:10 -0700)
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>
include/linux/module.h
scripts/Makefile.vmlinux
scripts/mksysmap
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/mod/modpost.h

index e31ee29fac6b755464713d9e8aa4a604b30a24b2..e135cc79aceeafa9eca41e6d7efd411529c771ad 100644 (file)
@@ -256,14 +256,10 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name);
        __PASTE(type,                   \
        __PASTE(__, name)))))
 
-#ifdef MODULE
 /* Creates an alias so file2alias.c can find device table. */
 #define MODULE_DEVICE_TABLE(type, name)                                        \
 static typeof(name) __mod_device_table(type, name)                     \
   __attribute__ ((used, alias(__stringify(name))))
-#else  /* !MODULE */
-#define MODULE_DEVICE_TABLE(type, name)
-#endif
 
 /* Version of form [<epoch>:]<version>[-<extra-version>].
  * Or for CVS/RCS ID version, everything but the number is stripped.
index ce79461714979c07ac5a535462185a380d089188..1e5e37aadcd058d252da8857db1286b3c6f77c89 100644 (file)
@@ -89,11 +89,13 @@ endif
 remove-section-y                                   := .modinfo
 remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
 
+remove-symbols := -w --strip-symbol='__mod_device_table__*'
+
 # To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy,
 # it is necessary to remove the PT_LOAD flag from the segment.
 quiet_cmd_strip_relocs = OBJCOPY $@
       cmd_strip_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
-                         $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $@
+                         $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $@
 
 targets += vmlinux
 vmlinux: vmlinux.unstripped FORCE
index a607a0059d119e76d1a9fd3b3bc1a226156a7bca..c4531eacde202061e4f94bcc74c7aea7e2fc50a6 100755 (executable)
@@ -59,6 +59,9 @@
 # EXPORT_SYMBOL (namespace)
 / __kstrtabns_/d
 
+# MODULE_DEVICE_TABLE (symbol name)
+/ __mod_device_table__/d
+
 # ---------------------------------------------------------------------------
 # Ignored suffixes
 #  (do not forget '$' after each pattern)
index 1260bc2287fba5eda236695f5d71b42603f5499f..7da9735e7ab3e51d7ca447297ae3753bf34eb773 100644 (file)
@@ -1477,7 +1477,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
        void *symval;
        char *zeros = NULL;
        const char *type, *name, *modname;
-       size_t typelen;
+       size_t typelen, modnamelen;
        static const char *prefix = "__mod_device_table__";
 
        /* We're looking for a section relative symbol */
@@ -1500,6 +1500,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
        type = strstr(modname, "__");
        if (!type)
                return;
+       modnamelen = type - modname;
        type += strlen("__");
 
        name = strstr(type, "__");
@@ -1526,5 +1527,21 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                }
        }
 
+       if (mod->is_vmlinux) {
+               struct module_alias *alias;
+
+               /*
+                * If this is vmlinux, record the name of the builtin module.
+                * Traverse the linked list in the reverse order, and set the
+                * builtin_modname unless it has already been set in the
+                * previous call.
+                */
+               list_for_each_entry_reverse(alias, &mod->aliases, node) {
+                       if (alias->builtin_modname)
+                               break;
+                       alias->builtin_modname = xstrndup(modname, modnamelen);
+               }
+       }
+
        free(zeros);
 }
index 5ca7c268294ebb65acb0ba52a671eddca9279c61..47c8aa2a69392509b380ec6f22372232f26540da 100644 (file)
@@ -2067,11 +2067,26 @@ static void write_if_changed(struct buffer *b, const char *fname)
 static void write_vmlinux_export_c_file(struct module *mod)
 {
        struct buffer buf = { };
+       struct module_alias *alias, *next;
 
        buf_printf(&buf,
                   "#include <linux/export-internal.h>\n");
 
        add_exported_symbols(&buf, mod);
+
+       buf_printf(&buf,
+                  "#include <linux/module.h>\n"
+                  "#undef __MODULE_INFO_PREFIX\n"
+                  "#define __MODULE_INFO_PREFIX\n");
+
+       list_for_each_entry_safe(alias, next, &mod->aliases, node) {
+               buf_printf(&buf, "MODULE_INFO(%s.alias, \"%s\");\n",
+                          alias->builtin_modname, alias->str);
+               list_del(&alias->node);
+               free(alias->builtin_modname);
+               free(alias);
+       }
+
        write_if_changed(&buf, ".vmlinux.export.c");
        free(buf.p);
 }
index 9133e4c3803f041ab8462452e3a2a31f674d5b01..2aecb8f25c87ec8837ae8b9e476227ad53b5c7d2 100644 (file)
@@ -99,10 +99,12 @@ buf_write(struct buffer *buf, const char *s, int len);
  * struct module_alias - auto-generated MODULE_ALIAS()
  *
  * @node: linked to module::aliases
+ * @modname: name of the builtin module (only for vmlinux)
  * @str: a string for MODULE_ALIAS()
  */
 struct module_alias {
        struct list_head node;
+       char *builtin_modname;
        char str[];
 };