git: 80a5b8512a2c - stable/12 - kldxref(8): Sort MDT_MODULE info first in linker.hints output
Mark Johnston
markj at FreeBSD.org
Sat Jan 23 16:01:59 UTC 2021
The branch stable/12 has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=80a5b8512a2c6193df36bd2dd885fc772633a971
commit 80a5b8512a2c6193df36bd2dd885fc772633a971
Author: Conrad Meyer <cem at FreeBSD.org>
AuthorDate: 2019-05-27 17:33:20 +0000
Commit: Mark Johnston <markj at 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);
More information about the dev-commits-src-all
mailing list