Date: Fri, 7 Sep 2001 00:25:13 -0700 (PDT) From: Steve Whiteley <stevew@wrcad.com> To: freebsd-gnats-submit@FreeBSD.org Subject: misc/30412: rtdl/dlopen() fails to merge common variables in 2 or more dlopen'ed libs Message-ID: <200109070725.f877PDl62797@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 30412 >Category: misc >Synopsis: rtdl/dlopen() fails to merge common variables in 2 or more dlopen'ed libs >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Sep 07 00:30:01 PDT 2001 >Closed-Date: >Last-Modified: >Originator: Steve Whiteley >Release: 4.3-stable >Organization: Whiteley Research Inc. >Environment: FreeBSD chaucer.srware.com 4.3-RC FreeBSD 4.3-RC #2: Sun Apr 22 14:16:02 PDT 2001 stevew@chaucer.srware.com:/usr3/obj/usr/src/sys/CHAUCER i386 >Description: It seems that in FreeBSD 4.3, if two shared libraries, each of which define an exported pointer variable of the same name, are opened using dlopen(), each pointer retains a unique address. This is different from Solaris and Linux, where the pointers are merged into a common symbol. For example, both libtcl and libtk (8.3.3) define tclStubsPtr. If these two libraries are opened with dlopen(..., RTLD_GLOBAL), calling Tk_Init() causes a seg fault on the first call of a tcl function from libtk. The problem is that the libtcl tclStubsPtr struct is being initialized, but the separate address of the tclStubsPtr in libtk which is resolved for all references in libtk remains a null pointer. Here is a mod to rtld.c in the rtld source that seems to fix the problem: In rtld.c near line 1862 in symlook_default() /**/ /* Search all RTLD_GLOBAL objects. */ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { symp = symlook_list(name, hash, &list_global, &obj, in_plt, &donelist); if (symp != NULL && (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { def = symp; defobj = obj; } } /* SRW ** block below was ahead of block above */ /* Search all dlopened DAGs containing the referencing object. */ STAILQ_FOREACH(elm, &refobj->dldags, link) { if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) break; symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt, &donelist); if (symp != NULL && (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { def = symp; defobj = obj; } } /**/ This will cause linkage to an exported symbol from the other dlopen'ed library, ahead of the variable local to the library whose references are being resolved. This would seem to be better logic, but there may be a disadvantage I have overlooked. My program works in Linux and Solaris. For FreeBSD I'm using a work-around that uses dlsym() to grab the two addresses and then explicitly setting the unset pointer. There is also an open problem report #25059 relating to dlopen(), possibly related? >How-To-Repeat: See "Full Description" >Fix: See "Full Description" >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200109070725.f877PDl62797>