diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 8bc8692a9229..f1ffc3e3e4df 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1275,8 +1275,11 @@ init_dag(Obj_Entry *root) { DoneList donelist; + if (root->dag_inited) + return; donelist_init(&donelist); init_dag1(root, root, &donelist); + root->dag_inited = true; } static void @@ -2045,8 +2048,16 @@ dlopen(const char *name, int mode) } } else { - /* Bump the reference counts for objects on this DAG. */ - ref_dag(obj); + /* + * Bump the reference counts for objects on this DAG. If + * this is the first dlopen() call for the object that was + * already loaded as a dependency, initialize the dag + * starting at it. + */ + if (obj->dl_refcount == 1) + init_dag(obj); + else + ref_dag(obj); if (ld_tracing) goto trace; diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 6bae2f034b70..faa84e2d5acc 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -222,6 +222,7 @@ typedef struct Struct_Obj_Entry { bool ref_nodel : 1; /* Refcount increased to prevent dlclose */ bool init_scanned: 1; /* Object is already on init list. */ bool on_fini_list: 1; /* Object is already on fini list. */ + bool dag_inited : 1; /* Object has its DAG initialized. */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */