diff options
Diffstat (limited to 'libexec/ld.so/loader.c')
-rw-r--r-- | libexec/ld.so/loader.c | 52 |
1 files changed, 40 insertions, 12 deletions
diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c index 3b40de37e50..a48dd495543 100644 --- a/libexec/ld.so/loader.c +++ b/libexec/ld.so/loader.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loader.c,v 1.125 2011/06/27 16:47:50 sthen Exp $ */ +/* $OpenBSD: loader.c,v 1.126 2011/11/28 20:59:03 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -59,6 +59,7 @@ void _dl_dtors(void); void _dl_boot_bind(const long, long *, Elf_Dyn *); void _dl_fixup_user_env(void); void _dl_set_sod(const char *, struct sod *); +void _dl_call_init_recurse(elf_object_t *object, int initfirst); const char *_dl_progname; int _dl_pagesz; @@ -94,13 +95,17 @@ _dl_set_sod(const char *path, struct sod *sod) */ void -_dl_run_all_dtors() +_dl_run_all_dtors(void) { elf_object_t *node; - int fini_complete; struct dep_node *dnode; + int fini_complete; + int skip_initfirst; + int initfirst_skipped; fini_complete = 0; + skip_initfirst = 1; + initfirst_skipped = 0; while (fini_complete == 0) { fini_complete = 1; @@ -111,7 +116,11 @@ _dl_run_all_dtors() (OBJECT_REF_CNT(node) == 0) && (node->status & STAT_INIT_DONE) && ((node->status & STAT_FINI_DONE) == 0)) { - node->status |= STAT_FINI_READY; + if (skip_initfirst && + (node->obj_flags & DF_1_INITFIRST)) + initfirst_skipped = 1; + else + node->status |= STAT_FINI_READY; } } for (node = _dl_objects->next; @@ -120,7 +129,9 @@ _dl_run_all_dtors() if ((node->dyn.fini) && (OBJECT_REF_CNT(node) == 0) && (node->status & STAT_INIT_DONE) && - ((node->status & STAT_FINI_DONE) == 0)) + ((node->status & STAT_FINI_DONE) == 0) && + (!skip_initfirst || + (node->obj_flags & DF_1_INITFIRST) == 0)) TAILQ_FOREACH(dnode, &node->child_list, next_sib) dnode->data->status &= ~STAT_FINI_READY; @@ -141,6 +152,9 @@ _dl_run_all_dtors() (*node->dyn.fini)(); } } + + if (fini_complete && initfirst_skipped) + fini_complete = initfirst_skipped = skip_initfirst = 0; } } @@ -265,8 +279,8 @@ _dl_load_dep_libs(elf_object_t *object, int flags, int booting) DL_DEB(("examining: '%s'\n", dynobj->load_name)); libcount = 0; - /* propagate RTLD_NOW to deplibs (can be set by dynamic tags) */ - depflags = flags | (dynobj->obj_flags & RTLD_NOW); + /* propagate DF_1_NOW to deplibs (can be set by dynamic tags) */ + depflags = flags | (dynobj->obj_flags & DF_1_NOW); for (dynp = dynobj->load_dyn; dynp->d_tag; dynp++) { if (dynp->d_tag == DT_NEEDED) { @@ -476,7 +490,7 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) phdp++; } exe_obj->load_list = load_list; - exe_obj->obj_flags |= RTLD_GLOBAL; + exe_obj->obj_flags |= DF_1_GLOBAL; exe_obj->load_size = maxva - minva; _dl_set_sod(exe_obj->load_name, &exe_obj->sod); @@ -840,7 +854,7 @@ _dl_rtld(elf_object_t *object) fails += _dl_md_reloc(object, DT_RELA, DT_RELASZ); prebind_symcache(object, SYM_PLT); fails += _dl_md_reloc_got(object, !(_dl_bindnow || - object->obj_flags & RTLD_NOW)); + object->obj_flags & DF_1_NOW)); if (_dl_symcache != NULL) { if (sz != 0) @@ -852,27 +866,41 @@ _dl_rtld(elf_object_t *object) return (fails); } + void _dl_call_init(elf_object_t *object) { + _dl_call_init_recurse(object, 1); + _dl_call_init_recurse(object, 0); +} + +void +_dl_call_init_recurse(elf_object_t *object, int initfirst) +{ struct dep_node *n; + object->status |= STAT_VISITED; + TAILQ_FOREACH(n, &object->child_list, next_sib) { - if (n->data->status & STAT_INIT_DONE) + if (n->data->status & STAT_VISITED) continue; - _dl_call_init(n->data); + _dl_call_init_recurse(n->data, initfirst); } + object->status &= ~STAT_VISITED; + if (object->status & STAT_INIT_DONE) return; + if (initfirst && (object->obj_flags & DF_1_INITFIRST) == 0) + return; + if (object->dyn.init) { DL_DEB(("doing ctors obj %p @%p: [%s]\n", object, object->dyn.init, object->load_name)); (*object->dyn.init)(); } - /* What about loops? */ object->status |= STAT_INIT_DONE; } |