From 8de950a22b47f2a5a632e462ab0d4818247b2bdf Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 29 Apr 2000 13:19:31 +0000 Subject: First round implementation of a fine grain enhanced module to module version dependency system. This isn't quite finished, but it is at a useful stage to do a functional checkpoint. Highlights: - version and dependency metadata is gathered via linker sets, so things are handled the same for static kernels and code built to live in a kld. - The dependencies are at module level (versus at file level). - Dependencies determine kld symbol search order - this means that you cannot link against symbols in another file unless you depend on it. This is so that you cannot accidently unload the target out from underneath the ones referencing it. - It is flexible enough that we can put tags in #include files and macros so that we can get decent hooks for enforcing recompiles on incompatable ABI changes. eg: if we change struct proc, we could force a recompile for all kld's that reference the proc struct. - Tangled dependency references at boot time are sorted. Files are relocated once all their dependencies are already relocated. Caveats: - Loader support is incomplete, but has been worked on seperately. - Actual enforcement of the version number tags is not active yet - just the module dependencies are live. The actual structure of versioning hasn't been agreed on yet. (eg: major.minor, or whatever) - There is some backwards compatability for old modules without metadata but I'm not sure how good it is. This is based on work originally done by Boris Popov (bp@freebsd.org), but I'm not sure he'd recognize much of it now. Don't blame him. :-) Also, ideas have been borrowed from Mike Smith. --- sys/kern/link_elf.c | 132 ++++++++++++++++++++++------------------------------ 1 file changed, 55 insertions(+), 77 deletions(-) (limited to 'sys/kern/link_elf.c') diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index f7c0e2a..1f98c4c 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -91,9 +91,10 @@ typedef struct elf_file { #endif } *elf_file_t; -static int link_elf_load_module(linker_class_t cls, - const char*, linker_file_t*); -static int link_elf_load_file(const char*, linker_file_t*); +static int link_elf_link_preload(linker_class_t cls, + const char*, linker_file_t*); +static int link_elf_link_preload_finish(linker_file_t); +static int link_elf_load_file(linker_class_t, const char*, linker_file_t*); static int link_elf_lookup_symbol(linker_file_t, const char*, c_linker_sym_t*); static int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); @@ -101,14 +102,16 @@ static int link_elf_search_symbol(linker_file_t, caddr_t value, c_linker_sym_t* sym, long* diffp); static void link_elf_unload_file(linker_file_t); -static void link_elf_unload_module(linker_file_t); +static void link_elf_unload_preload(linker_file_t); static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), KOBJMETHOD(linker_unload, link_elf_unload_file), - KOBJMETHOD(linker_load_file, link_elf_load_module), + KOBJMETHOD(linker_load_file, link_elf_load_file), + KOBJMETHOD(linker_link_preload, link_elf_link_preload), + KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), { 0, 0 } }; @@ -122,9 +125,8 @@ static struct linker_class link_elf_class = { }; static int parse_dynamic(elf_file_t ef); -static int load_dependancies(elf_file_t ef); static int relocate_file(elf_file_t ef); -static int parse_module_symbols(elf_file_t ef); +static int link_elf_preload_parse_symbols(elf_file_t ef); #ifdef DDB @@ -176,6 +178,7 @@ link_elf_init(void* arg) panic("link_elf_init: Can't create linker structures for kernel"); ef = (elf_file_t) linker_kernel_file; + ef->preloaded = 1; ef->address = 0; #ifdef SPARSE_MAPPING ef->object = 0; @@ -195,9 +198,7 @@ link_elf_init(void* arg) if (sizeptr) linker_kernel_file->size = *(size_t *)sizeptr; } - (void)parse_module_symbols(ef); - linker_current_file = linker_kernel_file; - linker_kernel_file->flags |= LINKER_FILE_LINKED; + (void)link_elf_preload_parse_symbols(ef); #ifdef DDB ef->gdb.l_addr = linker_kernel_file->address; @@ -220,7 +221,7 @@ link_elf_init(void* arg) SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); static int -parse_module_symbols(elf_file_t ef) +link_elf_preload_parse_symbols(elf_file_t ef) { caddr_t pointer; caddr_t ssym, esym, base; @@ -400,8 +401,8 @@ link_elf_delete_gdb(struct link_map *l) #endif /* DDB */ static int -link_elf_load_module(linker_class_t cls, - const char *filename, linker_file_t *result) +link_elf_link_preload(linker_class_t cls, + const char* filename, linker_file_t *result) { caddr_t modptr, baseptr, sizeptr, dynptr; char *type; @@ -410,12 +411,11 @@ link_elf_load_module(linker_class_t cls, int error; vm_offset_t dp; - /* Look to see if we have the module preloaded */ + /* Look to see if we have the file preloaded */ modptr = preload_search_by_name(filename); if (modptr == NULL) - return (link_elf_load_file(filename, result)); + return ENOENT; - /* It's preloaded, check we can handle it and collect information */ type = (char *)preload_search_info(modptr, MODINFO_TYPE); baseptr = preload_search_info(modptr, MODINFO_ADDR); sizeptr = preload_search_info(modptr, MODINFO_SIZE); @@ -439,7 +439,6 @@ link_elf_load_module(linker_class_t cls, #endif dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; ef->dynamic = (Elf_Dyn *)dp; - lf->address = ef->address; lf->size = *(size_t *)sizeptr; @@ -448,34 +447,46 @@ link_elf_load_module(linker_class_t cls, linker_file_unload(lf); return error; } - error = load_dependancies(ef); - if (error) { - linker_file_unload(lf); - return error; + *result = lf; + return (0); +} + +static int +link_elf_link_preload_finish(linker_file_t lf) +{ + elf_file_t ef; + int error; + + ef = (elf_file_t) lf; +#if 0 /* this will be more trouble than it's worth for now */ + for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { + if (dp->d_tag != DT_NEEDED) + continue; + modname = ef->strtab + dp->d_un.d_val; + error = linker_load_module(modname, lf); + if (error) + goto out; } +#endif error = relocate_file(ef); - if (error) { - linker_file_unload(lf); + if (error) return error; - } - (void)parse_module_symbols(ef); - lf->flags |= LINKER_FILE_LINKED; + (void)link_elf_preload_parse_symbols(ef); #ifdef DDB GDB_STATE(RT_ADD); ef->gdb.l_addr = lf->address; - ef->gdb.l_name = filename; + ef->gdb.l_name = lf->filename; ef->gdb.l_ld = ef->dynamic; link_elf_add_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); #endif - *result = lf; return (0); } static int -link_elf_load_file(const char* filename, linker_file_t* result) +link_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result) { struct nameidata nd; struct proc* p = curproc; /* XXX */ @@ -497,7 +508,6 @@ link_elf_load_file(const char* filename, linker_file_t* result) int resid; elf_file_t ef; linker_file_t lf; - char *pathname; Elf_Shdr *shdr; int symtabindex; int symstrindex; @@ -507,13 +517,8 @@ link_elf_load_file(const char* filename, linker_file_t* result) shdr = NULL; lf = NULL; - pathname = linker_search_path(filename); - if (pathname == NULL) - return ENOENT; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); error = vn_open(&nd, FREAD, 0); - free(pathname, M_LINKER); if (error) return error; NDFREE(&nd, NDF_ONLY_PNBUF); @@ -688,9 +693,19 @@ link_elf_load_file(const char* filename, linker_file_t* result) error = parse_dynamic(ef); if (error) goto out; - error = load_dependancies(ef); + error = linker_load_dependancies(lf); if (error) goto out; +#if 0 /* this will be more trouble than it's worth for now */ + for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { + if (dp->d_tag != DT_NEEDED) + continue; + modname = ef->strtab + dp->d_un.d_val; + error = linker_load_module(modname, lf); + if (error) + goto out; + } +#endif error = relocate_file(ef); if (error) goto out; @@ -746,12 +761,10 @@ link_elf_load_file(const char* filename, linker_file_t* result) ef->ddbstrcnt = strcnt; ef->ddbstrtab = ef->strbase; - lf->flags |= LINKER_FILE_LINKED; - #ifdef DDB GDB_STATE(RT_ADD); ef->gdb.l_addr = lf->address; - ef->gdb.l_name = linker_search_path(filename); + ef->gdb.l_name = filename; ef->gdb.l_ld = ef->dynamic; link_elf_add_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); @@ -784,13 +797,11 @@ link_elf_unload_file(linker_file_t file) GDB_STATE(RT_DELETE); link_elf_delete_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); - /* The strange cast is to quieten a 'discarding const' warning. */ - free((caddr_t) (uintptr_t) ef->gdb.l_name, M_LINKER); } #endif if (ef->preloaded) { - link_elf_unload_module(file); + link_elf_unload_preload(file); return; } #ifdef SPARSE_MAPPING @@ -811,45 +822,12 @@ link_elf_unload_file(linker_file_t file) } static void -link_elf_unload_module(linker_file_t file) +link_elf_unload_preload(linker_file_t file) { if (file->filename) preload_delete_name(file->filename); } -static int -load_dependancies(elf_file_t ef) -{ - linker_file_t lfdep; - char* name; - const Elf_Dyn *dp; - int error = 0; - - /* - * All files are dependant on /kernel. - */ - if (linker_kernel_file) { - linker_kernel_file->refs++; - linker_file_add_dependancy(&ef->lf, linker_kernel_file); - } - - for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { - if (dp->d_tag == DT_NEEDED) { - name = ef->strtab + dp->d_un.d_val; - - error = linker_load_file(name, &lfdep); - if (error) - goto out; - error = linker_file_add_dependancy(&ef->lf, lfdep); - if (error) - goto out; - } - } - -out: - return error; -} - static const char * symbol_name(elf_file_t ef, Elf_Word r_info) { -- cgit v1.1