All of lore.kernel.org
 help / color / mirror / Atom feed
From: Masahiro Yamada <masahiroy@kernel.org>
To: linux-kbuild@vger.kernel.org
Cc: linux-kernel@vger.kernel.org,
	Masahiro Yamada <masahiroy@kernel.org>,
	Michal Marek <michal.lkml@markovi.net>,
	Nathan Chancellor <nathan@kernel.org>,
	Nick Desaulniers <ndesaulniers@google.com>,
	llvm@lists.linux.dev
Subject: [PATCH 23/27] modpost: retrieve symbol versions by parsing *.cmd files
Date: Mon, 25 Apr 2022 04:08:07 +0900	[thread overview]
Message-ID: <20220424190811.1678416-24-masahiroy@kernel.org> (raw)
In-Reply-To: <20220424190811.1678416-1-masahiroy@kernel.org>

Currently, CONFIG_MODVERSIONS needs extra link to embed the symbol
versions into objects. Then, modpost parses the ELF objects to retrieve
the version CRCs.

See the current build flow below.

Current implementation
======================

                  embed CRC        |---------|              |------------|
       $(CC)        $(LD)          |         |              | final link |
  *.c ------> *.o --------> *.o -->| modpost |-- *.o ------>| for        |
                      /            |         |              | vmlinux    |
     genksyms        /             |         |-- *.mod.c -->| or 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 becomes 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 in the first place. 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 embed CRCs at the very
last moment.

See the following figure, which explains what I want to do.

New implementation
==================

       $(CC)           |---------|                    |------------|
  *.c ------> *.o  --->|         |-- *.o ------------>| final link |
                       | modpost |-- *.mod.c -------->| for        |
      genksyms         |         |-- *.symver.lds --->| vmlinux    |
  *.c ------> *.cmd -->|         |                    | or module  |
                       |---------|                    |------------|

We can pass the symbol versions to modpost as separate text data.
(The previous commit output the versions in *.cmd files.)

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

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
---

 scripts/mod/modpost.c | 177 ++++++++++++++++++++++++++++++++----------
 1 file changed, 136 insertions(+), 41 deletions(-)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index fb50927cd241..43ab4f000ae3 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -246,6 +246,9 @@ static inline unsigned int tdb_hash(const char *name)
 /* hash table of all exported symbols */
 HASHTABLE_DECLARE(exported_symbols, 8192);
 
+/* hash table of CRCs */
+HASHTABLE_DECLARE(crc_symbols, 1024);
+
 /**
  * Allocate a new symbols for use in the hash of exported symbols or
  * the list of unresolved symbols per module
@@ -420,7 +423,27 @@ static void sym_add_exported(const char *name, struct module *mod,
 		      s->module->is_vmlinux ? "" : ".ko");
 	}
 
-	s = alloc_symbol(name);
+	s = NULL;
+
+	if (modversions) {
+		struct hlist_node *n;
+
+		hash_for_matched_symbol_safe(s, n, crc_symbols, name) {
+			if (s->module == mod)
+				hash_del_symbol(s);
+			break;
+		}
+
+		if (!s)
+			warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
+			     "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
+			     name, mod->name, mod->is_vmlinux ? "" : ".ko",
+			     name);
+	}
+
+	if (!s)
+		s = alloc_symbol(name);
+
 	s->module = mod;
 	s->is_static = !mod->from_dump;
 	s->export    = export;
@@ -428,19 +451,116 @@ static void sym_add_exported(const char *name, struct module *mod,
 	hash_add_symbol(s, exported_symbols);
 }
 
-static void sym_set_crc(const char *name, unsigned int crc)
+static void sym_add_crc(const char *name, unsigned int crc, struct module *mod)
 {
-	struct symbol *s = find_symbol(name);
+	struct symbol *sym;
 
-	/*
-	 * Ignore stand-alone __crc_*, which might be auto-generated symbols
-	 * such as __*_veneer in ARM ELF.
-	 */
-	if (!s)
+	sym = alloc_symbol(name);
+
+	sym->crc = crc;
+	sym->crc_valid = true;
+	sym->module = mod;
+
+	hash_add_symbol(sym, crc_symbols);
+}
+
+/*
+ * The CRCs are recorded in .*.cmd files in the form of:
+ * #__crc_<name>=<crc>
+ */
+static void retrieve_crcs_from_cmdfile(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#__crc_"))) {
+		char *name;
+		size_t namelen;
+		unsigned int crc;
+		char *end;
+
+		name = p + strlen("\n#__crc_");
+
+		p = strchr(name, '=');
+		if (!p) {
+			error("invalid\n");
+			goto out;
+		}
+
+		namelen = p - name;
+
+		p++;
 
-	s->crc = crc;
-	s->crc_valid = true;
+		if (!isdigit(*p)) {
+			error("invalid\n");
+			goto out;
+		}
+
+		crc = strtol(p, &end, 0);
+		p = end;
+
+		if (*p != '\n') {
+			error("invalid\n");
+			goto out;
+		}
+
+		name[namelen] = '\0';
+		sym_add_crc(name, crc, mod);
+	}
+
+out:
+	free(buf);
+}
+
+/*
+ * The symbol versions (CRC) are recorded in the .*.cmd files.
+ * Parse them to retrieve CRCs for the current module.
+ */
+static void retrieve_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])
+		retrieve_crcs_from_cmdfile(obj, mod);
+
+	free(buf);
 }
 
 static void *grab_file(const char *filename, size_t *size)
@@ -663,33 +783,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)
 {
@@ -2019,6 +2112,10 @@ static void read_symbols(const char *modname)
 		if (strends(tmp, ".prelink"))
 			tmp[strlen(tmp) - 8] = '\0';
 		mod = new_module(tmp);
+
+		if (modversions)
+			retrieve_crcs(mod);
+
 		free(tmp);
 	}
 
@@ -2058,9 +2155,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
@@ -2451,8 +2545,9 @@ static void read_dump(const char *fname)
 			mod = new_module(modname);
 			mod->from_dump = true;
 		}
+
+		sym_add_crc(symname, crc, mod);
 		sym_add_exported(symname, mod, export_no(export));
-		sym_set_crc(symname, crc);
 		sym_update_namespace(symname, namespace);
 	}
 	free(buf);
-- 
2.32.0


  parent reply	other threads:[~2022-04-24 19:18 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-24 19:07 [PATCH 00/27] kbuild: yet another series of cleanups (modpost and LTO) Masahiro Yamada
2022-04-24 19:07 ` [PATCH 01/27] modpost: use snprintf() instead of sprintf() for safety Masahiro Yamada
2022-04-25 18:11   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 02/27] modpost: do not write out any file when error occurred Masahiro Yamada
2022-04-25 18:15   ` Nick Desaulniers
2022-04-26  3:47     ` Masahiro Yamada
2022-04-24 19:07 ` [PATCH 03/27] modpost: remove stale comment about sym_add_exported() Masahiro Yamada
2022-04-25 18:18   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 04/27] modpost: add a separate error for exported symbols without definition Masahiro Yamada
2022-04-25 18:21   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 05/27] modpost: retrieve the module dependency and CRCs in check_exports() Masahiro Yamada
2022-04-25 18:24   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 06/27] modpost: use bool type where appropriate Masahiro Yamada
2022-04-25 18:34   ` Nick Desaulniers
2022-04-25 18:56     ` Nick Desaulniers
2022-04-29 18:30       ` Masahiro Yamada
2022-05-01 13:14     ` Masahiro Yamada
2022-04-24 19:07 ` [PATCH 07/27] modpost: import include/linux/list.h Masahiro Yamada
2022-04-25 18:42   ` Nick Desaulniers
2022-04-26  4:05     ` Masahiro Yamada
2022-04-26 16:29   ` Nick Desaulniers
2022-04-30 14:21     ` Masahiro Yamada
2022-04-24 19:07 ` [PATCH 08/27] modpost: traverse modules in order Masahiro Yamada
2022-04-26 16:49   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 09/27] modpost: add sym_add_unresolved() helper Masahiro Yamada
2022-04-25 18:41   ` Nick Desaulniers
2022-04-26  3:58     ` Masahiro Yamada
2022-04-26 16:40       ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 10/27] modpost: traverse unresolved symbols in order Masahiro Yamada
2022-04-26 17:08   ` Nick Desaulniers
2022-04-30 15:24     ` Masahiro Yamada
2022-04-24 19:07 ` [PATCH 11/27] modpost: use doubly linked list for dump_lists Masahiro Yamada
2022-04-26 17:14   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 12/27] modpost: move struct namespace_list to modpost.c Masahiro Yamada
2022-04-25 18:44   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 13/27] modpost: traverse the namespace_list in order Masahiro Yamada
2022-04-26 17:20   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 14/27] modpost: dump Module.symvers in the same order of modules.order Masahiro Yamada
2022-04-26 22:22   ` Nick Desaulniers
2022-04-24 19:07 ` [PATCH 15/27] modpost: move static EXPORT_SYMBOL check to check_exports() Masahiro Yamada
2022-04-24 19:08 ` [PATCH 16/27] modpost: make multiple export error Masahiro Yamada
2022-04-25 18:48   ` Nick Desaulniers
2022-04-26  4:08     ` Masahiro Yamada
2022-04-26 16:39       ` Nick Desaulniers
2022-04-26 18:33         ` Masahiro Yamada
2022-04-24 19:08 ` [PATCH 17/27] modpost: make sym_add_exported() always allocate a new symbol Masahiro Yamada
2022-04-24 19:08 ` [PATCH 18/27] modpost: make sym_add_exported() a void function Masahiro Yamada
2022-04-24 19:08 ` [PATCH 19/27] modpost: use hlist for hash table implementation Masahiro Yamada
2022-04-24 19:08 ` [PATCH 20/27] modpost: mitigate false-negatives for static EXPORT_SYMBOL checks Masahiro Yamada
2022-04-24 19:08 ` [PATCH 21/27] kbuild: record symbol versions in *.cmd files Masahiro Yamada
2022-04-27 20:08   ` Nicolas Schier
2022-04-24 19:08 ` [PATCH 22/27] kbuild: generate a list of objects in vmlinux Masahiro Yamada
2022-04-27 20:14   ` Nicolas Schier
2022-04-28  4:49     ` Masahiro Yamada
2022-04-24 19:08 ` Masahiro Yamada [this message]
2022-04-24 19:08 ` [PATCH 24/27] modpost: generate linker script to collect symbol versions Masahiro Yamada
2022-04-28 21:49   ` Nick Desaulniers
2022-04-29  1:31     ` Masahiro Yamada
2022-04-24 19:08 ` [PATCH 25/27] kbuild: embed symbol versions at final link of vmlinux or modules Masahiro Yamada
2022-04-28  3:04   ` Nicolas Schier
2022-04-24 19:08 ` [PATCH 26/27] kbuild: stop generating *.symversions Masahiro Yamada
2022-04-28  3:15   ` Nicolas Schier
2022-04-28  4:46     ` Masahiro Yamada
2022-04-24 19:08 ` [PATCH 27/27] kbuild: do not create *.prelink.o for Clang LTO or IBT Masahiro Yamada
2022-04-28  3:30   ` Nicolas Schier
2022-04-28  4:38     ` Masahiro Yamada
2022-04-28  6:59       ` Nicolas Schier
2022-04-26 20:10 ` [PATCH 00/27] kbuild: yet another series of cleanups (modpost and LTO) Nicolas Schier
2022-04-27  3:18   ` Masahiro Yamada
2022-05-01  7:11     ` Masahiro Yamada

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220424190811.1678416-24-masahiroy@kernel.org \
    --to=masahiroy@kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=llvm@lists.linux.dev \
    --cc=michal.lkml@markovi.net \
    --cc=nathan@kernel.org \
    --cc=ndesaulniers@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.