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