[PATCH v8 7/8] modpost: Create modalias for builtin modules

Alexey Gladkov posted 8 patches 4 months, 3 weeks ago
[PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Alexey Gladkov 4 months, 3 weeks ago
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>
---
 include/linux/module.h   |  4 ----
 scripts/Makefile.vmlinux |  4 +++-
 scripts/mksysmap         |  3 +++
 scripts/mod/file2alias.c | 19 ++++++++++++++++++-
 scripts/mod/modpost.c    | 15 +++++++++++++++
 scripts/mod/modpost.h    |  2 ++
 6 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/include/linux/module.h b/include/linux/module.h
index e31ee29fac6b7..e135cc79aceea 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -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.
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index ce79461714979..1e5e37aadcd05 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -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
diff --git a/scripts/mksysmap b/scripts/mksysmap
index a607a0059d119..c4531eacde202 100755
--- a/scripts/mksysmap
+++ b/scripts/mksysmap
@@ -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)
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 1260bc2287fba..7da9735e7ab3e 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -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);
 }
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 5ca7c268294eb..47c8aa2a69392 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -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);
 }
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 9133e4c3803f0..2aecb8f25c87e 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -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[];
 };
 
-- 
2.51.0
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Charles Mirabile 4 months ago
On Thu, Sep 18, 2025 at 10:05:51AM +0200, Alexey Gladkov wrote:
> 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.

Hi -

This patch broke RISC-V builds for me. During the final objcopy where the new
symbols are supposed to be stripped, an error occurs producing lots of error
messages similar to this one:

riscv64-linux-gnu-objcopy: not stripping symbol `__mod_device_table__...'
because it is named in a relocation

It does not occur using defconfig, but I was able to bisect my way to this
commit and then reduce my config delta w.r.t defconfig until I landed on:

cat > .config <<'EOF'
CONFIG_RELOCATABLE=y
CONFIG_KASAN=y
EOF
ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- make olddefconfig
ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- make -j $(nproc)
...
  LD      vmlinux.unstripped
  NM      System.map
  SORTTAB vmlinux.unstripped
  CHKREL  vmlinux.unstripped
  OBJCOPY vmlinux
  OBJCOPY modules.builtin.modinfo
  GEN     modules.builtin
riscv64-linux-gnu-objcopy: not stripping symbol `<long symbol name>'
because it is named in a relocation
<repeats with different symbol names about a dozen times>
make[3]: *** [scripts/Makefile.vmlinux:97: vmlinux] Error 1
make[3]: *** Deleting file 'vmlinux'
make[2]: *** [Makefile:1242: vmlinux] Error 2
make[1]: *** [/tmp/linux/Makefile:369: __build_one_by_one] Error 2
make: *** [Makefile:248: __sub-make] Error 2

I confirmed that reverting this commit fixes the issue.

> 
> 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>
> ---
>  include/linux/module.h   |  4 ----
>  scripts/Makefile.vmlinux |  4 +++-
>  scripts/mksysmap         |  3 +++
>  scripts/mod/file2alias.c | 19 ++++++++++++++++++-
>  scripts/mod/modpost.c    | 15 +++++++++++++++
>  scripts/mod/modpost.h    |  2 ++
>  6 files changed, 41 insertions(+), 6 deletions(-)
> 
> diff --git a/include/linux/module.h b/include/linux/module.h
> index e31ee29fac6b7..e135cc79aceea 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -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.
> diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
> index ce79461714979..1e5e37aadcd05 100644
> --- a/scripts/Makefile.vmlinux
> +++ b/scripts/Makefile.vmlinux
> @@ -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
> diff --git a/scripts/mksysmap b/scripts/mksysmap
> index a607a0059d119..c4531eacde202 100755
> --- a/scripts/mksysmap
> +++ b/scripts/mksysmap
> @@ -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)
> diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
> index 1260bc2287fba..7da9735e7ab3e 100644
> --- a/scripts/mod/file2alias.c
> +++ b/scripts/mod/file2alias.c
> @@ -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);
>  }
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index 5ca7c268294eb..47c8aa2a69392 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -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);
>  }
> diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> index 9133e4c3803f0..2aecb8f25c87e 100644
> --- a/scripts/mod/modpost.h
> +++ b/scripts/mod/modpost.h
> @@ -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[];
>  };
>  
> -- 
> 2.51.0
>
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Alexey Gladkov 4 months ago
On Mon, Oct 06, 2025 at 09:16:37PM -0400, Charles Mirabile wrote:
> On Thu, Sep 18, 2025 at 10:05:51AM +0200, Alexey Gladkov wrote:
> > 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.
> 
> Hi -
> 
> This patch broke RISC-V builds for me. During the final objcopy where the new
> symbols are supposed to be stripped, an error occurs producing lots of error
> messages similar to this one:
> 
> riscv64-linux-gnu-objcopy: not stripping symbol `__mod_device_table__...'
> because it is named in a relocation
> 
> It does not occur using defconfig, but I was able to bisect my way to this
> commit and then reduce my config delta w.r.t defconfig until I landed on:
> 
> cat > .config <<'EOF'
> CONFIG_RELOCATABLE=y
> CONFIG_KASAN=y
> EOF
> ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- make olddefconfig
> ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- make -j $(nproc)
> ...
>   LD      vmlinux.unstripped
>   NM      System.map
>   SORTTAB vmlinux.unstripped
>   CHKREL  vmlinux.unstripped
>   OBJCOPY vmlinux
>   OBJCOPY modules.builtin.modinfo
>   GEN     modules.builtin
> riscv64-linux-gnu-objcopy: not stripping symbol `<long symbol name>'
> because it is named in a relocation
> <repeats with different symbol names about a dozen times>
> make[3]: *** [scripts/Makefile.vmlinux:97: vmlinux] Error 1
> make[3]: *** Deleting file 'vmlinux'
> make[2]: *** [Makefile:1242: vmlinux] Error 2
> make[1]: *** [/tmp/linux/Makefile:369: __build_one_by_one] Error 2
> make: *** [Makefile:248: __sub-make] Error 2
> 
> I confirmed that reverting this commit fixes the issue.

Hm. Indeed. I haven't found a good solution yet, but you can use the
following patch to unlock compilation. It won't solve the problem, it will
only hide it.

--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -84,7 +84,7 @@ endif
 remove-section-y                                   := .modinfo
 remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'

-remove-symbols := -w --strip-symbol='__mod_device_table__*'
+remove-symbols := -w --strip-unneeded-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.

> > 
> > 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>
> > ---
> >  include/linux/module.h   |  4 ----
> >  scripts/Makefile.vmlinux |  4 +++-
> >  scripts/mksysmap         |  3 +++
> >  scripts/mod/file2alias.c | 19 ++++++++++++++++++-
> >  scripts/mod/modpost.c    | 15 +++++++++++++++
> >  scripts/mod/modpost.h    |  2 ++
> >  6 files changed, 41 insertions(+), 6 deletions(-)
> > 
> > diff --git a/include/linux/module.h b/include/linux/module.h
> > index e31ee29fac6b7..e135cc79aceea 100644
> > --- a/include/linux/module.h
> > +++ b/include/linux/module.h
> > @@ -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.
> > diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
> > index ce79461714979..1e5e37aadcd05 100644
> > --- a/scripts/Makefile.vmlinux
> > +++ b/scripts/Makefile.vmlinux
> > @@ -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
> > diff --git a/scripts/mksysmap b/scripts/mksysmap
> > index a607a0059d119..c4531eacde202 100755
> > --- a/scripts/mksysmap
> > +++ b/scripts/mksysmap
> > @@ -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)
> > diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
> > index 1260bc2287fba..7da9735e7ab3e 100644
> > --- a/scripts/mod/file2alias.c
> > +++ b/scripts/mod/file2alias.c
> > @@ -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);
> >  }
> > diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> > index 5ca7c268294eb..47c8aa2a69392 100644
> > --- a/scripts/mod/modpost.c
> > +++ b/scripts/mod/modpost.c
> > @@ -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);
> >  }
> > diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> > index 9133e4c3803f0..2aecb8f25c87e 100644
> > --- a/scripts/mod/modpost.h
> > +++ b/scripts/mod/modpost.h
> > @@ -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[];
> >  };
> >  
> > -- 
> > 2.51.0
> > 
> 

-- 
Rgrds, legion
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Nicolas Schier 4 months ago
On Tue, Oct 07, 2025 at 12:15:21PM +0200, Alexey Gladkov wrote:
> On Mon, Oct 06, 2025 at 09:16:37PM -0400, Charles Mirabile wrote:
> > On Thu, Sep 18, 2025 at 10:05:51AM +0200, Alexey Gladkov wrote:
> > > 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.
> > 
> > Hi -
> > 
> > This patch broke RISC-V builds for me. During the final objcopy where the new
> > symbols are supposed to be stripped, an error occurs producing lots of error
> > messages similar to this one:
> > 
> > riscv64-linux-gnu-objcopy: not stripping symbol `__mod_device_table__...'
> > because it is named in a relocation
> > 
> > It does not occur using defconfig, but I was able to bisect my way to this
> > commit and then reduce my config delta w.r.t defconfig until I landed on:
> > 
> > cat > .config <<'EOF'
> > CONFIG_RELOCATABLE=y
> > CONFIG_KASAN=y
> > EOF
> > ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- make olddefconfig
> > ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- make -j $(nproc)
> > ...
> >   LD      vmlinux.unstripped
> >   NM      System.map
> >   SORTTAB vmlinux.unstripped
> >   CHKREL  vmlinux.unstripped
> >   OBJCOPY vmlinux
> >   OBJCOPY modules.builtin.modinfo
> >   GEN     modules.builtin
> > riscv64-linux-gnu-objcopy: not stripping symbol `<long symbol name>'
> > because it is named in a relocation
> > <repeats with different symbol names about a dozen times>
> > make[3]: *** [scripts/Makefile.vmlinux:97: vmlinux] Error 1
> > make[3]: *** Deleting file 'vmlinux'
> > make[2]: *** [Makefile:1242: vmlinux] Error 2
> > make[1]: *** [/tmp/linux/Makefile:369: __build_one_by_one] Error 2
> > make: *** [Makefile:248: __sub-make] Error 2
> > 
> > I confirmed that reverting this commit fixes the issue.

Thanks for the report!

> 
> Hm. Indeed. I haven't found a good solution yet, but you can use the
> following patch to unlock compilation. It won't solve the problem, it will
> only hide it.
> 
> --- a/scripts/Makefile.vmlinux
> +++ b/scripts/Makefile.vmlinux
> @@ -84,7 +84,7 @@ endif
>  remove-section-y                                   := .modinfo
>  remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
> 
> -remove-symbols := -w --strip-symbol='__mod_device_table__*'
> +remove-symbols := -w --strip-unneeded-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.
> 

Is it problematic to hide that?  Otherwise we'd have to revert the
patch, right?

Kind regards,
Nicolas
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Nathan Chancellor 4 months ago
On Thu, Oct 09, 2025 at 09:52:08PM +0200, Nicolas Schier wrote:
> On Tue, Oct 07, 2025 at 12:15:21PM +0200, Alexey Gladkov wrote:
> > Hm. Indeed. I haven't found a good solution yet, but you can use the
> > following patch to unlock compilation. It won't solve the problem, it will
> > only hide it.
> > 
> > --- a/scripts/Makefile.vmlinux
> > +++ b/scripts/Makefile.vmlinux
> > @@ -84,7 +84,7 @@ endif
> >  remove-section-y                                   := .modinfo
> >  remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
> > 
> > -remove-symbols := -w --strip-symbol='__mod_device_table__*'
> > +remove-symbols := -w --strip-unneeded-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.
> > 
> 
> Is it problematic to hide that?  Otherwise we'd have to revert the
> patch, right?

Yeah, I would much prefer to ending up with pointless
__mod_device_table__ symbols in the final binary than erroring out
during the build... Does this happen with other architectures? I have
not seen any reports yet but I have not tested anything yet. Why is
RISC-V special here?

It seems like the relocation comes from the .LASANLOC4 symbol in
.data.rel.local?

  $ llvm-objdump -Dr drivers/irqchip/irq-riscv-aplic-main.o
  ...
  Disassembly of section .data.rel.local:
  ...
  0000000000000130 <.LASANLOC4>:
  ...
       1c0: 0000          unimp
          00000000000001c0:  R_RISCV_64   __mod_device_table__kmod_irq_riscv_aplic_main__acpi__aplic_acpi_match
  ...

I cannot find much information about this ASANLOC outside of its
location within the GCC sources, do we even need it? I don't see a way
to opt out of this section altogether or on a per-variable basis, I
wonder if there is some way to strip it out...

I plan to send the initial 6.18 Kbuild fixes pull request on Saturday.
If we cannot figure out a real solution before then, maybe we can just
switch to '--strip-unneeded-symbol' with a comment to upgrade that to
'--strip-symbol' when possible?

Cheers,
Nathan
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Charles Mirabile 4 months ago
On Fri, Oct 10, 2025 at 1:37 AM Nathan Chancellor <nathan@kernel.org> wrote:
>
> On Thu, Oct 09, 2025 at 09:52:08PM +0200, Nicolas Schier wrote:
> > On Tue, Oct 07, 2025 at 12:15:21PM +0200, Alexey Gladkov wrote:
> > > Hm. Indeed. I haven't found a good solution yet, but you can use the
> > > following patch to unlock compilation. It won't solve the problem, it will
> > > only hide it.
> > >
> > > --- a/scripts/Makefile.vmlinux
> > > +++ b/scripts/Makefile.vmlinux
> > > @@ -84,7 +84,7 @@ endif
> > >  remove-section-y                                   := .modinfo
> > >  remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
> > >
> > > -remove-symbols := -w --strip-symbol='__mod_device_table__*'
> > > +remove-symbols := -w --strip-unneeded-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.
> > >
> >
> > Is it problematic to hide that?  Otherwise we'd have to revert the
> > patch, right?
>
> Yeah, I would much prefer to ending up with pointless
> __mod_device_table__ symbols in the final binary than erroring out
> during the build... Does this happen with other architectures? I have
> not seen any reports yet but I have not tested anything yet. Why is
> RISC-V special here?
>
> It seems like the relocation comes from the .LASANLOC4 symbol in
> .data.rel.local?
>
>   $ llvm-objdump -Dr drivers/irqchip/irq-riscv-aplic-main.o
>   ...
>   Disassembly of section .data.rel.local:
>   ...
>   0000000000000130 <.LASANLOC4>:
>   ...
>        1c0: 0000          unimp
>           00000000000001c0:  R_RISCV_64   __mod_device_table__kmod_irq_riscv_aplic_main__acpi__aplic_acpi_match
>   ...
>
> I cannot find much information about this ASANLOC outside of its
> location within the GCC sources, do we even need it? I don't see a way
> to opt out of this section altogether or on a per-variable basis, I
> wonder if there is some way to strip it out...

It seems from reading the gcc source that these are emitted to contain
information about where global declarations came from, presumably to
allow nicer ASAN error messages. (i.e. memory corruption affected this
symbol defined here). I don't think that KASAN uses these, but I am
not sure. I also don't know how they could be removed. I found a hit
using grep.app https://grep.app/search?case=true&q=ASANLOC in the
apache/nuttx repository where they seem to be doing something with
these symbols in a linker script, but I am not familiar enough with
linker scripts, or that project to fully understand what is going on.


>
> I plan to send the initial 6.18 Kbuild fixes pull request on Saturday.
> If we cannot figure out a real solution before then, maybe we can just
> switch to '--strip-unneeded-symbol' with a comment to upgrade that to
> '--strip-symbol' when possible?
>
> Cheers,
> Nathan
>
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Alexey Gladkov 4 months ago
On Thu, Oct 09, 2025 at 10:37:36PM -0700, Nathan Chancellor wrote:
> On Thu, Oct 09, 2025 at 09:52:08PM +0200, Nicolas Schier wrote:
> > On Tue, Oct 07, 2025 at 12:15:21PM +0200, Alexey Gladkov wrote:
> > > Hm. Indeed. I haven't found a good solution yet, but you can use the
> > > following patch to unlock compilation. It won't solve the problem, it will
> > > only hide it.
> > > 
> > > --- a/scripts/Makefile.vmlinux
> > > +++ b/scripts/Makefile.vmlinux
> > > @@ -84,7 +84,7 @@ endif
> > >  remove-section-y                                   := .modinfo
> > >  remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
> > > 
> > > -remove-symbols := -w --strip-symbol='__mod_device_table__*'
> > > +remove-symbols := -w --strip-unneeded-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.
> > > 
> > 
> > Is it problematic to hide that?  Otherwise we'd have to revert the
> > patch, right?
> 
> Yeah, I would much prefer to ending up with pointless
> __mod_device_table__ symbols in the final binary than erroring out
> during the build...

This is a very unpleasant problem, but it does not seem fatal. There will
not be many such characters in the final vmlinux. In the configuration
from the bug report, there are only:

$ nm vmlinux.unstripped.riscv |grep -c __mod_device_table__
17

Of course, this does not mean that the problem does not need to be solved.

> Does this happen with other architectures? I have
> not seen any reports yet but I have not tested anything yet.

LDFLAGS_vmlinux for riscv was taken from arm64. I suspect that there may
be the same problem there. But I haven't checked yet whether the problem
actually exists on arm64.

> Why is RISC-V special here?

This problem on riscv only occurs when CONFIG_RELOCATABLE=y is specified.
Without this parameter, everything will compile as expected.
 
> It seems like the relocation comes from the .LASANLOC4 symbol in
> .data.rel.local?
> 
>   $ llvm-objdump -Dr drivers/irqchip/irq-riscv-aplic-main.o
>   ...
>   Disassembly of section .data.rel.local:
>   ...
>   0000000000000130 <.LASANLOC4>:
>   ...
>        1c0: 0000          unimp
>           00000000000001c0:  R_RISCV_64   __mod_device_table__kmod_irq_riscv_aplic_main__acpi__aplic_acpi_match
>   ...
> 
> I cannot find much information about this ASANLOC outside of its
> location within the GCC sources, do we even need it? I don't see a way
> to opt out of this section altogether or on a per-variable basis, I
> wonder if there is some way to strip it out...

The aplic_acpi_match structure is indeed used, but they are used
themselves, not their alias, which is generated by the MODULE_DEVICE_TABLE
macro.

I also asked the guys from binutils for help:

https://sourceware.org/pipermail/binutils/2025-October/144782.html

> I plan to send the initial 6.18 Kbuild fixes pull request on Saturday.
> If we cannot figure out a real solution before then, maybe we can just
> switch to '--strip-unneeded-symbol' with a comment to upgrade that to
> '--strip-symbol' when possible?

Yes, that would be great.



Maybe I'm looking in the wrong direction, but still.

On riscv:

* with CONFIG_RELOCATABLE=y (where the error appears):

vmlinux.unstripped: ELF 64-bit LSB shared object, UCB RISC-V, RVC, soft-float ABI, version 1 (SYSV), dynamically linked, not stripped

* without CONFIG_RELOCATABLE:

vmlinux.unstripped: ELF 64-bit LSB executable, UCB RISC-V, RVC, soft-float ABI, version 1 (SYSV), statically linked, not stripped

On x64_64:

* with and without CONFIG_RELOCATABLE=y:

vmlinux.unstripped: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

-- 
Rgrds, legion
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Alexey Gladkov 4 months ago
On Fri, Oct 10, 2025 at 10:02:20AM +0200, Alexey Gladkov wrote:
> On Thu, Oct 09, 2025 at 10:37:36PM -0700, Nathan Chancellor wrote:
> > On Thu, Oct 09, 2025 at 09:52:08PM +0200, Nicolas Schier wrote:
> > > On Tue, Oct 07, 2025 at 12:15:21PM +0200, Alexey Gladkov wrote:
> > > > Hm. Indeed. I haven't found a good solution yet, but you can use the
> > > > following patch to unlock compilation. It won't solve the problem, it will
> > > > only hide it.
> > > > 
> > > > --- a/scripts/Makefile.vmlinux
> > > > +++ b/scripts/Makefile.vmlinux
> > > > @@ -84,7 +84,7 @@ endif
> > > >  remove-section-y                                   := .modinfo
> > > >  remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*'
> > > > 
> > > > -remove-symbols := -w --strip-symbol='__mod_device_table__*'
> > > > +remove-symbols := -w --strip-unneeded-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.
> > > > 
> > > 
> > > Is it problematic to hide that?  Otherwise we'd have to revert the
> > > patch, right?
> > 
> > Yeah, I would much prefer to ending up with pointless
> > __mod_device_table__ symbols in the final binary than erroring out
> > during the build...
> 
> This is a very unpleasant problem, but it does not seem fatal. There will
> not be many such characters in the final vmlinux. In the configuration
> from the bug report, there are only:
> 
> $ nm vmlinux.unstripped.riscv |grep -c __mod_device_table__
> 17
> 
> Of course, this does not mean that the problem does not need to be solved.
> 
> > Does this happen with other architectures? I have
> > not seen any reports yet but I have not tested anything yet.
> 
> LDFLAGS_vmlinux for riscv was taken from arm64. I suspect that there may
> be the same problem there. But I haven't checked yet whether the problem
> actually exists on arm64.

I tried to compile the kernel for arm64 with CONFIG_RELOCATABLE=y.
It works without errors and the symbols are removed.

vmlinux.unstripped: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped

-- 
Rgrds, legion
Re: [PATCH v8 7/8] modpost: Create modalias for builtin modules
Posted by Nicolas Schier 4 months, 2 weeks ago
On Thu, Sep 18, 2025 at 10:05:51AM +0200, Alexey Gladkov wrote:
> 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>
> ---
>  include/linux/module.h   |  4 ----
>  scripts/Makefile.vmlinux |  4 +++-
>  scripts/mksysmap         |  3 +++
>  scripts/mod/file2alias.c | 19 ++++++++++++++++++-
>  scripts/mod/modpost.c    | 15 +++++++++++++++
>  scripts/mod/modpost.h    |  2 ++
>  6 files changed, 41 insertions(+), 6 deletions(-)
> 

Reviewed-by: Nicolas Schier <nsc@kernel.org>

-- 
Nicolas