# HG changeset patch # User Tassilo Philipp # Date 1611146983 -3600 # Node ID dd5d03483314301fc3fdf7589ac2dce15877018e # Parent fccbb45a2dae7f9f522f7408c22a0f1368bab553 - dynload changes to support macos >= 11.0.1 "built-in dynamic linker cache of all system-provided libraries" (those dylibs are no longer present on the fs)" * dynload_plain test code changes to reflect this * note in doc - changed dynload_plain to not do inode-based tests on windows diff -r fccbb45a2dae -r dd5d03483314 ChangeLog --- a/ChangeLog Tue Dec 29 13:30:59 2020 +0100 +++ b/ChangeLog Wed Jan 20 13:49:43 2021 +0100 @@ -16,8 +16,11 @@ o support clang's integrated as (didn't build on non-Darwin PPC32 platforms) dynload: o fix to build with musl libc + o support for loading macos >= 11.0.1 (Big Sur) dylibs provided by system's "built-in dynamic + linker cache of all system-provided libraries" (those dylibs are no longer present on the fs) doc: o manual now specifying calling convention signature chars + o dynload(3) note about macos >= 11.0.1 cached dylib support (see above) bindings: o python: Python 3 support, Python 2 unicode support, added get_path function, changing 'Z' conversions to only immutable types and 'p' to mutable types (and handles), support @@ -27,6 +30,9 @@ tests: o extended callf testcode to test callconv mode switch signature chars (including syscalls) o robustness fixes (thanks Bernhard!) + o dynload_plain test fix on macos >= 11.0.1 (Big Sur) + o made inode testing of dynload_plain optional, depending on platform support or if macos + dylib not on fs but provided through system's cache buildsys: o cmake support of armasm64 on windows (thanks Bernhard!) diff -r fccbb45a2dae -r dd5d03483314 dynload/dynload.3 --- a/dynload/dynload.3 Tue Dec 29 13:30:59 2020 +0100 +++ b/dynload/dynload.3 Wed Jan 20 13:49:43 2021 +0100 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2007-2017 Daniel Adler , +.\" Copyright (c) 2007-2020 Daniel Adler , .\" Tassilo Philipp .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -100,6 +100,9 @@ are used to lookup symbol names using an index or symbol's address, respectively, returning a null pointer on error. The names are returned as they would appear in C source code (mangled if C++, etc.). The address passed to .Fn dlSymsNameFromValue must point to a loaded symbol. +.Sh NOTES +.Fn dlLoadLibrary +does handle loading dylibs on macos >= 11.0.1 that aren't on the file system but are provided through the OS' "built-in dynamic linker cache of all system-provided libraries" (to load, use same "path" as one would with dlopen(3)). .Sh BUGS .Fn dlGetLibraryPath is not thread-safe on Darwin (macOS, iOS, ...) and OpenBSD. diff -r fccbb45a2dae -r dd5d03483314 dynload/dynload.h --- a/dynload/dynload.h Tue Dec 29 13:30:59 2020 +0100 +++ b/dynload/dynload.h Wed Jan 20 13:49:43 2021 +0100 @@ -39,7 +39,7 @@ /* shared library loading and explicit symbol resolving */ /* dlLoadLibrary will search for specified lib (e.g. as leaf name, only), */ -/* to the platforms dynamic linking style */ +/* following platforms' dynamic linking style, returns NULL on error */ typedef struct DLLib_ DLLib; diff -r fccbb45a2dae -r dd5d03483314 dynload/dynload_syms_mach-o.c --- a/dynload/dynload_syms_mach-o.c Tue Dec 29 13:30:59 2020 +0100 +++ b/dynload/dynload_syms_mach-o.c Wed Jan 20 13:49:43 2021 +0100 @@ -39,7 +39,6 @@ #include #include -#include #include #include @@ -73,13 +72,9 @@ DLLib* pLib; DLSyms* pSyms = NULL; uint32_t i, n; - struct stat st0; const struct MACH_HEADER_TYPE* pHeader = NULL; const struct dysymtab_command* dysymtab_cmd = NULL; - if(stat(libPath, &st0) == -1) - return NULL; - pLib = dlLoadLibrary(libPath); if(!pLib) return NULL; @@ -87,18 +82,26 @@ /* Loop over all dynamically linked images to find ours. */ for(i = 0, n = _dyld_image_count(); i < n; ++i) { - struct stat st1; const char* name = _dyld_get_image_name(i); - if(name && (stat(name, &st1) != -1)) + if(name) { /* Don't rely on name comparison alone, as libPath might be relative, symlink, differently */ - /* cased, etc., but compare inode number with the one of the mapped dyld image. */ - if(st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/) + /* cased, use weird osx path placeholders, etc., but compare inode number with the one of the mapped dyld image. */ + + /* reload already loaded lib to get handle to compare with, should be lightweight and only increase ref count */ + DLLib* pLib_ = dlLoadLibrary(name); + if(pLib_) { - pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i); + /* free / refcount-- */ + dlFreeLibrary(pLib_); + + if(pLib == pLib_) + { + pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i); //@@@ slide = _dyld_get_image_vmaddr_slide(i); - break; /* found header */ + break; /* found header */ + } } } } diff -r fccbb45a2dae -r dd5d03483314 test/dynload_plain/dynload_plain.c --- a/test/dynload_plain/dynload_plain.c Tue Dec 29 13:30:59 2020 +0100 +++ b/test/dynload_plain/dynload_plain.c Wed Jan 20 13:49:43 2021 +0100 @@ -67,6 +67,8 @@ DLLib* pLib; DLSyms* pSyms; const char* path = NULL; + int cmp_inode = 1; + /* hacky/lazy list of some clib paths per platform - more/others, like version-suffixed ones */ /* can be specified in Makefile; this avoids trying to write portable directory traversal stuff */ const char* clibs[] = { @@ -78,7 +80,7 @@ "/lib32/libc.so", "/lib64/libc.so", "/usr/lib/libc.so", - "/usr/lib/system/libsystem_c.dylib", /* macos */ + "/usr/lib/system/libsystem_c.dylib", /* macos - note: not on fs w/ macos >= 11.0.1 */ "/usr/lib/libc.dylib", "/boot/system/lib/libroot.so", /* Haiku */ "\\ReactOS\\system32\\msvcrt.dll", /* ReactOS */ @@ -93,6 +95,15 @@ path = clibs[i]; break; } +#if defined(DC__OS_Darwin) + /* macos >= 11.0.1 (Big Sur) dylibs might not be on disk but in a sys cache, so dlopen works but not fs checks */ + else if((pLib = dlLoadLibrary(clibs[i]))) { + cmp_inode = 0; /* not dealing with files but dylib sys cache */ + dlFreeLibrary(pLib); + path = clibs[i]; + break; + } +#endif } if(path) { @@ -115,14 +126,36 @@ bs = dlGetLibraryPath(pLib, queriedPath, 200); if(bs && bs <= 200) { - struct stat st0, st1; /* to check if same file */ int b, bs_; printf("path of lib looked up via handle: %s\n", queriedPath); - b = (stat(path, &st0) != -1) && (stat(queriedPath, &st1) != -1); - printf("lib (inode:%d) and looked up lib (inode:%d) are same: %d\n", b?st0.st_ino:-1, b?st1.st_ino:-1, b && (st0.st_ino == st1.st_ino)); //@@@ on windows, inode numbers returned here are always 0 - r += b && (st0.st_ino == st1.st_ino); /* compare if same lib using inode */ + /*@@@ check if resolved path is absolute*/ +#if defined(DC_WINDOWS) + /* on windows, inode numbers returned by stat(2) tests below are always 0, so don't use those */ + cmp_inode = 0; +#endif + + /* path based check if same lib */ + if(cmp_inode) + { + struct stat st0, st1; /* to check if same file */ + b = (stat(path, &st0) != -1) && (stat(queriedPath, &st1) != -1); + printf("lib (inode:%d) and looked up lib (inode:%d) are same: %d\n", b?(int)st0.st_ino:-1, b?(int)st1.st_ino:-1, b && (st0.st_ino == st1.st_ino)); + r += b && (st0.st_ino == st1.st_ino); /* compare if same lib using inode */ + } + else + printf("-- skipping inode based check (doesn't apply to this platform or we are dealing with macos dylib that isn't on fs) --\n"); + + /* just load lib with queried path and compare handle */ + { + DLLib* pLib_ = dlLoadLibrary(queriedPath); + b = (pLib == pLib_); /* pLib guaranteed to not be NULL, here, so no explicit !pLib_ check */ + printf("lib (handle:%p) and looked up lib (handle:%p) are same: %d\n", pLib, pLib_, b); + r += b; + dlFreeLibrary(pLib_); /* dec ref count */ + } + /* check correct bufsize retval */ b = (bs == strlen(queriedPath) + 1); printf("looked up path's needed buffer size (%d) computed correctly 1/2: %d\n", bs, b); @@ -245,7 +278,7 @@ } /* Check final score of right ones to see if all worked */ - r = (r == 16); + r = (r == 16 + cmp_inode); printf("result: dynload_plain: %d\n", r); return !r; }