diff options
author | peter <peter@FreeBSD.org> | 2001-06-13 10:58:39 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2001-06-13 10:58:39 +0000 |
commit | f10fa038c14063eaf2da32ed734e644e5f569694 (patch) | |
tree | 88aef8097c80f09c2f725d61b6da4d433a595a61 /sys/kern/kern_linker.c | |
parent | 2514663dd721b9ac234d35a4dac65dfc457ff6bc (diff) | |
download | FreeBSD-src-f10fa038c14063eaf2da32ed734e644e5f569694.zip FreeBSD-src-f10fa038c14063eaf2da32ed734e644e5f569694.tar.gz |
With this commit, I hereby pronounce gensetdefs past its use-by date.
Replace the a.out emulation of 'struct linker_set' with something
a little more flexible. <sys/linker_set.h> now provides macros for
accessing elements and completely hides the implementation.
The linker_set.h macros have been on the back burner in various
forms since 1998 and has ideas and code from Mike Smith (SET_FOREACH()),
John Polstra (ELF clue) and myself (cleaned up API and the conversion
of the rest of the kernel to use it).
The macros declare a strongly typed set. They return elements with the
type that you declare the set with, rather than a generic void *.
For ELF, we use the magic ld symbols (__start_<setname> and
__stop_<setname>). Thanks to Richard Henderson <rth@redhat.com> for the
trick about how to force ld to provide them for kld's.
For a.out, we use the old linker_set struct.
NOTE: the item lists are no longer null terminated. This is why
the code impact is high in certain areas.
The runtime linker has a new method to find the linker set
boundaries depending on which backend format is in use.
linker sets are still module/kld unfriendly and should never be used
for anything that may be modular one day.
Reviewed by: eivind
Diffstat (limited to 'sys/kern/kern_linker.c')
-rw-r--r-- | sys/kern/kern_linker.c | 190 |
1 files changed, 96 insertions, 94 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index affc1dc..abd7fdd 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -54,6 +54,9 @@ int kld_debug = 0; static char *linker_search_path(const char *name); static const char *linker_basename(const char* path); +/* Metadata from the static kernel */ +SET_DECLARE(modmetadata_set, struct mod_metadata); + MALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); linker_file_t linker_kernel_file; @@ -105,7 +108,7 @@ linker_add_class(linker_class_t lc) static void linker_file_sysinit(linker_file_t lf) { - struct linker_set* sysinits; + struct sysinit** start, ** stop; struct sysinit** sipp; struct sysinit** xipp; struct sysinit* save; @@ -113,11 +116,7 @@ linker_file_sysinit(linker_file_t lf) KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", lf->filename)); - sysinits = (struct linker_set*) - linker_file_lookup_symbol(lf, "sysinit_set", 0); - - KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits)); - if (!sysinits) + if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) return; /* * Perform a bubble sort of the system initialization objects by @@ -126,8 +125,8 @@ linker_file_sysinit(linker_file_t lf) * Since some things care about execution order, this is the * operation which ensures continued function. */ - for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { - for (xipp = sipp + 1; *xipp; xipp++) { + for (sipp = start; sipp < stop; sipp++) { + for (xipp = sipp + 1; xipp < stop; xipp++) { if ((*sipp)->subsystem < (*xipp)->subsystem || ((*sipp)->subsystem == (*xipp)->subsystem && (*sipp)->order <= (*xipp)->order)) @@ -143,7 +142,7 @@ linker_file_sysinit(linker_file_t lf) * Traverse the (now) ordered list of system initialization tasks. * Perform each task, and continue on to the next task. */ - for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { + for (sipp = start; sipp < stop; sipp++) { if ((*sipp)->subsystem == SI_SUB_DUMMY) continue; /* skip dummy task(s)*/ @@ -155,7 +154,7 @@ linker_file_sysinit(linker_file_t lf) static void linker_file_sysuninit(linker_file_t lf) { - struct linker_set* sysuninits; + struct sysinit** start, ** stop; struct sysinit** sipp; struct sysinit** xipp; struct sysinit* save; @@ -163,11 +162,7 @@ linker_file_sysuninit(linker_file_t lf) KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", lf->filename)); - sysuninits = (struct linker_set*) - linker_file_lookup_symbol(lf, "sysuninit_set", 0); - - KLD_DPF(FILE, ("linker_file_sysuninit: SYSUNINITs %p\n", sysuninits)); - if (!sysuninits) + if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, NULL) != 0) return; /* @@ -177,8 +172,8 @@ linker_file_sysuninit(linker_file_t lf) * Since some things care about execution order, this is the * operation which ensures continued function. */ - for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) { - for (xipp = sipp + 1; *xipp; xipp++) { + for (sipp = start; sipp < stop; sipp++) { + for (xipp = sipp + 1; xipp < stop; xipp++) { if ((*sipp)->subsystem > (*xipp)->subsystem || ((*sipp)->subsystem == (*xipp)->subsystem && (*sipp)->order >= (*xipp)->order)) @@ -193,7 +188,7 @@ linker_file_sysuninit(linker_file_t lf) * Traverse the (now) ordered list of system initialization tasks. * Perform each task, and continue on to the next task. */ - for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) { + for (sipp = start; sipp < stop; sipp++) { if ((*sipp)->subsystem == SI_SUB_DUMMY) continue; /* skip dummy task(s)*/ @@ -205,64 +200,61 @@ linker_file_sysuninit(linker_file_t lf) static void linker_file_register_sysctls(linker_file_t lf) { - struct linker_set* sysctls; + struct sysctl_oid **start, **stop, **oidp; KLD_DPF(FILE, ("linker_file_register_sysctls: registering SYSCTLs for %s\n", lf->filename)); - sysctls = (struct linker_set*) - linker_file_lookup_symbol(lf, "sysctl_set", 0); - - KLD_DPF(FILE, ("linker_file_register_sysctls: SYSCTLs %p\n", sysctls)); - if (!sysctls) + if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) return; - sysctl_register_set(sysctls); + for (oidp = start; oidp < stop; oidp++) + sysctl_register_oid(*oidp); } static void linker_file_unregister_sysctls(linker_file_t lf) { - struct linker_set* sysctls; + struct sysctl_oid **start, **stop, **oidp; KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs for %s\n", lf->filename)); - sysctls = (struct linker_set*) - linker_file_lookup_symbol(lf, "sysctl_set", 0); - - KLD_DPF(FILE, ("linker_file_unregister_sysctls: SYSCTLs %p\n", sysctls)); - if (!sysctls) + if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) return; - sysctl_unregister_set(sysctls); + for (oidp = start; oidp < stop; oidp++) + sysctl_unregister_oid(*oidp); } -extern struct linker_set modmetadata_set; - static int linker_file_register_modules(linker_file_t lf) { int error; - struct linker_set *modules; - struct mod_metadata **mdpp; + struct mod_metadata **start, **stop; + struct mod_metadata **mdp; const moduledata_t *moddata; KLD_DPF(FILE, ("linker_file_register_modules: registering modules in %s\n", lf->filename)); - modules = (struct linker_set*) - linker_file_lookup_symbol(lf, "modmetadata_set", 0); - - if (!modules && lf == linker_kernel_file) - modules = &modmetadata_set; - - if (modules == NULL) - return 0; - for (mdpp = (struct mod_metadata**)modules->ls_items; *mdpp; mdpp++) { - if ((*mdpp)->md_type != MDT_MODULE) + if (linker_file_lookup_set(lf, "modmetadata_set", &start, &stop, 0) != 0) { + /* + * This fallback should be unnecessary, but if we get booted from + * boot2 instead of loader and we are missing our metadata then + * we have to try the best we can. + */ + if (lf == linker_kernel_file) { + start = SET_BEGIN(modmetadata_set); + stop = SET_LIMIT(modmetadata_set); + } else { + return 0; + } + } + for (mdp = start; mdp < stop; mdp++) { + if ((*mdp)->md_type != MDT_MODULE) continue; - moddata = (*mdpp)->md_data; + moddata = (*mdp)->md_data; KLD_DPF(FILE, ("Registering module %s in %s\n", moddata->name, lf->filename)); if (module_lookupbyname(moddata->name) != NULL) { @@ -514,6 +506,19 @@ linker_file_add_dependancy(linker_file_t file, linker_file_t dep) return 0; } +/* + * Locate a linker set and its contents. + * This is a helper function to avoid linker_if.h exposure elsewhere. + * Note: firstp and lastp are really void *** + */ +int +linker_file_lookup_set(linker_file_t file, const char *name, + void *firstp, void *lastp, int *countp) +{ + + return LINKER_LOOKUP_SET(file, name, firstp, lastp, countp); +} + caddr_t linker_file_lookup_symbol(linker_file_t file, const char* name, int deps) { @@ -986,17 +991,18 @@ linker_mdt_depend(linker_file_t lf, struct mod_metadata *mp, } static void -linker_addmodules(linker_file_t lf, struct linker_set *deps, int preload) +linker_addmodules(linker_file_t lf, struct mod_metadata **start, + struct mod_metadata **stop, int preload) { - struct mod_metadata *mp; + struct mod_metadata *mp, **mdp; char *modname; - int i, ver; + int ver; - for (i = 0; i < deps->ls_length; i++) { + for (mdp = start; mdp < stop; mdp++) { if (preload) - mp = deps->ls_items[i]; + mp = *mdp; else - mp = linker_reloc_ptr(lf, deps->ls_items[i]); + mp = linker_reloc_ptr(lf, *mdp); if (mp->md_type != MDT_VERSION) continue; if (preload) { @@ -1022,15 +1028,15 @@ linker_preload(void* arg) linker_file_t lf; linker_class_t lc; int error; - struct linker_set *sysinits; linker_file_list_t loaded_files; linker_file_list_t depended_files; - struct linker_set *deps; struct mod_metadata *mp, *nmp; + struct mod_metadata **start, **stop, **mdp, **nmdp; struct mod_depend *verinfo; - int i, j, nver; + int nver; int resolves; modlist_t mod; + struct sysinit **si_start, **si_stop; TAILQ_INIT(&loaded_files); TAILQ_INIT(&depended_files); @@ -1065,10 +1071,9 @@ linker_preload(void* arg) /* * First get a list of stuff in the kernel. */ - deps = (struct linker_set*) - linker_file_lookup_symbol(linker_kernel_file, MDT_SETNAME, 0); - if (deps) - linker_addmodules(linker_kernel_file, deps, 1); + if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, &stop, + NULL) == 0) + linker_addmodules(linker_kernel_file, start, stop, 1); /* * this is a once-off kinky bubble sort @@ -1076,20 +1081,19 @@ linker_preload(void* arg) */ restart: TAILQ_FOREACH(lf, &loaded_files, loaded) { - deps = (struct linker_set*) - linker_file_lookup_symbol(lf, MDT_SETNAME, 0); + error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); /* * First, look to see if we would successfully link with this stuff. */ resolves = 1; /* unless we know otherwise */ - if (deps) { - for (i = 0; i < deps->ls_length; i++) { - mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (!error) { + for (mdp = start; mdp < stop; mdp++) { + mp = linker_reloc_ptr(lf, *mdp); if (mp->md_type != MDT_DEPEND) continue; linker_mdt_depend(lf, mp, &modname, &verinfo); - for (j = 0; j < deps->ls_length; j++) { - nmp = linker_reloc_ptr(lf, deps->ls_items[j]); + for (nmdp = start; nmdp < stop; nmdp++) { + nmp = linker_reloc_ptr(lf, *nmdp); if (nmp->md_type != MDT_VERSION) continue; linker_mdt_version(lf, nmp, &nmodname, NULL); @@ -1097,7 +1101,7 @@ restart: if (strcmp(modname, nmodname) == 0) break; } - if (j < deps->ls_length) /* it's a self reference */ + if (nmdp < stop) /* it's a self reference */ continue; if (modlist_lookup(modname, 0) == NULL) { /* ok, the module isn't here yet, we are not finished */ @@ -1110,9 +1114,9 @@ restart: * modules inside and add it to the end of the link order list. */ if (resolves) { - if (deps) { - for (i = 0; i < deps->ls_length; i++) { - mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (!error) { + for (mdp = start; mdp < stop; mdp++) { + mp = linker_reloc_ptr(lf, *mdp); if (mp->md_type != MDT_VERSION) continue; linker_mdt_version(lf, mp, &modname, &nver); @@ -1156,11 +1160,10 @@ restart: panic("cannot add dependency"); } lf->userrefs++; /* so we can (try to) kldunload it */ - deps = (struct linker_set*) - linker_file_lookup_symbol(lf, MDT_SETNAME, 0); - if (deps) { - for (i = 0; i < deps->ls_length; i++) { - mp = linker_reloc_ptr(lf, deps->ls_items[i]); + error = linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); + if (!error) { + for (mdp = start; mdp < stop; mdp++) { + mp = linker_reloc_ptr(lf, *mdp); if (mp->md_type != MDT_DEPEND) continue; linker_mdt_depend(lf, mp, &modname, &verinfo); @@ -1172,7 +1175,10 @@ restart: } } - /* Now do relocation etc using the symbol search paths established by the dependencies */ + /* + * Now do relocation etc using the symbol search paths established by + * the dependencies + */ error = LINKER_LINK_PRELOAD_FINISH(lf); if (error) { printf("KLD file %s - could not finalize loading\n", lf->filename); @@ -1181,10 +1187,8 @@ restart: } linker_file_register_modules(lf); - sysinits = (struct linker_set*) - linker_file_lookup_symbol(lf, "sysinit_set", 0); - if (sysinits) - sysinit_add((struct sysinit **)sysinits->ls_items); + if (linker_file_lookup_set(lf, "sysinit_set", &si_start, &si_stop, NULL) == 0) + sysinit_add(si_start, si_stop); linker_file_register_sysctls(lf); lf->flags |= LINKER_FILE_LINKED; } @@ -1348,11 +1352,11 @@ int linker_load_dependancies(linker_file_t lf) { linker_file_t lfdep; - struct linker_set *deps; + struct mod_metadata **start, **stop, **mdp, **nmdp; struct mod_metadata *mp, *nmp; modlist_t mod; char *modname, *nmodname; - int i, j, ver, error = 0; + int ver, error = 0, count; /* * All files are dependant on /kernel. @@ -1364,12 +1368,10 @@ linker_load_dependancies(linker_file_t lf) return error; } - deps = (struct linker_set*) - linker_file_lookup_symbol(lf, MDT_SETNAME, 0); - if (deps == NULL) + if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, &count) != 0) return 0; - for (i = 0; i < deps->ls_length; i++) { - mp = linker_reloc_ptr(lf, deps->ls_items[i]); + for (mdp = start; mdp < stop; mdp++) { + mp = linker_reloc_ptr(lf, *mdp); if (mp->md_type != MDT_VERSION) continue; linker_mdt_version(lf, mp, &modname, &ver); @@ -1381,21 +1383,21 @@ linker_load_dependancies(linker_file_t lf) } } - for (i = 0; i < deps->ls_length; i++) { - mp = linker_reloc_ptr(lf, deps->ls_items[i]); + for (mdp = start; mdp < stop; mdp++) { + mp = linker_reloc_ptr(lf, *mdp); if (mp->md_type != MDT_DEPEND) continue; modname = linker_reloc_ptr(lf, mp->md_cval); nmodname = NULL; - for (j = 0; j < deps->ls_length; j++) { - nmp = linker_reloc_ptr(lf, deps->ls_items[j]); + for (nmdp = start; nmdp < stop; nmdp++) { + nmp = linker_reloc_ptr(lf, *nmdp); if (nmp->md_type != MDT_VERSION) continue; nmodname = linker_reloc_ptr(lf, nmp->md_cval); if (strcmp(modname, nmodname) == 0) break; } - if (j < deps->ls_length) /* early exit, it's a self reference */ + if (nmdp < stop) /* early exit, it's a self reference */ continue; mod = modlist_lookup(modname, 0); if (mod) { /* woohoo, it's loaded already */ @@ -1416,6 +1418,6 @@ linker_load_dependancies(linker_file_t lf) if (error) return error; - linker_addmodules(lf, deps, 0); + linker_addmodules(lf, start, stop, 0); return error; } |