The branch stable/12 has been updated by markj:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=80a5b8512a2c6193df36bd2dd885fc772633a971

commit 80a5b8512a2c6193df36bd2dd885fc772633a971
Author:     Conrad Meyer <[email protected]>
AuthorDate: 2019-05-27 17:33:20 +0000
Commit:     Mark Johnston <[email protected]>
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);
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to