Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 May 2019 17:33:20 +0000 (UTC)
From:      Conrad Meyer <cem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r348309 - head/usr.sbin/kldxref
Message-ID:  <201905271733.x4RHXKTP005785@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: cem
Date: Mon May 27 17:33:20 2019
New Revision: 348309
URL: https://svnweb.freebsd.org/changeset/base/348309

Log:
  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

Modified:
  head/usr.sbin/kldxref/kldxref.c

Modified: head/usr.sbin/kldxref/kldxref.c
==============================================================================
--- head/usr.sbin/kldxref/kldxref.c	Mon May 27 17:14:46 2019	(r348308)
+++ head/usr.sbin/kldxref/kldxref.c	Mon May 27 17:33:20 2019	(r348309)
@@ -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));
-			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);
+				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));
+			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);
+		}
 		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?201905271733.x4RHXKTP005785>