Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Jan 2021 16:01:59 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 80a5b8512a2c - stable/12 - kldxref(8): Sort MDT_MODULE info first in linker.hints output
Message-ID:  <202101231601.10NG1xET053759@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=80a5b8512a2c6193df36bd2dd885fc772633a971

commit 80a5b8512a2c6193df36bd2dd885fc772633a971
Author:     Conrad Meyer <cem@FreeBSD.org>
AuthorDate: 2019-05-27 17:33:20 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-01-23 16:01:21 +0000

    kldxref(8): Sort MDT_MODULE info first in linker.hints output
    
    MDT_MODULE info is required to be ordered before any other MDT metadata for
    a given kld because it serves as an implicit record boundary between
    distinct klds for linker.hints consumers.  kldxref(8) has previously relied
    on the assumption that MDT_MODULE was ordered relative to other module
    metadata in kld objects by source code ordering.
    
    However, C does not require implementations to emit file scope objects in
    any particular order, and it seems that GCC 6.4.0 and/or binutils 2.32 ld
    may reorder emitted objects with respect to source code ordering.
    
    So: just take two passes over a given .ko's module metadata, scanning for
    the MDT_MODULE on the first pass and the other metadata on subsequent
    passes.  It's not super expensive and not exactly a performance-critical
    piece of code.  This ensures MDT_MODULE is always ordered before
    MDT_PNP_INFO and other MDTs, regardless of compiler/linker movement.  As a
    fringe benefit, it removes the requirement that care be taken to always
    order MODULE_PNP_INFO after DRIVER_MODULE in source code.
    
    Reviewed by:    emaste, imp
    Differential Revision:  https://reviews.freebsd.org/D20405
    
    (cherry picked from commit 9c1fa7a429145b298a012cb7b752c82a1e0b1184)
---
 usr.sbin/kldxref/kldxref.c | 51 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 43 insertions(+), 8 deletions(-)

diff --git a/usr.sbin/kldxref/kldxref.c b/usr.sbin/kldxref/kldxref.c
index 4e456a05c25b..c70405962dd8 100644
--- a/usr.sbin/kldxref/kldxref.c
+++ b/usr.sbin/kldxref/kldxref.c
@@ -549,9 +549,9 @@ read_kld(char *filename, char *kldname)
 {
 	struct mod_metadata md;
 	struct elf_file ef;
-	void **p, **orgp;
+	void **p;
 	int error, eftype;
-	long start, finish, entries;
+	long start, finish, entries, i;
 	char cval[MAXMODNAME + 1];
 
 	if (verbose || dflag)
@@ -575,18 +575,53 @@ read_kld(char *filename, char *kldname)
 		    &entries));
 		check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries,
 		    (void *)&p));
-		orgp = p;
-		while(entries--) {
-			check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md),
+		/*
+		 * Do a first pass to find MDT_MODULE.  It is required to be
+		 * ordered first in the output linker.hints stream because it
+		 * serves as an implicit record boundary between distinct klds
+		 * in the stream.  Other MDTs only make sense in the context of
+		 * a specific MDT_MODULE.
+		 *
+		 * Some compilers (e.g., GCC 6.4.0 xtoolchain) or binutils
+		 * (e.g., GNU binutils 2.32 objcopy/ld.bfd) can reorder
+		 * MODULE_METADATA set entries relative to the source ordering.
+		 * This is permitted by the C standard; memory layout of
+		 * file-scope objects is left implementation-defined.  There is
+		 * no requirement that source code ordering is retained.
+		 *
+		 * Handle that here by taking two passes to ensure MDT_MODULE
+		 * records are emitted to linker.hints before other MDT records
+		 * in the same kld.
+		 */
+		for (i = 0; i < entries; i++) {
+			check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md),
+			    &md));
+			check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval,
+			    sizeof(cval), cval));
+			if (md.md_type == MDT_MODULE) {
+				parse_entry(&md, cval, &ef, kldname);
+				break;
+			}
+		}
+		if (error != 0) {
+			warnc(error, "error while reading %s", filename);
+			break;
+		}
+
+		/*
+		 * Second pass for all !MDT_MODULE entries.
+		 */
+		for (i = 0; i < entries; i++) {
+			check(EF_SEG_READ_REL(&ef, (Elf_Off)p[i], sizeof(md),
 			    &md));
-			p++;
 			check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval,
 			    sizeof(cval), cval));
-			parse_entry(&md, cval, &ef, kldname);
+			if (md.md_type != MDT_MODULE)
+				parse_entry(&md, cval, &ef, kldname);
 		}
 		if (error != 0)
 			warnc(error, "error while reading %s", filename);
-		free(orgp);
+		free(p);
 	} while(0);
 	EF_CLOSE(&ef);
 	return (error);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101231601.10NG1xET053759>