aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/kldxref/kldxref.c
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2019-05-27 17:33:20 +0000
committerConrad Meyer <cem@FreeBSD.org>2019-05-27 17:33:20 +0000
commit9c1fa7a429145b298a012cb7b752c82a1e0b1184 (patch)
tree8e4662c22d479ee7ff9f96c9cc038340aa5d2112 /usr.sbin/kldxref/kldxref.c
parentfcd0c06eee56cb0bdcdba7e034e1b8f2a79fe729 (diff)
Notes
Diffstat (limited to 'usr.sbin/kldxref/kldxref.c')
-rw-r--r--usr.sbin/kldxref/kldxref.c51
1 files 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);