diff options
| author | Conrad Meyer <cem@FreeBSD.org> | 2019-05-27 17:33:20 +0000 |
|---|---|---|
| committer | Conrad Meyer <cem@FreeBSD.org> | 2019-05-27 17:33:20 +0000 |
| commit | 9c1fa7a429145b298a012cb7b752c82a1e0b1184 (patch) | |
| tree | 8e4662c22d479ee7ff9f96c9cc038340aa5d2112 /usr.sbin/kldxref/kldxref.c | |
| parent | fcd0c06eee56cb0bdcdba7e034e1b8f2a79fe729 (diff) | |
Notes
Diffstat (limited to 'usr.sbin/kldxref/kldxref.c')
| -rw-r--r-- | usr.sbin/kldxref/kldxref.c | 51 |
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); |
