summaryrefslogtreecommitdiffstats
path: root/sys/kern/link_elf_obj.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2000-04-29 13:19:31 +0000
committerpeter <peter@FreeBSD.org>2000-04-29 13:19:31 +0000
commit8de950a22b47f2a5a632e462ab0d4818247b2bdf (patch)
tree38b4753b3c3b977d419f65254cb442749845de6e /sys/kern/link_elf_obj.c
parentc3e5d07abf2d42fb40aaf24a4fe6f2216e01b35c (diff)
downloadFreeBSD-src-8de950a22b47f2a5a632e462ab0d4818247b2bdf.zip
FreeBSD-src-8de950a22b47f2a5a632e462ab0d4818247b2bdf.tar.gz
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.
Diffstat (limited to 'sys/kern/link_elf_obj.c')
-rw-r--r--sys/kern/link_elf_obj.c132
1 files changed, 55 insertions, 77 deletions
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index f7c0e2a..1f98c4c 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.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)
{
OpenPOWER on IntegriCloud