From: kettenis Date: Tue, 23 Aug 2016 06:46:17 +0000 (+0000) Subject: Implement support for DT_INIT_ARRAY, DT_FINI_ARRAY and DT_PREINIT_ARRAY. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=86fa57a2792c6374b0849dd7b818a11e676e60ba;p=openbsd Implement support for DT_INIT_ARRAY, DT_FINI_ARRAY and DT_PREINIT_ARRAY. Don't skip DT_INIT and DT_FINI for the main executable. This matches what Linux and Solaris do. ok guenther@ --- diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c index 6fcff3d62ac..b85db853f89 100644 --- a/libexec/ld.so/loader.c +++ b/libexec/ld.so/loader.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loader.c,v 1.165 2016/08/14 04:30:39 guenther Exp $ */ +/* $OpenBSD: loader.c,v 1.166 2016/08/23 06:46:17 kettenis Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -53,6 +53,7 @@ void _dl_debug_state(void); void _dl_setup_env(const char *_argv0, char **_envp); void _dl_dtors(void); void _dl_fixup_user_env(void); +void _dl_call_preinit(elf_object_t *); void _dl_call_init_recurse(elf_object_t *object, int initfirst); int _dl_pagesz; @@ -73,9 +74,31 @@ struct r_debug *_dl_debug_map; void _dl_dopreload(char *paths); /* - * Run dtors for all objects that are eligible. + * Run dtors for a single object. */ +void +_dl_run_dtors(elf_object_t *obj) +{ + if (obj->dyn.fini_array) { + int num = obj->dyn.fini_arraysz / sizeof(Elf_Addr); + int i; + + DL_DEB(("doing finiarray obj %p @%p: [%s]\n", + obj, obj->dyn.fini_array, obj->load_name)); + for (i = num; i > 0; i--) + (*obj->dyn.fini_array[i-1])(); + } + if (obj->dyn.fini) { + DL_DEB(("doing dtors obj %p @%p: [%s]\n", + obj, obj->dyn.fini, obj->load_name)); + (*obj->dyn.fini)(); + } +} + +/* + * Run dtors for all objects that are eligible. + */ void _dl_run_all_dtors(void) { @@ -91,10 +114,10 @@ _dl_run_all_dtors(void) while (fini_complete == 0) { fini_complete = 1; - for (node = _dl_objects->next; + for (node = _dl_objects; node != NULL; node = node->next) { - if ((node->dyn.fini) && + if ((node->dyn.fini || node->dyn.fini_array) && (OBJECT_REF_CNT(node) == 0) && (node->status & STAT_INIT_DONE) && ((node->status & STAT_FINI_DONE) == 0)) { @@ -105,10 +128,10 @@ _dl_run_all_dtors(void) node->status |= STAT_FINI_READY; } } - for (node = _dl_objects->next; + for (node = _dl_objects; node != NULL; node = node->next ) { - if ((node->dyn.fini) && + if ((node->dyn.fini || node->dyn.fini_array) && (OBJECT_REF_CNT(node) == 0) && (node->status & STAT_INIT_DONE) && ((node->status & STAT_FINI_DONE) == 0) && @@ -120,18 +143,14 @@ _dl_run_all_dtors(void) } - for (node = _dl_objects->next; + for (node = _dl_objects; node != NULL; node = node->next ) { if (node->status & STAT_FINI_READY) { - DL_DEB(("doing dtors obj %p @%p: [%s]\n", - node, node->dyn.fini, - node->load_name)); - fini_complete = 0; node->status |= STAT_FINI_DONE; node->status &= ~STAT_FINI_READY; - (*node->dyn.fini)(); + _dl_run_dtors(node); } } @@ -157,11 +176,6 @@ _dl_dtors(void) DL_DEB(("doing dtors\n")); - /* main program runs its dtors itself - * but we want to run dtors on all it's children); - */ - _dl_objects->status |= STAT_FINI_DONE; - _dl_objects->opencount--; _dl_notify_unload_shlib(_dl_objects); @@ -605,14 +619,10 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data) _dl_debug_state(); /* - * The first object is the executable itself, - * it is responsible for running it's own ctors/dtors - * thus do NOT run the ctors for the executable, all of - * the shared libraries which follow. * Do not run init code if run from ldd. */ if (_dl_objects->next != NULL) { - _dl_objects->status |= STAT_INIT_DONE; + _dl_call_preinit(_dl_objects); _dl_call_init(_dl_objects); } @@ -689,6 +699,20 @@ _dl_rtld(elf_object_t *object) return (fails); } +void +_dl_call_preinit(elf_object_t *object) +{ + if (object->dyn.preinit_array) { + int num = object->dyn.preinit_arraysz / sizeof(Elf_Addr); + int i; + + DL_DEB(("doing preinitarray obj %p @%p: [%s]\n", + object, object->dyn.preinit_array, object->load_name)); + for (i = 0; i < num; i++) + (*object->dyn.preinit_array[i])(); + } +} + void _dl_call_init(elf_object_t *object) { @@ -723,6 +747,16 @@ _dl_call_init_recurse(elf_object_t *object, int initfirst) (*object->dyn.init)(); } + if (object->dyn.init_array) { + int num = object->dyn.init_arraysz / sizeof(Elf_Addr); + int i; + + DL_DEB(("doing initarray obj %p @%p: [%s]\n", + object, object->dyn.init_array, object->load_name)); + for (i = 0; i < num; i++) + (*object->dyn.init_array[i])(); + } + object->status |= STAT_INIT_DONE; } diff --git a/libexec/ld.so/resolve.c b/libexec/ld.so/resolve.c index dc384c7bed0..02d96833cb2 100644 --- a/libexec/ld.so/resolve.c +++ b/libexec/ld.so/resolve.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.c,v 1.74 2016/08/08 21:59:20 guenther Exp $ */ +/* $OpenBSD: resolve.c,v 1.75 2016/08/23 06:46:17 kettenis Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -246,6 +246,7 @@ _dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, int phdrc, const int objtype, const long lbase, const long obase) { elf_object_t *object; + #if 0 _dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n", objname, dynp, objtype, lbase, obase); @@ -322,6 +323,12 @@ _dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, object->Dyn.info[DT_FINI] += obase; if (object->Dyn.info[DT_JMPREL]) object->Dyn.info[DT_JMPREL] += obase; + if (object->Dyn.info[DT_INIT_ARRAY]) + object->Dyn.info[DT_INIT_ARRAY] += obase; + if (object->Dyn.info[DT_FINI_ARRAY]) + object->Dyn.info[DT_FINI_ARRAY] += obase; + if (object->Dyn.info[DT_PREINIT_ARRAY]) + object->Dyn.info[DT_PREINIT_ARRAY] += obase; if (object->Dyn.info[DT_HASH] != 0) { Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH]; diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h index df0469c9fc0..24dbef66133 100644 --- a/libexec/ld.so/resolve.h +++ b/libexec/ld.so/resolve.h @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.h,v 1.79 2016/08/08 21:59:20 guenther Exp $ */ +/* $OpenBSD: resolve.h,v 1.80 2016/08/23 06:46:17 kettenis Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -81,13 +81,23 @@ struct elf_object { const char *soname; const char *rpath; Elf_Addr symbolic; - Elf_Rel *rel; + Elf_Rel *rel; Elf_Addr relsz; Elf_Addr relent; Elf_Addr pltrel; Elf_Addr debug; Elf_Addr textrel; Elf_Addr jmprel; + Elf_Addr bind_now; + void (**init_array)(void); + void (**fini_array)(void); + Elf_Addr init_arraysz; + Elf_Addr fini_arraysz; + const char *runpath; + Elf_Addr flags; + Elf_Addr encoding; + void (**preinit_array)(void); + Elf_Addr preinit_arraysz; } u; } Dyn; #define dyn Dyn.u diff --git a/sys/sys/exec_elf.h b/sys/sys/exec_elf.h index f1c5d48dc16..f3186e6db6e 100644 --- a/sys/sys/exec_elf.h +++ b/sys/sys/exec_elf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.h,v 1.59 2016/07/14 06:03:46 guenther Exp $ */ +/* $OpenBSD: exec_elf.h,v 1.60 2016/08/23 06:46:17 kettenis Exp $ */ /* * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. * @@ -526,7 +526,7 @@ typedef struct { #define DF_1_CONLFAT 0x00002000 /* ld.so: number of low tags that are used saved internally (0 .. DT_NUM-1) */ -#define DT_NUM (DT_JMPREL+1) +#define DT_NUM (DT_PREINIT_ARRAYSZ+1) /* Standard ELF hashing function */ unsigned int elf_hash(const unsigned char *name);