The diff below adds support for DT_PREINIT_ARRAY, DT_INIT_ARRAY and DT_FINI_ARRAY to our ld.so. The idea is that these tags each point to a list of function pointers that get executed at initialization and termination time. Functions listed by DT_PREINIT_ARRAY get run immediately after ld.so has finished loading and relocating all shared objects. This happens only for the main executable. DT_INIT_ARRAY runs immediately after DT_INIT for an object, and DT_FINI_ARRAY immediately before DT_FINI. The functions listed by DT_FINI_ARRAY run in reversed order.
There is a functional change here. Our current ld.so doesn't run DT_INIT and DT_FINI for the main executable. The ELF standard is a bit ambiguous about this, but Linux does run tose for the main executable. And Solaris allegedly does as well. So my diff changes that. This stuff is apparently necessary for implementing the official ARM C++ ABI. Tested on hppa. ok? Index: loader.c =================================================================== RCS file: /cvs/src/libexec/ld.so/loader.c,v retrieving revision 1.165 diff -u -p -r1.165 loader.c --- loader.c 14 Aug 2016 04:30:39 -0000 1.165 +++ loader.c 17 Aug 2016 19:05:20 -0000 @@ -73,9 +73,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, 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 +113,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 +127,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 +142,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 +175,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,16 +618,10 @@ _dl_boot(const char **argv, char **envp, _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; + if (_dl_objects->next != NULL) _dl_call_init(_dl_objects); - } DL_DEB(("entry point: 0x%lx\n", dl_data[AUX_entry])); @@ -692,6 +699,16 @@ _dl_rtld(elf_object_t *object) void _dl_call_init(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])(); + } + _dl_call_init_recurse(object, 1); _dl_call_init_recurse(object, 0); } @@ -721,6 +738,16 @@ _dl_call_init_recurse(elf_object_t *obje DL_DEB(("doing ctors obj %p @%p: [%s]\n", object, object->dyn.init, object->load_name)); (*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; Index: resolve.c =================================================================== RCS file: /cvs/src/libexec/ld.so/resolve.c,v retrieving revision 1.74 diff -u -p -r1.74 resolve.c --- resolve.c 8 Aug 2016 21:59:20 -0000 1.74 +++ resolve.c 17 Aug 2016 19:05:20 -0000 @@ -246,6 +246,7 @@ _dl_finalize_object(const char *objname, 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, 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]; Index: resolve.h =================================================================== RCS file: /cvs/src/libexec/ld.so/resolve.h,v retrieving revision 1.79 diff -u -p -r1.79 resolve.h --- resolve.h 8 Aug 2016 21:59:20 -0000 1.79 +++ resolve.h 17 Aug 2016 19:05:20 -0000 @@ -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