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
This commit is contained in:
parent
fcd0c06eee
commit
9c1fa7a429
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user