diff mbox series

[v6,01/10] modpost: extract symbol versions from *.cmd files

Message ID 20220513113930.10488-2-masahiroy@kernel.org (mailing list archive)
State New, archived
Headers show
Series kbuild: yet another series of cleanups (modpost, LTO, MODULE_REL_CRCS, export.h) | expand

Commit Message

Masahiro Yamada May 13, 2022, 11:39 a.m. UTC
Currently, CONFIG_MODVERSIONS needs extra link to embed the symbol
versions into ELF objects. Then, modpost extracts the version CRCs
from them.

The following figures show how it currently works, and how I am trying
to change it.

Current implementation
======================
                                                           |----------|
                 embed CRC      -------------------------->| final    |
       $(CC)       $(LD)       /  |---------|              | link for |
       -----> *.o -------> *.o -->| modpost |              | vmlinux  |
      /              /            |         |-- *.mod.c -->| or       |
     / genksyms     /             |---------|              | module   |
  *.c ------> *.symversions                                |----------|

Genksyms outputs the calculated CRCs in the form of linker script
(*.symversions), which is used by $(LD) to update the object.

If CONFIG_LTO_CLANG=y, the build process is much more complex. Embedding
the CRCs is postponed until the LLVM bitcode is converted into ELF,
creating another intermediate *.prelink.o.

However, this complexity is unneeded. There is no reason why we must
embed version CRCs in objects so early.

There is final link stage for vmlinux (scripts/link-vmlinux.sh) and
modules (scripts/Makefile.modfinal). We can link CRCs at the very last
moment.

New implementation
==================
                                                           |----------|
                   --------------------------------------->| final    |
       $(CC)      /    |---------|                         | link for |
       -----> *.o ---->|         |                         | vmlinux  |
      /                | modpost |--- .vmlinux.export.c -->| or       |
     / genksyms        |         |--- *.mod.c ------------>| module   |
  *.c ------> *.cmd -->|---------|                         |----------|

Pass the symbol versions to modpost as separate text data, which are
available in *.cmd files.

This commit changes modpost to extract CRCs from *.cmd files instead of
from ELF objects.

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
Reviewed-by: Nicolas Schier <nicolas@fjasle.eu>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
---

Changes in v6:
  - Fix false-positive warnings when CONFIG_TRIM_UNUSED_KSYMS=y

Changes in v2:
  - Simplify the implementation (parse .cmd files after ELF)

 scripts/mod/modpost.c | 179 +++++++++++++++++++++++++++++++-----------
 1 file changed, 131 insertions(+), 48 deletions(-)

Comments

Guenter Roeck May 28, 2022, 10:47 p.m. UTC | #1
Hi,

On Fri, May 13, 2022 at 08:39:21PM +0900, Masahiro Yamada wrote:
> Currently, CONFIG_MODVERSIONS needs extra link to embed the symbol
> versions into ELF objects. Then, modpost extracts the version CRCs
> from them.
> 
[ ... ]
> This commit changes modpost to extract CRCs from *.cmd files instead of
> from ELF objects.
> 
> Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
> Reviewed-by: Nicolas Schier <nicolas@fjasle.eu>
> Tested-by: Nathan Chancellor <nathan@kernel.org>
> Reviewed-by: Sami Tolvanen <samitolvanen@google.com>

This patch results in

._muldi3_di.o.cmd: No such file or directory

when building parisc64:defconfig, and

._divsi3.o.cmd: No such file or directory

when building csky:allmodconfig.

Reverting this patch (and the subsequent kbuild patches to avoid
conflicts) fixes the problem for both architectures. In case it
helps, the complete build log when rebuilding an image for csky
is as follows.

#
# No change to .config
#
  HOSTCC  scripts/mod/modpost.o
  HOSTLD  scripts/mod/modpost
  CALL    scripts/atomic/check-atomics.sh
  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  SO2S    arch/csky/kernel/vdso/vdso-syms.S
  AS      arch/csky/kernel/vdso/vdso-syms.o
  AR      arch/csky/kernel/vdso/built-in.a
  AR      arch/csky/kernel/built-in.a
  CHK     kernel/kheaders_data.tar.xz
  GEN     .version
  CHK     include/generated/compile.h
  UPD     include/generated/compile.h
  CC      init/version.o
  AR      init/built-in.a
  LD      vmlinux.o
  MODPOST vmlinux.symvers
._divsi3.o.cmd: No such file or directory
make[1]: *** [scripts/Makefile.modpost:59: vmlinux.symvers] Error 1
make: *** [Makefile:1159: vmlinux] Error 2

This was seen with gcc 11.2 and 11.3.

Guenter

---
bisect on mainline:

# bad: [9d004b2f4fea97cde123e7f1939b80e77bf2e695] Merge tag 'cxl-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
# good: [4b0986a3613c92f4ec1bdc7f60ec66fea135991f] Linux 5.18
git bisect start 'HEAD' 'v5.18'
# good: [86c87bea6b42100c67418af690919c44de6ede6e] Merge tag 'devicetree-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
git bisect good 86c87bea6b42100c67418af690919c44de6ede6e
# good: [c011dd537ffe47462051930413fed07dbdc80313] Merge tag 'arm-soc-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
git bisect good c011dd537ffe47462051930413fed07dbdc80313
# bad: [df202b452fe6c6d6f1351bad485e2367ef1e644e] Merge tag 'kbuild-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild
git bisect bad df202b452fe6c6d6f1351bad485e2367ef1e644e
# good: [d4dcdc53c492a7b9fa9031cb85e238b21208ada2] Merge tag 'qcom-arm64-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/dt
git bisect good d4dcdc53c492a7b9fa9031cb85e238b21208ada2
# good: [ae862183285cbb2ef9032770d98ffa9becffe9d5] Merge tag 'arm-dt-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
git bisect good ae862183285cbb2ef9032770d98ffa9becffe9d5
# good: [cc3c470ae4ad758b8ddad825ab199f7eaa8b0a9e] Merge tag 'arm-drivers-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
git bisect good cc3c470ae4ad758b8ddad825ab199f7eaa8b0a9e
# good: [ecf0aa5317b0ad6bb015128a5b763c954fd58708] Merge tag 'arm-multiplatform-5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
git bisect good ecf0aa5317b0ad6bb015128a5b763c954fd58708
# good: [4484054816cab940fc2fde23fa989174fec889d0] modpost: use doubly linked list for dump_lists
git bisect good 4484054816cab940fc2fde23fa989174fec889d0
# good: [16477cdfefdb494235a675cc80563d736991d833] Merge tag 'asm-generic-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic
git bisect good 16477cdfefdb494235a675cc80563d736991d833
# good: [a44abaca0e196cfeef2374ed663b97daa1ad112a] modpost: move *.mod.c generation to write_mod_c_files()
git bisect good a44abaca0e196cfeef2374ed663b97daa1ad112a
# good: [69c4cc99bbcbf3ef2e1901b569954e9226180840] modpost: add sym_find_with_module() helper
git bisect good 69c4cc99bbcbf3ef2e1901b569954e9226180840
# bad: [7b4537199a4a8480b8c3ba37a2d44765ce76cd9b] kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS
git bisect bad 7b4537199a4a8480b8c3ba37a2d44765ce76cd9b
# bad: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files
git bisect bad f292d875d0dc700b3af0bef04c5abc1dc7b3b62c
# first bad commit: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files

---
bisect on kbuild-5.19:

# bad: [5ce2176b81f77366bd02c27509b83049f0020544] genksyms: adjust the output format to modpost
# good: [3123109284176b1532874591f7c81f3837bbdc17] Linux 5.18-rc1
git bisect start 'HEAD' 'v5.18-rc1'
# good: [70ddb48db4aaddd3c2a7d8802463e15b21ce8525] modpost: move struct namespace_list to modpost.c
git bisect good 70ddb48db4aaddd3c2a7d8802463e15b21ce8525
# good: [e76cc48d8e6df5d949284132981db73d2dd8c6b5] modpost: make sym_add_exported() always allocate a new symbol
git bisect good e76cc48d8e6df5d949284132981db73d2dd8c6b5
# good: [78e9e56af3858bf2c52c065daa6c8bee0d72048c] kbuild: record symbol versions in *.cmd files
git bisect good 78e9e56af3858bf2c52c065daa6c8bee0d72048c
# good: [69c4cc99bbcbf3ef2e1901b569954e9226180840] modpost: add sym_find_with_module() helper
git bisect good 69c4cc99bbcbf3ef2e1901b569954e9226180840
# bad: [7b4537199a4a8480b8c3ba37a2d44765ce76cd9b] kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS
git bisect bad 7b4537199a4a8480b8c3ba37a2d44765ce76cd9b
# bad: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files
git bisect bad f292d875d0dc700b3af0bef04c5abc1dc7b3b62c
# first bad commit: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files
Masahiro Yamada May 29, 2022, 4:27 a.m. UTC | #2
On Sun, May 29, 2022 at 7:47 AM Guenter Roeck <linux@roeck-us.net> wrote:
>
> Hi,
>
> On Fri, May 13, 2022 at 08:39:21PM +0900, Masahiro Yamada wrote:
> > Currently, CONFIG_MODVERSIONS needs extra link to embed the symbol
> > versions into ELF objects. Then, modpost extracts the version CRCs
> > from them.
> >
> [ ... ]
> > This commit changes modpost to extract CRCs from *.cmd files instead of
> > from ELF objects.
> >
> > Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
> > Reviewed-by: Nicolas Schier <nicolas@fjasle.eu>
> > Tested-by: Nathan Chancellor <nathan@kernel.org>
> > Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
>
> This patch results in
>
> ._muldi3_di.o.cmd: No such file or directory
>
> when building parisc64:defconfig, and
>
> ._divsi3.o.cmd: No such file or directory
>
> when building csky:allmodconfig.
>
> Reverting this patch (and the subsequent kbuild patches to avoid
> conflicts) fixes the problem for both architectures. In case it
> helps, the complete build log when rebuilding an image for csky
> is as follows.



Thank you for the report!

This commit has been in the tree for a while
but I did not get this kind of report from the 0-day bot.

The wide test coverage from your system is very helpful.
I just submitted a fix.

Thank you.









> #
> # No change to .config
> #
>   HOSTCC  scripts/mod/modpost.o
>   HOSTLD  scripts/mod/modpost
>   CALL    scripts/atomic/check-atomics.sh
>   CALL    scripts/checksyscalls.sh
>   CHK     include/generated/compile.h
>   SO2S    arch/csky/kernel/vdso/vdso-syms.S
>   AS      arch/csky/kernel/vdso/vdso-syms.o
>   AR      arch/csky/kernel/vdso/built-in.a
>   AR      arch/csky/kernel/built-in.a
>   CHK     kernel/kheaders_data.tar.xz
>   GEN     .version
>   CHK     include/generated/compile.h
>   UPD     include/generated/compile.h
>   CC      init/version.o
>   AR      init/built-in.a
>   LD      vmlinux.o
>   MODPOST vmlinux.symvers
> ._divsi3.o.cmd: No such file or directory
> make[1]: *** [scripts/Makefile.modpost:59: vmlinux.symvers] Error 1
> make: *** [Makefile:1159: vmlinux] Error 2
>
> This was seen with gcc 11.2 and 11.3.
>
> Guenter
>
> ---
> bisect on mainline:
>
> # bad: [9d004b2f4fea97cde123e7f1939b80e77bf2e695] Merge tag 'cxl-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
> # good: [4b0986a3613c92f4ec1bdc7f60ec66fea135991f] Linux 5.18
> git bisect start 'HEAD' 'v5.18'
> # good: [86c87bea6b42100c67418af690919c44de6ede6e] Merge tag 'devicetree-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
> git bisect good 86c87bea6b42100c67418af690919c44de6ede6e
> # good: [c011dd537ffe47462051930413fed07dbdc80313] Merge tag 'arm-soc-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
> git bisect good c011dd537ffe47462051930413fed07dbdc80313
> # bad: [df202b452fe6c6d6f1351bad485e2367ef1e644e] Merge tag 'kbuild-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild
> git bisect bad df202b452fe6c6d6f1351bad485e2367ef1e644e
> # good: [d4dcdc53c492a7b9fa9031cb85e238b21208ada2] Merge tag 'qcom-arm64-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/dt
> git bisect good d4dcdc53c492a7b9fa9031cb85e238b21208ada2
> # good: [ae862183285cbb2ef9032770d98ffa9becffe9d5] Merge tag 'arm-dt-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
> git bisect good ae862183285cbb2ef9032770d98ffa9becffe9d5
> # good: [cc3c470ae4ad758b8ddad825ab199f7eaa8b0a9e] Merge tag 'arm-drivers-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
> git bisect good cc3c470ae4ad758b8ddad825ab199f7eaa8b0a9e
> # good: [ecf0aa5317b0ad6bb015128a5b763c954fd58708] Merge tag 'arm-multiplatform-5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
> git bisect good ecf0aa5317b0ad6bb015128a5b763c954fd58708
> # good: [4484054816cab940fc2fde23fa989174fec889d0] modpost: use doubly linked list for dump_lists
> git bisect good 4484054816cab940fc2fde23fa989174fec889d0
> # good: [16477cdfefdb494235a675cc80563d736991d833] Merge tag 'asm-generic-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic
> git bisect good 16477cdfefdb494235a675cc80563d736991d833
> # good: [a44abaca0e196cfeef2374ed663b97daa1ad112a] modpost: move *.mod.c generation to write_mod_c_files()
> git bisect good a44abaca0e196cfeef2374ed663b97daa1ad112a
> # good: [69c4cc99bbcbf3ef2e1901b569954e9226180840] modpost: add sym_find_with_module() helper
> git bisect good 69c4cc99bbcbf3ef2e1901b569954e9226180840
> # bad: [7b4537199a4a8480b8c3ba37a2d44765ce76cd9b] kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS
> git bisect bad 7b4537199a4a8480b8c3ba37a2d44765ce76cd9b
> # bad: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files
> git bisect bad f292d875d0dc700b3af0bef04c5abc1dc7b3b62c
> # first bad commit: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files
>
> ---
> bisect on kbuild-5.19:
>
> # bad: [5ce2176b81f77366bd02c27509b83049f0020544] genksyms: adjust the output format to modpost
> # good: [3123109284176b1532874591f7c81f3837bbdc17] Linux 5.18-rc1
> git bisect start 'HEAD' 'v5.18-rc1'
> # good: [70ddb48db4aaddd3c2a7d8802463e15b21ce8525] modpost: move struct namespace_list to modpost.c
> git bisect good 70ddb48db4aaddd3c2a7d8802463e15b21ce8525
> # good: [e76cc48d8e6df5d949284132981db73d2dd8c6b5] modpost: make sym_add_exported() always allocate a new symbol
> git bisect good e76cc48d8e6df5d949284132981db73d2dd8c6b5
> # good: [78e9e56af3858bf2c52c065daa6c8bee0d72048c] kbuild: record symbol versions in *.cmd files
> git bisect good 78e9e56af3858bf2c52c065daa6c8bee0d72048c
> # good: [69c4cc99bbcbf3ef2e1901b569954e9226180840] modpost: add sym_find_with_module() helper
> git bisect good 69c4cc99bbcbf3ef2e1901b569954e9226180840
> # bad: [7b4537199a4a8480b8c3ba37a2d44765ce76cd9b] kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS
> git bisect bad 7b4537199a4a8480b8c3ba37a2d44765ce76cd9b
> # bad: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files
> git bisect bad f292d875d0dc700b3af0bef04c5abc1dc7b3b62c
> # first bad commit: [f292d875d0dc700b3af0bef04c5abc1dc7b3b62c] modpost: extract symbol versions from *.cmd files



--
Best Regards
Masahiro Yamada
diff mbox series

Patch

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index fc5db1f73cf1..213a130d1635 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -381,19 +381,10 @@  static struct symbol *sym_add_exported(const char *name, struct module *mod,
 	return s;
 }
 
-static void sym_set_crc(const char *name, unsigned int crc)
+static void sym_set_crc(struct symbol *sym, unsigned int crc)
 {
-	struct symbol *s = find_symbol(name);
-
-	/*
-	 * Ignore stand-alone __crc_*, which might be auto-generated symbols
-	 * such as __*_veneer in ARM ELF.
-	 */
-	if (!s)
-		return;
-
-	s->crc = crc;
-	s->crc_valid = true;
+	sym->crc = crc;
+	sym->crc_valid = true;
 }
 
 static void *grab_file(const char *filename, size_t *size)
@@ -616,33 +607,6 @@  static int ignore_undef_symbol(struct elf_info *info, const char *symname)
 	return 0;
 }
 
-static void handle_modversion(const struct module *mod,
-			      const struct elf_info *info,
-			      const Elf_Sym *sym, const char *symname)
-{
-	unsigned int crc;
-
-	if (sym->st_shndx == SHN_UNDEF) {
-		warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
-		     "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
-		     symname, mod->name, mod->is_vmlinux ? "" : ".ko",
-		     symname);
-
-		return;
-	}
-
-	if (sym->st_shndx == SHN_ABS) {
-		crc = sym->st_value;
-	} else {
-		unsigned int *crcp;
-
-		/* symbol points to the CRC in the ELF object */
-		crcp = sym_get_data(info, sym);
-		crc = TO_NATIVE(*crcp);
-	}
-	sym_set_crc(symname, crc);
-}
-
 static void handle_symbol(struct module *mod, struct elf_info *info,
 			  const Elf_Sym *sym, const char *symname)
 {
@@ -760,6 +724,104 @@  static char *remove_dot(char *s)
 	return s;
 }
 
+/*
+ * The CRCs are recorded in .*.cmd files in the form of:
+ * #SYMVER <name> <crc>
+ */
+static void extract_crcs_for_object(const char *object, struct module *mod)
+{
+	char cmd_file[PATH_MAX];
+	char *buf, *p;
+	const char *base;
+	int dirlen, ret;
+
+	base = strrchr(object, '/');
+	if (base) {
+		base++;
+		dirlen = base - object;
+	} else {
+		dirlen = 0;
+		base = object;
+	}
+
+	ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
+		       dirlen, object, base);
+	if (ret >= sizeof(cmd_file)) {
+		error("%s: too long path was truncated\n", cmd_file);
+		return;
+	}
+
+	buf = read_text_file(cmd_file);
+	p = buf;
+
+	while ((p = strstr(p, "\n#SYMVER "))) {
+		char *name;
+		size_t namelen;
+		unsigned int crc;
+		struct symbol *sym;
+
+		name = p + strlen("\n#SYMVER ");
+
+		p = strchr(name, ' ');
+		if (!p)
+			break;
+
+		namelen = p - name;
+		p++;
+
+		if (!isdigit(*p))
+			continue;	/* skip this line */
+
+		crc = strtol(p, &p, 0);
+		if (*p != '\n')
+			continue;	/* skip this line */
+
+		name[namelen] = '\0';
+
+		/*
+		 * sym_find_with_module() may return NULL here.
+		 * It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y.
+		 * Since commit e1327a127703, genksyms calculates CRCs of all
+		 * symbols, including trimmed ones. Ignore orphan CRCs.
+		 */
+		sym = sym_find_with_module(name, mod);
+		if (sym)
+			sym_set_crc(sym, crc);
+	}
+
+	free(buf);
+}
+
+/*
+ * The symbol versions (CRC) are recorded in the .*.cmd files.
+ * Parse them to retrieve CRCs for the current module.
+ */
+static void mod_set_crcs(struct module *mod)
+{
+	char objlist[PATH_MAX];
+	char *buf, *p, *obj;
+	int ret;
+
+	if (mod->is_vmlinux) {
+		strcpy(objlist, ".vmlinux.objs");
+	} else {
+		/* objects for a module are listed in the *.mod file. */
+		ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name);
+		if (ret >= sizeof(objlist)) {
+			error("%s: too long path was truncated\n", objlist);
+			return;
+		}
+	}
+
+	buf = read_text_file(objlist);
+	p = buf;
+
+	while ((obj = strsep(&p, "\n")) && obj[0])
+		extract_crcs_for_object(obj, mod);
+
+	free(buf);
+}
+
 static void read_symbols(const char *modname)
 {
 	const char *symname;
@@ -820,9 +882,6 @@  static void read_symbols(const char *modname)
 		if (strstarts(symname, "__kstrtabns_"))
 			sym_update_namespace(symname + strlen("__kstrtabns_"),
 					     sym_get_data(&info, sym));
-		if (strstarts(symname, "__crc_"))
-			handle_modversion(mod, &info, sym,
-					  symname + strlen("__crc_"));
 	}
 
 	// check for static EXPORT_SYMBOL_* functions && global vars
@@ -850,12 +909,17 @@  static void read_symbols(const char *modname)
 
 	parse_elf_finish(&info);
 
-	/* Our trick to get versioning for module struct etc. - it's
-	 * never passed as an argument to an exported function, so
-	 * the automatic versioning doesn't pick it up, but it's really
-	 * important anyhow */
-	if (modversions)
+	if (modversions) {
+		/*
+		 * Our trick to get versioning for module struct etc. - it's
+		 * never passed as an argument to an exported function, so
+		 * the automatic versioning doesn't pick it up, but it's really
+		 * important anyhow.
+		 */
 		sym_add_unresolved("module_layout", mod, false);
+
+		mod_set_crcs(mod);
+	}
 }
 
 static void read_symbols_from_files(const char *filename)
@@ -1012,6 +1076,23 @@  static void add_header(struct buffer *b, struct module *mod)
 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
 }
 
+static void check_symversions(struct module *mod)
+{
+	struct symbol *sym;
+
+	if (!modversions)
+		return;
+
+	list_for_each_entry(sym, &mod->exported_symbols, list) {
+		if (!sym->crc_valid) {
+			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
+			     "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
+			     sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
+			     sym->name);
+		}
+	}
+}
+
 /**
  * Record CRCs for unresolved symbols
  **/
@@ -1227,7 +1308,7 @@  static void read_dump(const char *fname)
 		}
 		s = sym_add_exported(symname, mod, gpl_only);
 		s->is_static = false;
-		sym_set_crc(symname, crc);
+		sym_set_crc(s, crc);
 		sym_update_namespace(symname, namespace);
 	}
 	free(buf);
@@ -1353,6 +1434,8 @@  int main(int argc, char **argv)
 		if (mod->from_dump)
 			continue;
 
+		check_symversions(mod);
+
 		if (!mod->is_vmlinux)
 			write_mod_c_file(mod);
 	}