# HG changeset patch # User Tassilo Philipp # Date 1491472836 -7200 # Node ID 87c695673522e8ddb77b873256a8271da60ab145 # Parent 28bf0b231bcec02bb79ead40337a0a03ed208990 dynload darwin/mach-o update: - removed unnecessarily complex darwin loader interface, and sharing with dynload_unix now - mach-o symbol resolving refactored: * to handle symlinks, relative paths, paths with random casing * loading lib when not already loaded, for API consistency with ELF and PE implementations diff -r 28bf0b231bce -r 87c695673522 ChangeLog --- a/ChangeLog Thu Apr 06 11:40:15 2017 +0200 +++ b/ChangeLog Thu Apr 06 12:00:36 2017 +0200 @@ -16,6 +16,11 @@ o SPARC64 (v9) support o POSIX compliance: fallback for wx alloc on systems that don't have mmap()'s MAP_ANON o allocated space used for thunk now always W^X (req. for e.g. OpenBSD >= 6.0) +dynload: + o simplifications of implemention on Darwin + o reliability/stability fixes for Mach-O dlSyms* lib to handle symlinks, + relative paths, paths with random casings + o allowing Mach-O dlSyms* lib to be used standalone (consistent with ELF and PE impls now) general: o marked assembly code as not needing an execstack, for safer/easier integration into other projects/builds, where needed; this is needed b/c of questionable default behaviours of some diff -r 28bf0b231bce -r 87c695673522 dynload/dynload.c --- a/dynload/dynload.c Thu Apr 06 11:40:15 2017 +0200 +++ b/dynload/dynload.c Thu Apr 06 12:00:36 2017 +0200 @@ -6,7 +6,7 @@ Description: Auto-include delegate to windows/posix-based dynamic linker. License: - Copyright (c) 2007-2015 Daniel Adler , + Copyright (c) 2007-2017 Daniel Adler , Tassilo Philipp Permission to use, copy, modify, and distribute this software for any @@ -24,16 +24,10 @@ */ - #include "../autovar/autovar_OSFAMILY.h" #if defined(OSFAMILY_Windows) # include "dynload_windows.c" #elif defined(OSFAMILY_Unix) -# include "../autovar/autovar_OS.h" -# if defined(OS_Darwin) -# include "dynload_darwin.c" -# else -# include "dynload_unix.c" -# endif +# include "dynload_unix.c" #endif diff -r 28bf0b231bce -r 87c695673522 dynload/dynload_darwin.c --- a/dynload/dynload_darwin.c Thu Apr 06 11:40:15 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - - Package: dyncall - Library: dynload - File: dynload/dynload_darwin.c - Description: dynload module for .dylib (mach-o darwin/OS X) files - License: - - Copyright (c) 2007-2015 Olivier Chafik - Minor bug-fix modifications by Daniel Adler. - - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -*/ - - - -/* - - dynload_darwin.c - - dynload module for .dylib (mach-o darwin/OS X) files - -*/ - - -#include "dynload.h" -#include "dynload_alloc.h" -#include -#include - -struct DLLib_ -{ - char* libPath; - void* handle; -}; - - -DLLib* dlLoadLibrary(const char* libPath) -{ - void* handle; - size_t len; - DLLib* lib; - - handle = dlopen(libPath, RTLD_LAZY); - if (!handle) - return NULL; - - - lib = (DLLib*)dlAllocMem(sizeof(DLLib)); - lib->handle = handle; - /* libPath might be null (self reference on image) [Daniel] */ - if (libPath != NULL) { - len = strlen(libPath); - lib->libPath = (char*)dlAllocMem(len + 1); - strcpy(lib->libPath, libPath); - lib->libPath[len] = '\0'; - } else { - lib->libPath = NULL; - } - return lib; -} - -void* dlFindSymbol(DLLib* libHandle, const char* symbol) -{ - return dlsym(libHandle && libHandle->handle ? libHandle->handle : RTLD_DEFAULT, symbol); -} - - -void dlFreeLibrary(DLLib* libHandle) -{ - if (!libHandle) - return; - - dlclose(libHandle->handle); - if (libHandle->libPath) - dlFreeMem(libHandle->libPath); - dlFreeMem(libHandle); -} - diff -r 28bf0b231bce -r 87c695673522 dynload/dynload_syms.c --- a/dynload/dynload_syms.c Thu Apr 06 11:40:15 2017 +0200 +++ b/dynload/dynload_syms.c Thu Apr 06 12:00:36 2017 +0200 @@ -6,7 +6,7 @@ Description: License: - Copyright (c) 2007-2015 Daniel Adler , + Copyright (c) 2007-2017 Daniel Adler , Tassilo Philipp Permission to use, copy, modify, and distribute this software for any @@ -33,7 +33,5 @@ #include "dynload_syms_mach-o.c" #elif defined(ABI_ELF) #include "dynload_syms_elf.c" -#else -void dummy() { } #endif diff -r 28bf0b231bce -r 87c695673522 dynload/dynload_syms_mach-o.c --- a/dynload/dynload_syms_mach-o.c Thu Apr 06 11:40:15 2017 +0200 +++ b/dynload/dynload_syms_mach-o.c Thu Apr 06 12:00:36 2017 +0200 @@ -6,7 +6,9 @@ Description: License: - Copyright (c) 2007-2015 Olivier Chafik + Copyright (c) 2007-2015 Olivier Chafik , + 2017 refactored for stability, API consistency + and portability by Tassilo Philipp. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -32,76 +34,89 @@ #include "dynload.h" #include "dynload_alloc.h" +#include "../autovar/autovar_ARCH.h" #include #include +#include #include #include -#if defined(ARCH_X64) //@@@ use dyncall_macros.h +#if defined(ARCH_X64) || defined(ARCH_PPC64) || defined(ARCH_ARM64) //@@@ use dyncall_macros.h #define MACH_HEADER_TYPE mach_header_64 -#define SEGMENT_COMMAND segment_command_64 #define NLIST_TYPE nlist_64 #else #define MACH_HEADER_TYPE mach_header -#define SEGMENT_COMMAND segment_command #define NLIST_TYPE nlist #endif -struct DLLib_ -{ - char* libPath; - void* handle; -}; - - struct DLSyms_ { - const char* pStringTable; + DLLib* pLib; + const char* pStringTable; const struct NLIST_TYPE* pSymbolTable; - uint32_t symbolCount; + uint32_t symbolCount; }; -DLSyms* dlSymsInit(const char* libPath) +DLSyms* dlSymsInit(const char* libPath) { - DLSyms* pSyms = NULL; + DLLib* pLib; + DLSyms* pSyms; uint32_t iImage, nImages; + struct stat st0; + + if(stat(libPath, &st0) == -1) + return NULL; + + pLib = dlLoadLibrary(libPath); + if(!pLib) + return NULL; + + // Loop over all dynamically linked images. for (iImage = 0, nImages = _dyld_image_count(); iImage < nImages; iImage++) { + struct stat st1; const char* name = _dyld_get_image_name(iImage); - if (name && !strcmp(name, libPath)) + + if(name && (stat(name, &st1) != -1)) { - const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage); - const char* pBase = ((const char*)pHeader); - if (pHeader->filetype != MH_DYLIB) - return NULL; - if (pHeader->flags & MH_SPLIT_SEGS) - return NULL; - - if (pHeader) + // 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)*/) { - uint32_t iCmd, nCmds = pHeader->ncmds; - const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE)); - - for (iCmd = 0; iCmd < nCmds; iCmd++) + const struct MACH_HEADER_TYPE* pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(iImage); + const char* pBase = ((const char*)pHeader); + if (pHeader->filetype != MH_DYLIB) + return NULL; + if (pHeader->flags & MH_SPLIT_SEGS) + return NULL; + + if (pHeader) { - if (cmd->cmd == LC_SYMTAB) + uint32_t iCmd, nCmds = pHeader->ncmds; + const struct load_command* cmd = (const struct load_command*)(pBase + sizeof(struct MACH_HEADER_TYPE)); + + for (iCmd = 0; iCmd < nCmds; iCmd++) { - const struct symtab_command* scmd = (const struct symtab_command*)cmd; - - pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) ); - pSyms->symbolCount = scmd->nsyms; - pSyms->pStringTable = pBase + scmd->stroff; - pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff); - - return pSyms; + if (cmd->cmd == LC_SYMTAB) + { + const struct symtab_command* scmd = (const struct symtab_command*)cmd; + + pSyms = (DLSyms*)( dlAllocMem(sizeof(DLSyms)) ); + pSyms->symbolCount = scmd->nsyms; + pSyms->pStringTable = pBase + scmd->stroff; + pSyms->pSymbolTable = (struct NLIST_TYPE*)(pBase + scmd->symoff); + pSyms->pLib = pLib; + + return pSyms; + } + cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize); } - cmd = (const struct load_command*)(((char*)cmd) + cmd->cmdsize); } + break; } - break; } } return NULL; @@ -110,17 +125,15 @@ void dlSymsCleanup(DLSyms* pSyms) { - if (!pSyms) - return; - - dlFreeMem(pSyms); + if(pSyms) { + dlFreeLibrary(pSyms->pLib); + dlFreeMem(pSyms); + } } int dlSymsCount(DLSyms* pSyms) { - if (!pSyms) - return 0; - return pSyms->symbolCount; + return pSyms ? pSyms->symbolCount : 0; } static const struct NLIST_TYPE* get_nlist(DLSyms* pSyms, int index) @@ -128,11 +141,11 @@ const struct NLIST_TYPE* nl; if (!pSyms) return NULL; - + nl = pSyms->pSymbolTable + index; if (nl->n_un.n_strx <= 1) return NULL; // would be empty string anyway - + //TODO skip more symbols based on nl->n_desc and nl->n_type ? return nl; } @@ -141,20 +154,7 @@ const char* dlSymsName(DLSyms* pSyms, int index) { const struct NLIST_TYPE* nl = get_nlist(pSyms, index); - if (!nl) - return NULL; - - return pSyms->pStringTable + nl->n_un.n_strx; -} - - -void* dlSymsValue(DLSyms* pSyms, int index) -{ - const struct NLIST_TYPE* nl = get_nlist(pSyms, index); - if (!nl) - return NULL; - - return (void*) (ptrdiff_t) (nl->n_value); + return nl ? pSyms->pStringTable + nl->n_un.n_strx : NULL; } @@ -163,6 +163,7 @@ Dl_info info; if (!dladdr(value, &info) || (value != info.dli_saddr)) return NULL; - + return info.dli_sname; } +