## DANGER ## This is a hack, against old code, and is NOT thread safe etc etc. ## --- libexec/rtld-elf/amd64/reloc.c 2011-09-17 01:19:56.000000000 0000 +++ libexec/rtld-elf/amd64/reloc.c 2011-09-17 01:19:56.000000000 0000 @@ -155,6 +155,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where = (Elf_Addr) (defobj->relocbase + def->st_value + rela->r_addend); } break; @@ -174,6 +175,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where32 = (Elf32_Addr) (unsigned long) (defobj->relocbase + def->st_value + rela->r_addend - (Elf_Addr) where); } @@ -204,6 +206,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where = (Elf_Addr) (defobj->relocbase + def->st_value); } break; @@ -234,6 +237,7 @@ } } + rtld_add_rundep_if_needed(obj, defobj); *where = (Elf_Addr) (def->st_value - defobj->tlsoffset + rela->r_addend); } @@ -265,6 +269,7 @@ } } + rtld_add_rundep_if_needed(obj, defobj); *where32 = (Elf32_Addr) (def->st_value - defobj->tlsoffset + rela->r_addend); @@ -281,6 +286,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where += (Elf_Addr) defobj->tlsindex; } break; @@ -295,6 +301,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where += (Elf_Addr) (def->st_value + rela->r_addend); } break; @@ -309,6 +316,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where32 += (Elf32_Addr) (def->st_value + rela->r_addend); } break; @@ -374,6 +382,7 @@ lockstate); if (def == NULL) return -1; + rtld_add_rundep_if_needed(obj, defobj); target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend); reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela); } --- //depot/yahoo/ybsd_next/src/libexec/rtld-elf/i386/reloc.c 2011-09-17 01:19:56.000000000 0000 +++ /home/peter/ybsd_next/src/libexec/rtld-elf/i386/reloc.c 2011-09-17 01:19:56.000000000 0000 @@ -155,6 +155,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where += (Elf_Addr) (defobj->relocbase + def->st_value); } break; @@ -174,6 +175,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where += (Elf_Addr) (defobj->relocbase + def->st_value) - (Elf_Addr) where; @@ -204,6 +206,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where = (Elf_Addr) (defobj->relocbase + def->st_value); } break; @@ -238,6 +241,7 @@ } } + rtld_add_rundep_if_needed(obj, defobj); *where += (Elf_Addr) (def->st_value - defobj->tlsoffset); } break; @@ -252,6 +256,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where += (Elf_Addr) defobj->tlsindex; } break; @@ -266,6 +271,7 @@ if (def == NULL) goto done; + rtld_add_rundep_if_needed(obj, defobj); *where += (Elf_Addr) def->st_value; } break; @@ -325,6 +331,7 @@ lockstate); if (def == NULL) return -1; + rtld_add_rundep_if_needed(obj, defobj); target = (Elf_Addr)(defobj->relocbase + def->st_value); reloc_jmpslot(where, target, defobj, obj, rel); } --- //depot/yahoo/ybsd_next/src/libexec/rtld-elf/map_object.c 2011-09-17 01:19:56.000000000 0000 +++ /home/peter/ybsd_next/src/libexec/rtld-elf/map_object.c 2011-09-17 01:19:56.000000000 0000 @@ -378,6 +378,7 @@ STAILQ_INIT(&obj->dldags); STAILQ_INIT(&obj->dagmembers); STAILQ_INIT(&obj->names); + STAILQ_INIT(&obj->rundeps); return obj; } --- //depot/yahoo/ybsd_next/src/libexec/rtld-elf/rtld.c 2011-09-17 17:10:30.000000000 0000 +++ /home/peter/ybsd_next/src/libexec/rtld-elf/rtld.c 2011-09-17 17:10:30.000000000 0000 @@ -139,6 +139,7 @@ static int origin_subst_one(char **, const char *, const char *, const char *, char *); static char *origin_subst(const char *, const char *); +static void unref_runtime(Obj_Entry *); static int rtld_verify_versions(const Objlist *); static int rtld_verify_object_versions(Obj_Entry *); static void object_add_name(Obj_Entry *, const char *); @@ -604,6 +610,99 @@ return (func_ptr_type) obj_main->entry; } + +static +void garbageCollectObjects() +{ + Objlist_Entry *elm; + Obj_Entry *obj; + SLIST_HEAD(, Struct_Obj_Entry) worklist; + Needed_Entry *needed; + + SLIST_INIT(&worklist); + + + /* + * Mark all objects as non reachable except dlopened objects + * and unloadable objects + */ + for(obj = obj_list; obj != NULL; obj = obj->next) { + if (obj->dl_refcount > 0 || obj->unloadable) { + obj->reachable = 1; + SLIST_INSERT_HEAD(&worklist,obj,gcworklistlink); + } else { + obj->reachable = 0; + } + } + + + /* Mark all objects loaded at program start as reachable */ + STAILQ_FOREACH(elm,&list_main, link) { + if (!elm->obj->reachable) { + elm->obj->reachable = 1; + SLIST_INSERT_HEAD(&worklist,elm->obj,gcworklistlink); + } + } + + /* For all reachable objects */ + + while(!SLIST_EMPTY(&worklist)) { + + obj = SLIST_FIRST(&worklist); + SLIST_REMOVE_HEAD(&worklist,gcworklistlink); + + /* All needed objects of a reachable objects are reachable */ + for (needed = obj->needed; needed != NULL; needed = needed->next) { + if (needed->obj != NULL && needed->obj->reachable == 0) { + needed->obj->reachable = 1; + SLIST_INSERT_HEAD(&worklist,needed->obj,gcworklistlink); + } + } + + /* All runtime deps are reachable */ + STAILQ_FOREACH(elm, &obj->rundeps, link) { + if (elm->obj->reachable == 0) { + elm->obj->reachable = 1; + SLIST_INSERT_HEAD(&worklist,elm->obj,gcworklistlink); + } + } + } + + + /* + * Now throw away all runtime dependencies of unreachable objects. + */ + + for(obj = obj_list; obj != NULL; obj = obj->next) { + if (!obj->reachable && obj->refcount != 0) + unref_runtime(obj); + } + +} + +static inline int +rtld_needs_rundep(Obj_Entry *from, const Obj_Entry* to) +{ + + return (!(from == to || + from->refcount == 0 || + to->refcount == 0 || + objlist_find(&list_main, to) || + objlist_find(&from->dagmembers, to) || + objlist_find(&from->rundeps, to))); +} + +void +rtld_add_rundep_if_needed(Obj_Entry *from, const Obj_Entry* to) +{ + if(rtld_needs_rundep(from,to)) { + objlist_push_tail(&from->rundeps, (Obj_Entry*) to); + ref_dag((Obj_Entry *) to); + LD_UTRACE(UTRACE_ADD_RUNDEP,(Obj_Entry*) to, from, 0, + to->refcount, to->path); + } +} + Elf_Addr _rtld_bind(Obj_Entry *obj, Elf_Size reloff) { @@ -642,6 +741,15 @@ * that the trampoline needs. */ target = reloc_jmpslot(where, target, defobj, obj, rel); + if (rtld_needs_rundep(obj, defobj)) { + lock_upgrade(rtld_bind_lock, &lockstate); + if (!objlist_find(&obj->rundeps, defobj)) { + objlist_push_tail(&obj->rundeps, (Obj_Entry *)defobj); + ref_dag((Obj_Entry *)defobj); + LD_UTRACE(UTRACE_ADD_RUNDEP, (Obj_Entry *)defobj, obj, 0, + defobj->refcount, defobj->path); + } + } lock_release(rtld_bind_lock, &lockstate); return target; } @@ -2325,6 +2433,7 @@ objlist_call_fini(&list_fini, root, &lockstate); unref_dag(root); + garbageCollectObjects(); /* Finish cleaning up the newly-unreferenced objects. */ GDB_STATE(RT_DELETE,&root->linkmap); @@ -2435,8 +2544,10 @@ == RTLD_NOW, &obj_rtld, &lockstate)) == -1) { obj->dl_refcount--; unref_dag(obj); - if (obj->refcount == 0) + if (obj->refcount == 0) { + garbageCollectObjects(); unload_object(obj); + } obj = NULL; } else { /* Make list of init functions to call. */ @@ -3532,6 +3643,7 @@ if (obj->refcount == 0) { LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, obj->path); + unlink_object(obj); dbg("unloading \"%s\"", obj->path); unload_filtees(root); munmap(obj->mapbase, obj->mapsize); @@ -3550,17 +3662,12 @@ { Objlist_Entry *elm; - if (root->refcount == 0) { - /* Remove the object from the RTLD_GLOBAL list. */ - objlist_remove(&list_global, root); + /* Remove the object from the RTLD_GLOBAL list. */ + objlist_remove(&list_global, root); - /* Remove the object from all objects' DAG lists. */ - STAILQ_FOREACH(elm, &root->dagmembers, link) { - objlist_remove(&elm->obj->dldags, root); - if (elm->obj != root) - unlink_object(elm->obj); - } - } + /* Remove the object from all objects' DAG lists. */ + STAILQ_FOREACH(elm, &root->dagmembers, link) + objlist_remove(&elm->obj->dldags, root); } #ifdef __i386__ @@ -3583,8 +3690,11 @@ Objlist_Entry *elm; assert(root->dag_inited); - STAILQ_FOREACH(elm, &root->dagmembers, link) - elm->obj->refcount++; + if (STAILQ_EMPTY(&root->dagmembers)) + init_dag(root); + else + STAILQ_FOREACH(elm, &root->dagmembers, link) + elm->obj->refcount++; } static void @@ -3593,8 +3703,23 @@ Objlist_Entry *elm; assert(root->dag_inited); - STAILQ_FOREACH(elm, &root->dagmembers, link) + STAILQ_FOREACH(elm, &root->dagmembers, link) { elm->obj->refcount--; + if (elm->obj->refcount == 0) + unref_runtime(elm->obj); + } +} + +static void +unref_runtime(Obj_Entry *obj) +{ + Objlist_Entry *elm; + while (!STAILQ_EMPTY(&obj->rundeps)) { + elm = STAILQ_FIRST(&obj->rundeps); + STAILQ_REMOVE_HEAD(&obj->rundeps, link); + unref_dag(elm->obj); + free(elm); + } } /* --- //depot/yahoo/ybsd_next/src/libexec/rtld-elf/rtld.h 2011-09-17 17:16:31.000000000 0000 +++ /home/peter/ybsd_next/src/libexec/rtld-elf/rtld.h 2011-09-17 17:16:31.000000000 0000 @@ -238,7 +238,10 @@ ino_t ino; /* Object's inode number */ void *priv; /* Platform-dependant */ int32_t buildosver; /* Build OS Version */ + Objlist rundeps; /* Run time rependency has these members (%) */ + bool reachable; /* Object is globally reachable */ bool unloadable; /* Object is unloadable */ + SLIST_ENTRY(Struct_Obj_Entry) gcworklistlink; /* Used during garbage collection */ } Obj_Entry; #define RTLD_MAGIC 0xd550b87a @@ -321,6 +324,7 @@ void _rtld_bind_start(void); void symlook_init(SymLook *, const char *); int symlook_obj(SymLook *, const Obj_Entry *); +void rtld_add_rundep_if_needed(Obj_Entry *from, const Obj_Entry* to); void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset); void *allocate_tls(Obj_Entry *, void *, size_t, size_t); void free_tls(void *, size_t, size_t);