summaryrefslogtreecommitdiff
path: root/ldso
AgeCommit message (Collapse)AuthorLines
2023-01-18fix debugger tracking of shared libraries on mips with PIE main programRich Felker-0/+4
mips has its own mechanisms for DT_DEBUG because it makes _DYNAMIC read-only, and the original mechanism, DT_MIPS_RLD_MAP, was PIE-incompatible. DT_MIPS_RLD_MAP_REL was added to remedy this, but we never implemented support for it. add it now using the same idioms for mips-specific ldso logic.
2022-11-30ldso: fix invalid early references to extern-linkage libc.page_sizeRich Felker-1/+8
when PAGE_SIZE is not constant, internal/libc.h defines it to expand to libc.page_size. however, kernel_mapped_dso, reachable from stage 2 of the dynamic linker bootstrap (__dls2), needs PAGE_SIZE to interpret the relro range. at this point the libc object is both uninitialized and invalid to access according to our model for bootstrapping, which does not assume any external-linkage objects are accessible until stages 2b/3. in practice it likely worked because hidden visibility tends to behave like internal linkage, but this is not a property that the dynamic linker was designed to rely upon. this bug likely manifested as relro malfunction on archs with variable page size, due to incorrect mask when aligning the relro bounds to page boundaries. while there are certainly more direct ways to fix the known problem point here, a maximally future-proof way is to just bypass the libc.h PAGE_SIZE definition in the dynamic linker and instead have dynlink.c define its own internal-linkage object for variable page size. then, if anything else in stage 2 ever ends up referencing PAGE_SIZE, it will just automatically work right.
2022-11-10fix double-processing of DT_RELR relocations in ldso relocating itselfRich Felker-0/+1
this is analogous to skip_relative logic in do_relocs -- because relative relocations for the dynamic linker itself were already performed at entry (stage 1), they must not be applied again.
2022-10-19remove LFS64 symbol aliases; replace with dynamic linker remappingRich Felker-0/+34
originally the namespace-infringing "large file support" interfaces were included as part of glibc-ABI-compat, with the intent that they not be used for linking, since our off_t is and always has been unconditionally 64-bit and since we usually do not aim to support nonstandard interfaces when there is an equivalent standard interface. unfortunately, having the symbols present and available for linking caused configure scripts to detect them and attempt to use them without declarations, producing all the expected ill effects that entails. as a result, commit 2dd8d5e1b8ba1118ff1782e96545cb8a2318592c was made to prevent this, using macros to redirect the LFS64 names to the standard names, conditional on _GNU_SOURCE or _LARGEFILE64_SOURCE. however, this has turned out to be a source of further problems, especially since g++ defines _GNU_SOURCE by default. in particular, the presence of these names as macros breaks a lot of valid code. this commit removes all the LFS64 symbols and replaces them with a mechanism in the dynamic linker symbol lookup failure path to retry with the spurious "64" removed from the symbol name. in the future, if/when the rest of glibc-ABI-compat is moved out of libc, this can be removed.
2022-09-12process DT_RELR relocations in ldso-startup/static-pieRich Felker-0/+15
commit d32dadd60efb9d3b255351a3b532f8e4c3dd0db1 added DT_RELR processing for programs and shared libraries processed by the dynamic linker, but left them unsupported in the dynamic linker itseld and in static pie binaries, which self-relocate via code in dlstart.c. add the equivalent processing to this code path so that there are not arbitrary restrictions on where the new packed relative relocation form can be used.
2022-08-17ldso: make exit condition clearer in fixup_rpathÉrico Nogueira-1/+1
breaking out of the switch-case when l==-1 means the conditional below will necessarily be true (-1 >= buf_size, a size_t variable) and the function will return 0. it is, however, somewhat unclear that that's what's happening. simply returning there is simpler
2022-08-02ldso: process RELR only for non-FDPIC archsRich Felker-1/+2
the way RELR is applied is not a meaningful operation for FDPIC (there is no single "base" address). it seems unlikely RELR would ever be added for FDPIC, but if it ever is, the behavior and possibly data format will need to be different, so guard against calling the non-FDPIC code.
2022-08-02ldso: support DT_RELR relative relocation formatFangrui Song-1/+20
this resolves DT_RELR relocations in non-ldso, dynamic-linked objects.
2022-07-19early stage ldso: remove symbolic references via error handling functionRich Felker-2/+11
while the error handling function should not be reached in stage 2 (assuming ldso itself was linked correctly), this was not statically determinate from the compiler's perspective, and in theory a compiler performing LTO could lift the TLS references (errno and other things) out of the printf-family functions called in a stage where TLS is not yet initialized. instead, perform the call via a static-storage, internal-linkage function pointer which will be set to a no-op function until the stage where the real error handling function should be reachable. inspired by commit 63c67053a3e42e9dff788de432f82ff07d4d772a.
2022-07-02in early stage ldso before __dls2b, call mprotect with __syscallAlex Xu (Hello71)-6/+8
if LTO is enabled, gcc hoists the call to ___errno_location outside the loop even though the access to errno is gated behind head != &ldso because ___errno_location is marked __attribute__((const)). this causes the program to crash because TLS is not yet initialized when called from __dls2. this is also possible if LTO is not enabled; even though gcc 11 doesn't do it, it is still wrong to use errno here. since the start and end are already aligned, we can simply call __syscall instead of using global errno. Fixes: e13a2b8953ef ("implement PT_GNU_RELRO support")
2021-04-20remove unnecessary cast for map_library returnÉrico Nogueira-1/+1
the function already returns (void *)
2021-04-16fix regression in dl_iterate_phdr reporting of modules with no TLSRich Felker-1/+2
__tls_get_addr should not be called with an invalid TLS module id of 0. in practice it probably "works", returning the DTV length as if it were a pointer, and the callback should probably not inspect dlpi_tls_data in this case, but it's likely that some real-world callbacks use a check on dlpi_tls_data being non-null, rather than on dlpi_tls_modid being nonzero, to conclude that the module has TLS.
2021-03-26fix dl_iterate_phdr dlpi_tls_data reporting to match specRich Felker-1/+1
dl_iterate_phdr was wrongly reporting the address of the DSO's PT_TLS image rather than the calling thread's instance of the TLS. the man page, which is essentially normative for a nonstandard function of this sort, clearly specifies the latter. it does not clarify where exactly within/relative-to the image the pointer should point, but the reasonable thing to do is match the ABI's DTP offset, and this seems to be what other implementations do.
2021-03-05don't fail to map library/executable with zero-length segment mapsRich Felker-0/+1
reportedly the GNU linker can emit such segments, causing spurious failure to load due to mmap with a length of zero producing EINVAL. no action is required for such a load map (it's effectively a nop in the program headers table) so just treat it as always successful.
2020-11-11lift child restrictions after multi-threaded forkRich Felker-0/+19
as the outcome of Austin Group tracker issue #62, future editions of POSIX have dropped the requirement that fork be AS-safe. this allows but does not require implementations to synchronize fork with internal locks and give forked children of multithreaded parents a partly or fully unrestricted execution environment where they can continue to use the standard library (per POSIX, they can only portably use AS-safe functions). up until recently, taking this allowance did not seem desirable. however, commit 8ed2bd8bfcb4ea6448afb55a941f4b5b2b0398c0 exposed the extent to which applications and libraries are depending on the ability to use malloc and other non-AS-safe interfaces in MT-forked children, by converting latent very-low-probability catastrophic state corruption into predictable deadlock. dealing with the fallout has been a huge burden for users/distros. while it looks like most of the non-portable usage in applications could be fixed given sufficient effort, at least some of it seems to occur in language runtimes which are exposing the ability to run unrestricted code in the child as part of the contract with the programmer. any attempt at fixing such contracts is not just a technical problem but a social one, and is probably not tractable. this patch extends the fork function to take locks for all libc singletons in the parent, and release or reset those locks in the child, so that when the underlying fork operation takes place, the state protected by these locks is consistent and ready for the child to use. locking is skipped in the case where the parent is single-threaded so as not to interfere with legacy AS-safety property of fork in single-threaded programs. lock order is mostly arbitrary, but the malloc locks (including bump allocator in case it's used) must be taken after the locks on any subsystems that might use malloc, and non-AS-safe locks cannot be taken while the thread list lock is held, imposing a requirement that it be taken last.
2020-11-11convert malloc use under libc-internal locks to use internal allocatorRich Felker-0/+5
this change lifts undocumented restrictions on calls by replacement mallocs to libc functions that might take these locks, and sets the stage for lifting restrictions on the child execution environment after multithreaded fork. care is taken to #define macros to replace all four functions (malloc, calloc, realloc, free) even if not all of them will be used, using an undefined symbol name for the ones intended not to be used so that any inadvertent future use will be caught at compile time rather than directed to the wrong implementation.
2020-11-11drop use of getdelim/stdio in dynamic linkerRich Felker-5/+22
the only place stdio was used here was for reading the ldso path file, taking advantage of getdelim to automatically allocate and resize the buffer. the motivation for use here was that, with shared libraries, stdio is already available anyway and free to use. this has long been a nuisance to users because getdelim's use of realloc here triggered a valgrind bug, but removing it doesn't really fix that; on some archs even calling the valgrind-interposed malloc at this point will crash. the actual motivation for this change is moving towards getting rid of use of application-provided malloc in parts of libc where it would be called with libc-internal locks held, leading to the possibility of deadlock if the malloc implementation doesn't follow unwritten rules about which libc functions are safe for it to call. since getdelim is required to produce a pointer as if by malloc (i.e. that can be passed to reallor or free), it necessarily must use the public malloc. instead of performing a realloc loop as the path file is read, first query its size with fstat and allocate only once. this produces slightly different truncation behavior when racing with writes to a file, but neither behavior is or could be made safe anyway; on a live system, ldso path files should be replaced by atomic rename only. the change should also reduce memory waste.
2020-10-27ldso: notify the debugger when we're doing a dlopenrcombs-2/+6
Otherwise lldb doesn't notice the new library and stack traces containing it get cut off unhelpfully.
2020-10-14ldso: use pthread_t rather than kernel tid to track ctor visitorRich Felker-3/+3
commit 188759bbee057aa94db2bbb7cf7f5855f3b9ab53 documented the intent to allow recursive dlopen based on tracking ctor_visitor, but used a kernel tid rather than the pthread_t to identify the caller. as a result, it would not behave as intended under fork by a ctor, where the child tid would not match.
2020-10-14fix stale lock when allocation of ctor queue fails during dlopenRich Felker-1/+2
queue_ctors should not be called with the init_fini_lock held, since it may longjmp out on allocation failure. this introduces a minor TOCTOU race with p->constructed, but one already exists further down anyway, and by design it's okay to run through the queue more than once anyway. the only reason we bother to check p->constructed at all is to avoid spurious failure of dlopen when the library is already fully loaded and constructed.
2020-08-27remove redundant pthread struct members repeated for layout purposesRich Felker-1/+1
dtv_copy, canary2, and canary_at_end existed solely to match multiple ABI and asm-accessed layouts simultaneously. now that pthread_arch.h can be included before struct __pthread is defined, the struct layout can depend on macros defined by pthread_arch.h.
2020-06-10have ldso track replacement of aligned_allocRich Felker-0/+2
this is in preparation for improving behavior of malloc interposition.
2020-06-02move declaration of interfaces between malloc and ldso to dynlink.hRich Felker-1/+0
this eliminates consumers of malloc_impl.h outside of the malloc implementation.
2020-03-20ldso: remove redundant switch case for REL_NONEFangrui Song-2/+0
as a result of commit b6a6cd703ffefa6352249fb01f4da28d85d17306, the REL_NONE case is now redundant.
2020-01-15fix incorrect __hwcap seen in dynamic-linked __set_thread_areaRich Felker-1/+1
the bug fixed in commit b82cd6c78d812d38c31febba5a9e57dbaa7919c4 was mostly masked on arm because __hwcap was zero at the point of the call from the dynamic linker to __set_thread_area, causing the access to libc.auxv to be skipped and kuser_helper versions of TLS access and atomics to be used instead of the armv6 or v7 versions. however, on kernels with kuser_helper removed for hardening it would crash. since __set_thread_area potentially uses __hwcap, it must be initialized before the function is called. move the AT_HWCAP lookup from stage 3 to stage 2b.
2020-01-01fix fdpic regression in dynamic linker with overly smart compilersRich Felker-2/+8
at least gcc 9 broke execution of DT_INIT/DT_FINI for fdpic archs (presently only sh) by recognizing that the stores to the compound-literal function descriptor constructed to call them were dead stores. there's no way to make a "may_alias function", so instead launder the descriptor through an asm-statement barrier. in practice just making the compound literal volatile seemed to have worked too, but this should be less of a hack and more accurately convey the semantics of what transformations are not valid.
2019-12-31fix crashing ldso on archs where __set_thread_area examines auxvRich Felker-13/+13
commit 1c84c99913bf1cd47b866ed31e665848a0da84a2 moved the call to __init_tp above the initialization of libc.auxv, inadvertently breaking archs where __set_thread_area examines auxv for the sake of determining the TLS/atomic model needed at runtime. this broke armv6 and sh2.
2019-12-31move stage3_func typedef out of shared internal dynlink.h headerRich Felker-0/+2
this interface contract is entirely internal to dynlink.c.
2019-11-02add time64 redirect for, and redirecting implementation of, dlsymRich Felker-0/+27
if symbols are being redirected to provide the new time64 ABI, dlsym must perform matching redirections; otherwise, it would poke a hole in the magic and return pointers to functions that are not safe to call from a caller using time64 types. rather than duplicating a table of redirections, use the time64 symbols present in libc's symbol table to derive the decision for whether a particular symbol needs to be redirected.
2019-08-13fix regression whereby main thread didn't get TLS relocationsRich Felker-7/+13
commit ffab43602b5900c86b7040abdda8ccf6cdec95f5 broke this by moving relocations after not only the allocation of storage for the main thread's static TLS, but after the copying of the TLS image. thus, relocation results were not reflected in the main thread's copy. this could be fixed by calling __reset_tls after relocations, but instead split the allocation and installation before/after relocations so that there's not a redundant copy. due to commit 71af5309874269bcc9e4b84ea716fab33d888c1d, updating of static_tls_cnt needs to be kept with allocation of static TLS, before relocations, rather than after installation.
2019-08-12make relocation time symbol lookup and dlsym consistentSzabolcs Nagy-53/+31
Using common code path for all symbol lookups fixes three dlsym issues: - st_shndx of STT_TLS symbols were not checked and thus an undefined tls symbol reference could be incorrectly treated as a definition (the sysv hash lookup returns undefined symbols, gnu does not, so should be rare in practice). - symbol binding was not checked so a hidden symbol may be returned (in principle STB_LOCAL symbols may appear in the dynamic symbol table for hidden symbols, but linkers most likely don't produce it). - mips specific behaviour was not applied (ARCH_SYM_REJECT_UND) so undefined symbols may be returned on mips. always_inline is used to avoid relocation performance regression, the code generation for find_sym should not be affected.
2019-08-12ldso: correct condition for local symbol handling in do_relocsRich Felker-1/+1
commit 7a9669e977e5f750cf72ccbd2614f8b72ce02c4c added use of the symbol reference as the definition, in place of performing a lookup, for STT_SECTION symbol references that were first found used in FDPIC. such references may happen in certain other cases, such as local-dynamic TLS and with relocation types that require a symbol but that are being used for non-symbolic purposes, like the powerpc unaligned address relocations. in all such cases I'm aware of, the symbol referenced is a section symbol (STT_SECTION); however, the important semantic property is not its being a section, but rather its binding local (STB_LOCAL). check the latter instead of the former for greater generality and semantic correctness.
2019-08-11add support for powerpc/powerpc64 unaligned relocationsSamuel Holland-0/+3
R_PPC_UADDR32 (R_PPC64_UADDR64) has the same meaning as R_PPC_ADDR32 (R_PPC64_ADDR64), except that its address need not be aligned. For powerpc64, BFD ld(1) will automatically convert between ADDR<->UADDR relocations when the address is/isn't at its native alignment. This will happen if, for example, there is a pointer in a packed struct. gold and lld do not currently generate R_PPC64_UADDR64, but pass through misaligned R_PPC64_ADDR64 relocations from object files, possibly relaxing them to misaligned R_PPC64_RELATIVE. In both cases (relaxed or not) this violates the PSABI, which defines the relevant field type as "a 64-bit field occupying 8 bytes, the alignment of which is 8 bytes unless otherwise specified." All three linkers violate the PSABI on 32-bit powerpc, where the only difference is that the field is 32 bits wide, aligned to 4 bytes. Currently musl fails to load executables linked by BFD ld containing R_PPC64_UADDR64, with the error "unsupported relocation type 43". This change provides compatibility with BFD ld on powerpc64, and any static linker on either architecture that starts following the PSABI more closely.
2019-08-11ldso: remove redundant runtime checks in static TLS logicRich Felker-2/+2
as a result of commit ffab43602b5900c86b7040abdda8ccf6cdec95f5, static_tls_cnt is now valid during relocations at program startup, so it's no longer necessary to condition the check against static_tls_cnt on this being a runtime (dlopen) relocation.
2019-08-11ldso: fix calloc misuse allocating initial tlsRich Felker-5/+7
this is analogous to commit 2f1f51ae7b2d78247568e7fdb8462f3c19e469a4, and should have been caught at the same time since it was right next to the code moved in that commit. between final stage 3 reloc_all and the jump to the main program's entry point, it is not valid to call any functions which may be interposed by the application; doing so results in execution of application code before ctors have run, and on fdpic archs, before the main program's fdpic self-fixups have taken place, which will produce runaway wrong execution.
2019-07-06fix inadvertent use of uninitialized variable in dladdrRich Felker-1/+1
commit c8b49b2fbc7faa8bf065220f11963d76c8a2eb93 introduced code that checked bestsym to determine whether a matching symbol was found, but bestsym is uninitialized if not. instead use best, consistent with use in the rest of the function. simplified from bug report and patch by Cheng Liu.
2019-06-25remove unnecessary and problematic _Noreturn from crt/ldso startupRich Felker-2/+2
after commit a48ccc159a5fa061a18419296100ee48a1cd6cc9 removed the use of _Noreturn on the stage3_func type (which only worked due to it being defined to the "GNU C" attribute in C99 mode), GCC could no longer assume that the ends of __dls2 and __dls2b are unreachable, and produced a warning that a function marked _Noreturn returns. also, since commit 4390383b32250a941ec616e8bff6f568a801b1c0, the _Noreturn declaration for __libc_start_main in crt1/rcrt1 has been not only inconsistent with the definition, but wrong. formally, __libc_start_main does return, via a (hopefully) tail call to a helper function after the barrier. incorrect usage of _Noreturn in the declaration was probably formal UB. the _Noreturn specifiers were not useful in any of these places, so remove them all. now, the only remaining usage of _Noreturn is in public interfaces where _Noreturn is part of their contract.
2019-05-16fix tls offsets when p_vaddr%p_align != 0 on TLS_ABOVE_TP targetsSzabolcs Nagy-3/+4
currently the bfd linker does not seem to create tls segments where p_vaddr%p_align != 0, but this is valid in ELF and then the runtime computed tls offset must satisfy offset%p_align == (base+p_vaddr)%p_align and in case of local exec tls (main executable) the smallest such offset must be used (otherwise it is incompatible with the offset computed by the static linker). the !TLS_ABOVE_TP case is handled correctly (the offset is negative then in the formula). the ldso code for TLS_ABOVE_TP is changed so the static tls offset of each module satisfies the formula.
2019-05-16fix static tls offsets of shared libs on TLS_ABOVE_TP targetsSzabolcs Nagy-4/+2
tls_offset should always point to the end of the allocated static tls area, but this was not handled correctly on "tls variant 1" targets in the dynamic linker: after application tls was allocated, tls_offset was aligned up, potentially wasting tls space. (alignment may be needed at the begining of the tls area, not at the end, but that will be fixed separately as it is unlikely to affect real binaries.) when static tls was allocated for a shared library, tls_offset was only updated with the size of the tls segment which does not include alignment gaps, which can easily happen if the tls size update for one library leaves tls_offset misaligned for the next one. this can cause oob access in __copy_tls or arbitrary breakage at tls access. (the issue was observed on aarch64 with rust binaries)
2019-05-12remove unused struct dso members from dynlink.cFangrui Song-1/+0
maintainer's note: commit 9d44b6460ab603487dab4d916342d9ba4467e6b9 removed their use.
2019-04-10overhaul i386 syscall mechanism not to depend on external asm sourceRich Felker-0/+3
this is the first part of a series of patches intended to make __syscall fully self-contained in the object file produced using syscall.h, which will make it possible for crt1 code to perform syscalls. the (confusingly named) i386 __vsyscall mechanism, which this commit removes, was introduced before the presence of a valid thread pointer was mandatory; back then the thread pointer was setup lazily only if threads were used. the intent was to be able to perform syscalls using the kernel's fast entry point in the VDSO, which can use the sysenter (Intel) or syscall (AMD) instruction instead of int $128, but without inlining an access to the __syscall global at the point of each syscall, which would incur a significant size cost from PIC setup everywhere. the mechanism also shuffled registers/calling convention around to avoid spills of call-saved registers, and to avoid allocating ebx or ebp via asm constraints, since there are plenty of broken-but-supported compiler versions which are incapable of allocating ebx with -fPIC or ebp with -fno-omit-frame-pointer. the new mechanism preserves the properties of avoiding spills and avoiding allocation of ebx/ebp in constraints, but does it inline, using some fairly simple register shuffling, and uses a field of the thread structure rather than global data for the vdso-provided syscall code address. for now, the external __syscall function is refactored not to use the old __vsyscall so it can be kept, but the intent is to remove it too.
2019-04-06fix the use of syscall result in dl_mmapIlya Matveychikov-1/+1
2019-04-02delete a redundant if in dynamic linker ctor execution loopRay-1/+0
2019-03-10fix invalid-/double-/use-after-free in new dlopen ctor executionRich Felker-1/+2
this affected the error path where dlopen successfully found and loaded the requested dso and all its dependencies, but failed to resolve one or more relocations, causing the operation to fail after storage for the ctor queue was allocated. commit 188759bbee057aa94db2bbb7cf7f5855f3b9ab53 wrongly put the free for the ctor_queue array in the error path inside a loop over each loaded dso that needed to be backed-out, rather than just doing it once. in addition, the exit path also observed the ctor_queue pointer still being nonzero, and would attempt to call ctors on the backed-out dsos unless the double-free crashed the process first.
2019-03-03avoid malloc of ctor queue for programs with no external depsRich Felker-2/+9
together with the previous two commits, this completes restoration of the property that dynamic-linked apps with no external deps and no tls have no failure paths before entry.
2019-03-03avoid malloc of deps arrays for ldso and vdsoRich Felker-0/+3
neither has or can have any dependencies, but since commit 403555690775f7c8806372644f543518e6664e3b, gratuitous zero-length deps arrays were being allocated for them. use a dummy array instead.
2019-03-03avoid malloc of deps array for programs with no external depsRich Felker-3/+10
traditionally, we've provided a guarantee that dynamic-linked applications with no external dependencies (nothing but libc) and no thread-local storage have no failure paths before the entry point. normally, thanks to reclaim_gaps, such a malloc will not require a syscall anyway, but if segment alignment is unlucky, it might. use a builtin array for this common special case.
2019-03-03fix malloc misuse for startup ctor queue, breakage on fdpic archsRich Felker-5/+9
in the case where malloc is being replaced, it's not valid to call malloc between final relocations and main app's crt1 entry point; on fdpic archs the main app's entry point will not yet have performed the self-fixups necessary to call its code. to fix, reorder queue_ctors before final relocations. an alternative solution would be doing the allocation from __libc_start_init, after the entry point but before any ctors run. this is less desirable, since it would leave a call to malloc that might be provided by the application happening at startup when doing so can be easily avoided.
2019-03-03synchronize shared library dtor exec against concurrent loads/ctorsRich Felker-1/+17
previously, going way back, there was simply no synchronization here. a call to exit concurrent with ctor execution from dlopen could cause a dtor to execute concurrently with its corresponding ctor, or could cause dtors for newly-constructed libraries to be skipped. introduce a shutting_down state that blocks further ctor execution, producing the quiescence the dtor execution loop needs to ensure any kind of consistency, and that blocks further calls to dlopen so that a call into dlopen from a dtor cannot deadlock. better approaches to some of this may be possible, but the changes here at least make things safe.
2019-03-03overhaul shared library ctor execution for dependency order, concurrencyRich Felker-17/+101
previously, shared library constructors at program start and dlopen time were executed in reverse load order. some libraries, however, rely on a depth-first dependency order, which most other dynamic linker implementations provide. this is a much more reasonable, less arbitrary order, and it turns out to have much better properties with regard to how slow-running ctors affect multi-threaded programs, and how recursive dlopen behaves. this commit builds on previous work tracking direct dependencies of each dso (commit 403555690775f7c8806372644f543518e6664e3b), and performs a topological sort on the dependency graph at load time while the main ldso lock is held and before success is committed, producing a queue of constructors needed by the newly-loaded dso (or main application). in the case of circular dependencies, the dependency chain is simply broken at points where it becomes circular. when the ctor queue is run, the init_fini_lock is held only for iteration purposes; it's released during execution of each ctor, so that arbitrarily-long-running application code no longer runs with a lock held in the caller. this prevents a dlopen with slow ctors in one thread from arbitrarily delaying other threads that call dlopen. fully-independent ctors can run concurrently; when multiple threads call dlopen with a shared dependency, one will end up executing the ctor while the other waits on a condvar for it to finish. another corner case improved by these changes is recursive dlopen (call from a ctor). previously, recursive calls to dlopen could cause a ctor for a library to be executed before the ctor for its dependency, even when there was no relation between the calling library and the library it was loading, simply due to the naive reverse-load-order traversal. now, we can guarantee that recursive dlopen in non-circular-dependency usage preserves the desired ctor execution order properties, and that even in circular usage, at worst the libraries whose ctors call dlopen will fail to have completed construction when ctors that depend on them run. init_fini_lock is changed to a normal, non-recursive mutex, since it is no longer held while calling back into application code.