this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

CoreServices: DateTimeUtils fixes & a test Support for lazy binding

+413 -103
+2 -1
CMakeLists.txt
··· 74 74 src/dyld/UndefinedFunction.cpp 75 75 src/dyld/Trampoline.cpp 76 76 src/dyld/trampoline_helper.nasm 77 + src/dyld/dyld_stub_binder.nasm 77 78 src/dyld/ld.cpp 78 79 src/dyld/dyld.cpp 79 80 src/dyld/public.cpp ··· 118 119 add_subdirectory(src/libSystem) 119 120 add_subdirectory(src/Cocoa) 120 121 add_subdirectory(src/libobjcdarwin) 121 - #add_subdirectory(src/libunwind-darwin-gcc) 122 + add_subdirectory(src/CoreFoundation) 122 123 add_subdirectory(src/libncurses) 123 124 add_subdirectory(src/CoreSecurity) 124 125 add_subdirectory(src/CoreServices)
+1 -2
etc/dylib.conf
··· 9 9 /usr/lib/libgcc_s.1.dylib=libgcc_s.so 10 10 /usr/lib/libbz2.1.0.dylib=libbz2.so.1 11 11 #libncurses.5.4.dylib=libncurses.so.5 12 - #/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation=libCoreFoundation.so 13 - /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation=libgnustep-corebase.so 12 + /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation=libCoreFoundation.so 14 13 /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices=libCoreServices.so 15 14 /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation=libobjc.A.dylib.so 16 15 /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit=libAppKit.so
+1 -1
src/Cocoa/CMakeLists.txt
··· 7 7 8 8 9 9 add_library(Cocoa SHARED zero.c) 10 - target_link_libraries(Cocoa -lgnustep-gui -lopal crashhandler) 10 + target_link_libraries(Cocoa -lgnustep-gui -lopal crashhandler CoreFoundation) 11 11 12 12 install(TARGETS Cocoa DESTINATION "lib${SUFFIX}/darling") 13 13
+28
src/CoreFoundation/CMakeLists.txt
··· 1 + project(CoreFoundation) 2 + 3 + cmake_minimum_required(VERSION 2.4.0) 4 + if(COMMAND cmake_policy) 5 + cmake_policy(SET CMP0003 NEW) 6 + endif(COMMAND cmake_policy) 7 + 8 + #if (NOT "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" MATCHES ".*clang") 9 + # message(FATAL_ERROR "Clang is the only supported compiler.") 10 + #endif (NOT "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" MATCHES ".*clang") 11 + 12 + #configure_file(config.h.in config.h) 13 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 14 + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fblocks") 15 + 16 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 17 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) 18 + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../util) 19 + 20 + set(CoreFoundation_SRCS 21 + NameTranslate.cpp 22 + ) 23 + 24 + add_library(CoreFoundation SHARED ${CoreFoundation_SRCS}) 25 + target_link_libraries(CoreFoundation -lgnustep-corebase objc.A.dylib) 26 + 27 + install(TARGETS CoreFoundation DESTINATION "lib${SUFFIX}/darling") 28 +
+34
src/CoreFoundation/NameTranslate.cpp
··· 1 + #include <cstring> 2 + 3 + namespace Darling 4 + { 5 + typedef bool (*DlsymHookFunc)(char* symName); 6 + void registerDlsymHook(DlsymHookFunc func); 7 + void deregisterDlsymHook(DlsymHookFunc func); 8 + }; 9 + 10 + static bool NameTranslator(char* symName); 11 + 12 + __attribute__((constructor)) 13 + static void initTranslation() 14 + { 15 + Darling::registerDlsymHook(NameTranslator); 16 + } 17 + 18 + __attribute__((destructor)) 19 + static void exitTranslation() 20 + { 21 + Darling::deregisterDlsymHook(NameTranslator); 22 + } 23 + 24 + static bool NameTranslator(char* name) 25 + { 26 + if (strcmp(name, "__CFConstantStringClassReference") == 0) 27 + { 28 + strcpy(name, "_OBJC_CLASS_NSCFString"); 29 + return true; 30 + } 31 + 32 + return false; 33 + } 34 +
+1 -1
src/CoreServices/CMakeLists.txt
··· 26 26 ) 27 27 28 28 add_library(CoreServices SHARED ${CoreServices_SRCS}) 29 - target_link_libraries(CoreServices -licuuc System.B.dylib) 29 + target_link_libraries(CoreServices -licuuc System.B.dylib util) 30 30 31 31 install(TARGETS CoreServices DESTINATION "lib${SUFFIX}/darling") 32 32
+1 -1
src/CoreServices/DateTimeUtils.cpp
··· 1 1 #include "DateTimeUtils.h" 2 2 #include <climits> 3 3 4 - UTCDateTime time_tToUTC(time_t t) 4 + UTCDateTime Darling::time_tToUTC(time_t t) 5 5 { 6 6 UTCDateTime rv; 7 7 uint64_t time = t + UNIX_OFFSET;
+42 -27
src/CoreServices/FileManager.cpp
··· 59 59 return noErr; 60 60 } 61 61 62 - size_t pos = 1; 63 - struct stat st; 64 - int componentPos = 0; 65 - do 62 + std::vector<std::string> components = string_explode(fullPath, '/', false); 63 + std::string position = "/"; 64 + size_t pos; 65 + 66 + for (size_t pos = 0; pos < components.size(); pos++) 66 67 { 67 - std::string component; 68 + bool found = false; 69 + struct dirent* ent; 68 70 69 - pos = fullPath.find('/', pos); 70 - component = fullPath.substr(0, pos); 71 - 72 - if (::lstat(component.c_str(), &st) == -1) 71 + DIR* dir = opendir(position.c_str()); 72 + if (!dir) 73 73 return makeOSStatus(errno); 74 - 75 - fsref->inodes[componentPos++] = st.st_ino; 76 - } 77 - while (pos != std::string::npos); 74 + 75 + while ((ent = readdir(dir))) 76 + { 77 + if (components[pos] == ent->d_name) 78 + { 79 + found = true; 80 + fsref->inodes[pos] = ent->d_ino; 81 + 82 + if (pos+1 == components.size() && isDirectory != nullptr) 83 + *isDirectory = ent->d_type == DT_DIR; 84 + break; 85 + } 86 + } 78 87 79 - if (isDirectory) 80 - *isDirectory = S_ISDIR(st.st_mode); 88 + closedir(dir); 89 + 90 + if (!found) 91 + return fnfErr; 92 + 93 + if (!string_endsWith(position, "/")) 94 + position += '/'; 95 + position += components[pos]; 96 + 97 + pos++; 98 + } 81 99 82 100 return noErr; 83 101 } ··· 97 115 complete = (char*) malloc(strlen(real) + strlen(bname) + 2); 98 116 99 117 strcpy(complete, real); 100 - strcat(complete, "/"); 118 + if (strrchr(complete, '/') != complete+strlen(complete)-1) 119 + strcat(complete, "/"); 101 120 strcat(complete, bname); 102 121 103 122 free(real); ··· 119 138 120 139 while ((ent = readdir(dir))) 121 140 { 141 + if (strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".") == 0) 142 + continue; 122 143 if (ent->d_ino == inode) 123 144 { 124 145 found = true; ··· 289 310 290 311 Boolean CFURLGetFSRef(CFURLRef urlref, FSRef* fsref) 291 312 { 292 - char* buf; 313 + std::unique_ptr<char[]> buf; 293 314 CFIndex len; 294 315 CFStringRef sref = CFURLCopyFileSystemPath(urlref, kCFURLPOSIXPathStyle); 295 316 296 317 if (!sref) 297 318 return false; 298 319 299 - len = CFStringGetLength(sref)*4+1; 300 - buf = new char[len]; 320 + len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(sref), kCFStringEncodingUTF8); 321 + buf.reset(new char[len]); 301 322 302 - if (!CFStringGetCString(sref, buf, len, kCFStringEncodingUTF8)) 303 - { 304 - delete [] buf; 323 + if (!CFStringGetCString(sref, buf.get(), len, kCFStringEncodingUTF8)) 305 324 return false; 306 - } 307 325 308 326 CFRelease(sref); 309 327 310 - OSErr err = FSPathMakeRef((uint8_t*) buf, fsref, nullptr); 311 - delete [] buf; 312 - 313 - return err == noErr; 328 + return FSPathMakeRef((uint8_t*) buf.get(), fsref, nullptr) == noErr; 314 329 } 315 330
+12 -2
src/dyld/FileMap.cpp
··· 34 34 } 35 35 } 36 36 37 - const FileMap::ImageMap* FileMap::add(const MachO& mach, uintptr_t slide, uintptr_t base) 37 + const FileMap::ImageMap* FileMap::add(const MachO& mach, uintptr_t slide, uintptr_t base, bool bindLazy) 38 38 { 39 39 ImageMap* symbol_map = new ImageMap; 40 40 ··· 45 45 symbol_map->eh_frame = mach.get_eh_frame(); 46 46 symbol_map->unwind_info = mach.get_unwind_info(); 47 47 symbol_map->sections = mach.sections(); 48 + 49 + if (!bindLazy) 50 + { 51 + for (auto* b : mach.binds()) 52 + { 53 + if (!b->is_lazy) 54 + continue; 55 + symbol_map->lazy_binds.push_back(*b); 56 + } 57 + } 48 58 49 59 if (!m_maps.insert(std::make_pair(base, symbol_map)).second) 50 60 { ··· 113 123 return map->filename.c_str(); 114 124 } 115 125 116 - const FileMap::ImageMap* FileMap::imageMapForAddr(const void* p) 126 + FileMap::ImageMap* FileMap::imageMapForAddr(const void* p) 117 127 { 118 128 uintptr_t addr = reinterpret_cast<uintptr_t>(p); 119 129 const ImageMap* symbol_map;
+7 -2
src/dyld/FileMap.h
··· 23 23 #include <stdint.h> 24 24 #include <string> 25 25 #include <map> 26 + #include <list> 26 27 #include "MachO.h" 27 28 #include <dlfcn.h> 29 + #include "../util/mutex.h" 28 30 29 31 class FileMap 30 32 { ··· 33 35 34 36 struct ImageMap; 35 37 36 - const ImageMap* add(const MachO& mach, uintptr_t slide, uintptr_t base); 38 + const ImageMap* add(const MachO& mach, uintptr_t slide, uintptr_t base, bool bindLazy); 37 39 38 40 void addWatchDog(uintptr_t addr); 39 41 ··· 46 48 std::pair<uint64_t,uint64_t> eh_frame; 47 49 std::pair<uint64_t,uint64_t> unwind_info; 48 50 std::vector<MachO::Section> sections; 51 + 52 + std::list<MachO::Bind> lazy_binds; 53 + Darling::Mutex mutex_lazy_binds; 49 54 }; 50 55 51 - const ImageMap* imageMapForAddr(const void* p); 56 + ImageMap* imageMapForAddr(const void* p); 52 57 const char* fileNameForAddr(const void* p); 53 58 const char* gdbInfoForAddr(const void* p); 54 59 bool findSymbolInfo(const void* addr, Dl_info* p); // used by __darwin_dladdr
+94 -19
src/dyld/MachOLoader.cpp
··· 50 50 extern char** g_argv; 51 51 extern bool g_trampoline; 52 52 extern std::set<LoaderHookFunc*> g_machoLoaderHooks; 53 + extern MachOLoader* g_loader; 53 54 54 55 // These are GCC internals 55 56 extern "C" void __register_frame(void*); ··· 109 110 { 110 111 } 111 112 112 - void MachOLoader::loadDylibs(const MachO& mach, bool nobind) 113 + void MachOLoader::loadDylibs(const MachO& mach, bool nobind, bool bindLazy) 113 114 { 114 115 for (std::string dylib : mach.dylibs()) 115 116 { 116 117 // __darwin_dlopen checks if already loaded 117 118 // automatically adds a reference if so 118 119 119 - int flags = DARWIN_RTLD_GLOBAL|DARWIN_RTLD_NOW; 120 + int flags = DARWIN_RTLD_GLOBAL; 120 121 if (nobind) 121 122 flags |= __DARLING_RTLD_NOBIND; 123 + if (bindLazy) 124 + flags |= DARWIN_RTLD_LAZY; 125 + else 126 + flags |= DARWIN_RTLD_NOW; 122 127 123 128 if (!__darwin_dlopen(dylib.c_str(), flags)) 124 129 { ··· 313 318 } 314 319 } 315 320 316 - void MachOLoader::doBind(const MachO& mach, intptr slide) 321 + void* MachOLoader::doBind(const std::vector<MachO::Bind*>& binds, intptr slide, bool resolveLazy) 317 322 { 318 323 std::string last_weak_name; 319 324 uintptr_t last_weak_sym = 0; 320 325 size_t seen_weak_bind_index = 0; 321 326 size_t seen_weak_binds_orig_size = m_seen_weak_binds.size(); 327 + uintptr_t sym; 322 328 323 - g_bound_names.resize(mach.binds().size()); 329 + g_bound_names.resize(binds.size()); 324 330 325 - for (MachO::Bind* bind : mach.binds()) 331 + for (MachO::Bind* bind : binds) 326 332 { 333 + if (bind->is_lazy) 334 + { 335 + if (!resolveLazy) 336 + { 337 + LOG << "Delaying lazy bind resolution, offset=" << std::hex << bind->offset << std::dec << std::endl; 338 + continue; 339 + } 340 + else 341 + LOG << "Lazy bind resolution forced\n"; 342 + } 343 + 327 344 if (bind->type == BIND_TYPE_POINTER || bind->type == BIND_TYPE_STUB) 328 345 { 329 346 std::string name = bind->name.substr(1); 330 347 uintptr_t* ptr = (uintptr_t*)(bind->vmaddr + slide); 331 - uintptr_t sym = 0; 348 + 349 + sym = 0; 332 350 333 351 if (bind->is_weak) 334 352 { ··· 421 439 } 422 440 423 441 LOG << "bind " << name << ": " 424 - << *ptr << " => " << (void*)sym << " @" << ptr << std::endl; 442 + << std::hex << *ptr << std::dec << " => " << (void*)sym << " @" << ptr << std::endl; 425 443 426 444 if (g_trampoline) 427 445 sym = (uintptr_t) m_pTrampolineMgr->generate((void*)sym, name.c_str()); ··· 455 473 } 456 474 457 475 std::inplace_merge(m_seen_weak_binds.begin(), m_seen_weak_binds.begin() + seen_weak_binds_orig_size, m_seen_weak_binds.end()); 476 + 477 + return reinterpret_cast<void*>(sym); 458 478 } 459 479 460 480 ··· 474 494 475 495 476 496 477 - void MachOLoader::load(const MachO& mach, std::string sourcePath, Exports* exports, bool nobind) 497 + void MachOLoader::load(const MachO& mach, std::string sourcePath, Exports* exports, bool bindLater, bool bindLazy) 478 498 { 479 499 if (!exports) 480 500 exports = &m_exports; ··· 490 510 doRebase(mach, slide); 491 511 doMProtect(); // decrease the segment protection value 492 512 493 - loadDylibs(mach, nobind); 513 + loadDylibs(mach, bindLater, bindLazy); 494 514 495 515 loadInitFuncs(mach, slide); 496 516 497 517 loadExports(mach, base, exports); 498 518 499 - if (!nobind) 500 - doBind(mach, slide); 519 + if (!bindLater) 520 + doBind(mach.binds(), slide, !bindLazy); 501 521 502 - const FileMap::ImageMap* img = g_file_map.add(mach, slide, base); 522 + const FileMap::ImageMap* img = g_file_map.add(mach, slide, base, bindLazy); 503 523 504 - if (!nobind) 524 + if (!bindLater) 505 525 { 506 526 for (LoaderHookFunc* func : g_machoLoaderHooks) 507 527 func(&img->header, slide); 508 528 } 509 529 else 510 - m_pendingBinds.push_back(PendingBind{ &mach, &img->header, slide }); 530 + { 531 + LOG << mach.binds().size() << " binds pending\n"; 532 + m_pendingBinds.push_back(PendingBind{ &mach, &img->header, slide, bindLazy }); 533 + } 511 534 } 512 535 513 536 void MachOLoader::doPendingBinds() 514 537 { 515 538 for (const PendingBind& b : m_pendingBinds) 516 539 { 517 - doBind(*b.macho, b.slide); 540 + LOG << "Perform " << b.macho->binds().size() << " binds\n"; 541 + doBind(b.macho->binds(), b.slide, b.bindLazy); 518 542 if (b.macho->get_eh_frame().first) 519 543 __register_frame(reinterpret_cast<void*>(b.macho->get_eh_frame().first + b.slide)); 520 544 for (LoaderHookFunc* func : g_machoLoaderHooks) ··· 559 583 } 560 584 561 585 562 - void MachOLoader::run(MachO& mach, int argc, char** argv, char** envp) 586 + void MachOLoader::run(MachO& mach, int argc, char** argv, char** envp, bool bindLazy) 563 587 { 564 588 char* apple[2] = { g_darwin_executable_path, 0 }; 565 589 std::vector<char*> envCopy; ··· 568 592 // envCopy.push_back(envp[i]); 569 593 envCopy.push_back(0); 570 594 571 - load(mach, g_darwin_executable_path, nullptr, true); 595 + load(mach, g_darwin_executable_path, nullptr, true, bindLazy); 572 596 setupDyldData(mach); 573 597 574 598 g_file_map.addWatchDog(m_last_addr + 1); 575 599 576 600 //g_timer.print(mach.filename().c_str()); 577 601 578 - mach.close(); 579 - 580 602 doPendingBinds(); 581 603 runPendingInitFuncs(argc, argv, &envCopy[0], apple); 604 + 605 + mach.close(); 582 606 583 607 fflush(stdout); 584 608 assert(argc > 0); ··· 635 659 636 660 PUSH(argc); 637 661 JUMP(entry); 662 + } 663 + 664 + extern "C" void* dyld_stub_binder_fixup(FileMap::ImageMap** imageMap, uintptr_t lazyOffset) 665 + { 666 + if (!*imageMap) 667 + { 668 + LOG << "Finding image for address " << imageMap << std::endl; 669 + *imageMap = g_file_map.imageMapForAddr(reinterpret_cast<void*>(imageMap)); 670 + 671 + if (!*imageMap) 672 + { 673 + std::cerr << "dyld_stub_binder_fixup(): Image map not found for " << imageMap << std::endl; 674 + abort(); 675 + } 676 + } 677 + 678 + std::vector<MachO::Bind*> toBind; // will hold only the single item we need to bind 679 + std::list<MachO::Bind>::iterator it; 680 + 681 + (*imageMap)->mutex_lazy_binds.lock(); 682 + it = (*imageMap)->lazy_binds.begin(); 683 + 684 + while (it != (*imageMap)->lazy_binds.end()) 685 + { 686 + if (it->offset == lazyOffset) 687 + { 688 + toBind.push_back(&*it); 689 + break; 690 + } 691 + it++; 692 + } 693 + 694 + if (toBind.empty()) 695 + { 696 + std::cerr << "dyld_stub_binder_fixup(): Lazy bind not found for offset " << std::hex << lazyOffset << std::dec << std::endl; 697 + abort(); 698 + } 699 + 700 + void* addr; 701 + try 702 + { 703 + addr = g_loader->doBind(toBind, (*imageMap)->slide, true); 704 + } 705 + catch (const std::exception& e) 706 + { 707 + std::cerr << "dyld_stub_binder_fixup(): Failed to resolve the symbol: " << e.what() << std::endl; 708 + abort(); 709 + } 710 + 711 + (*imageMap)->mutex_lazy_binds.unlock(); 712 + return addr; 638 713 } 639 714 640 715 #ifdef DEBUG
+7 -4
src/dyld/MachOLoader.h
··· 59 59 void loadInitFuncs(const MachO& mach, intptr slide); 60 60 61 61 // Loads libraries this module depends on 62 - void loadDylibs(const MachO& mach, bool nobinds); 62 + void loadDylibs(const MachO& mach, bool nobinds, bool bindLazy); 63 63 64 64 // Resolves all external symbols required by this module 65 - void doBind(const MachO& mach, intptr slide); 65 + void* doBind(const std::vector<MachO::Bind*>& binds, intptr slide, bool resolveLazy = false); 66 66 67 + // Calls mprotect() to switch segment protections to the "initial" value. 68 + // We initially set the maximum value. 67 69 void doMProtect(); 68 70 69 71 // Creates a list of publicly visible functions in this module 70 72 void loadExports(const MachO& mach, intptr base, Exports* exports); 71 73 72 74 // Loads a Mach-O file and does all the processing 73 - void load(const MachO& mach, std::string sourcePath, Exports* exports = 0, bool nobind = false); 75 + void load(const MachO& mach, std::string sourcePath, Exports* exports = 0, bool bindLater = false, bool bindLazy = false); 74 76 75 77 // Dyld data contains an accessor to internal dyld functionality. This stores the accessor pointer. 76 78 void setupDyldData(const MachO& mach); ··· 82 84 void doPendingBinds(); 83 85 84 86 // Starts an application 85 - void run(MachO& mach, int argc, char** argv, char** envp); 87 + void run(MachO& mach, int argc, char** argv, char** envp, bool bindLazy = false); 86 88 87 89 const Exports& getExports() const { return m_exports; } 88 90 ··· 115 117 const MachO* macho; 116 118 const mach_header* header; 117 119 intptr slide; 120 + bool bindLazy; 118 121 }; 119 122 std::vector<PendingBind> m_pendingBinds; 120 123 };
+9 -4
src/dyld/dyld.cpp
··· 60 60 std::cerr << "Environment variables:\n" 61 61 "\tDYLD_DEBUG=1 - enable debug info (lots of output)\n" 62 62 "\tDYLD_IGN_MISSING_SYMS=1 - replace missing symbol references with a stub function\n" 63 - "\tDYLD_SYSROOT=<path> - set the base for library path resolution (overrides autodetection)\n" 64 63 "\tDYLD_MTRACE=1 - enable mtrace\n" 65 - "\tDYLD_TRAMPOLINE=1 - access all bound functions via a debug trampoline\n"; 64 + "\tDYLD_TRAMPOLINE=1 - access all bound functions via a debug trampoline\n" 65 + "\tDYLD_ROOT_PATH=<path> - set the base for library path resolution (overrides autodetection)\n" 66 + "\tDYLD_BIND_AT_LAUNCH=1 - force dyld to bind all lazy references on startup\n"; 66 67 return 1; 67 68 } 68 69 ··· 135 136 g_loader = new MachOLoader; 136 137 137 138 autoSysrootSearch(); 139 + bool forceBind = false; 138 140 139 - g_loader->run(*g_mainBinary, g_argc, g_argv, envp); 141 + if (getenv("DYLD_BIND_AT_LAUNCH") != nullptr) 142 + forceBind = true; 143 + 144 + g_loader->run(*g_mainBinary, g_argc, g_argv, envp, forceBind); 140 145 141 146 delete g_loader; 142 147 g_loader = 0; ··· 176 181 177 182 void autoSysrootSearch() 178 183 { 179 - if (const char* s = getenv("DYLD_SYSROOT")) 184 + if (const char* s = getenv("DYLD_ROOT_PATH")) 180 185 { 181 186 strncpy(g_sysroot, s, PATH_MAX-1); 182 187 g_sysroot[PATH_MAX-1] = 0;
+57
src/dyld/dyld_stub_binder.nasm
··· 1 + extern reg_saveall 2 + extern reg_restoreall 3 + extern dyld_stub_binder_fixup ; void* dyld_stub_binder_fixup(void* cache, uintptr_t index) 4 + global dyld_stub_binder 5 + 6 + ; Stub identifier is pushed first 7 + ; then the code pushes a pointer to cache 8 + 9 + %ifidn __OUTPUT_FORMAT__, elf64 10 + 11 + BITS 64 12 + section text 13 + 14 + dyld_stub_binder: 15 + 16 + call reg_saveall ; 224 bytes 17 + mov rdi, [rsp+224] ; cache 18 + mov rsi, [rsp+224+8] ; offset 19 + 20 + call dyld_stub_binder_fixup 21 + 22 + mov r11, rax 23 + call reg_restoreall 24 + 25 + add rsp, 16 ; remove arguments to dyld_stub_binder 26 + jmp r11 27 + 28 + %elifidn __OUTPUT_FORMAT__, elf 29 + 30 + BITS 32 31 + section text 32 + 33 + dyld_stub_binder: 34 + 35 + call reg_saveall ; 32 bytes 36 + mov eax, [esp+32] ; cache 37 + mov ecx, [esp+32+4] ; offset 38 + push ecx 39 + push eax 40 + 41 + call dyld_stub_binder_fixup 42 + add esp, 8 43 + 44 + mov [esp-4], eax ; save the real addr somewhere 45 + call reg_restoreall 46 + 47 + mov eax, [esp-32-4] ; restore the real addr 48 + add esp, 8 ; remove arguments to dyld_stub_binder 49 + jmp eax 50 + 51 + %else 52 + 53 + %error "Unsupported platform" 54 + 55 + %endif 56 + 57 +
+6 -18
src/dyld/ld.cpp
··· 409 409 lib->machoRef = machO; 410 410 411 411 bool global = flag & RTLD_GLOBAL && !(flag & RTLD_LOCAL); 412 + bool lazy = flag & RTLD_LAZY && !(flag & RTLD_NOW); 412 413 413 414 if (!global) 414 415 { 415 416 lib->exports = new Exports; 416 - g_loader->load(*machO, name, lib->exports, nobind); 417 + g_loader->load(*machO, name, lib->exports, nobind, lazy); 417 418 } 418 419 else 419 - g_loader->load(*machO, name, 0, nobind); 420 + g_loader->load(*machO, name, 0, nobind, lazy); 420 421 421 422 if (!nobind) 422 423 { ··· 554 555 if (itSym == e.end()) 555 556 { 556 557 // Now try without a prefix 557 - sym = ::dlsym(RTLD_DEFAULT, translateSymbol(symbol)); 558 + const char* translated = translateSymbol(symbol); 559 + LOG << "Trying " << translated << std::endl; 560 + sym = ::dlsym(RTLD_DEFAULT, translated); 558 561 if (sym) 559 562 return sym; 560 563 ··· 624 627 return -1; 625 628 } 626 629 627 - return 0; 628 - } 629 - 630 - extern "C" void* dyld_stub_binder() 631 - { 632 - /* 633 - long arg1, arg2; 634 - asm ("movq (%%rsp), %%rbx;" 635 - "movq %%rbx, %0;" 636 - "movq 4(%%rsp), %%rbx;" 637 - "movq %%rbx, %1;" 638 - : "=r" (arg1), "=r" (arg2) 639 - ); 640 - */ 641 - // TODO 642 630 return 0; 643 631 } 644 632
+18
src/libSystem/kernel-mach/error.h
··· 1 + #ifndef MACH_ERROR_H 2 + #define MACH_ERROR_H 3 + #include <mach/kern_return.h> 4 + 5 + #ifdef __cplusplus 6 + extern "C" { 7 + #endif 8 + 9 + const char* mach_error_string(kern_return_t code); 10 + void mach_error(const char* str, kern_return_t code); 11 + const char* mach_error_type(kern_return_t code); 12 + 13 + #ifdef __cplusplus 14 + } 15 + #endif 16 + 17 + #endif 18 +
+22 -10
src/libmach-o/BindState.cpp
··· 37 37 typedef long long ll; 38 38 typedef unsigned long long ull; 39 39 40 - BindState::BindState(MachOImpl* mach0, bool is_weak0) 40 + BindState::BindState(MachOImpl* mach0, bool is_weak0, bool is_lazy0) 41 41 : mach(mach0), ordinal(0), sym_name(NULL), type(BIND_TYPE_POINTER), 42 - addend(0), seg_index(0), seg_offset(0), is_weak(is_weak0) 42 + addend(0), seg_index(0), seg_offset(0), is_weak(is_weak0), is_lazy(is_lazy0), 43 + last_start(nullptr) 43 44 { 44 45 } 45 46 46 - void BindState::readBindOp(const uint8_t*& p) 47 + void BindState::readBindOp(const uint8_t* bindsStart, const uint8_t*& p) 47 48 { 49 + uintptr_t offset; 48 50 uint8_t op = *p & BIND_OPCODE_MASK; 49 51 uint8_t imm = *p & BIND_IMMEDIATE_MASK; 50 - p++; 51 52 52 - LOGF("bind: op=%x imm=%d\n", op, imm); 53 + if (!last_start) 54 + last_start = bindsStart; 55 + offset = last_start - bindsStart; 56 + 57 + LOG << "bind: op=" << std::hex << int(op) << " imm=" << int(imm) << std::dec << " @" << (void*)p << ", bindsStart at " << (void*)bindsStart << std::endl; 58 + p++; 53 59 54 60 switch (op) 55 61 { 56 62 case BIND_OPCODE_DONE: 63 + last_start = p; 57 64 break; 58 65 59 66 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: ··· 96 103 break; 97 104 98 105 case BIND_OPCODE_DO_BIND: 99 - addBind(); 106 + addBind(offset); 100 107 break; 101 108 102 109 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: 103 110 LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n"); 104 - addBind(); 111 + addBind(offset); 105 112 seg_offset += uleb128(p); 106 113 break; 107 114 108 115 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: 109 116 LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED %d\n", (int)imm); 110 - addBind(); 117 + addBind(offset); 111 118 seg_offset += imm * mach->m_ptrsize; 112 119 break; 113 120 ··· 118 125 (unsigned)count, (unsigned)skip); 119 126 for (uint64_t i = 0; i < count; i++) 120 127 { 121 - addBind(); 128 + addBind(offset); 122 129 seg_offset += skip; 123 130 } 124 131 break; ··· 129 136 } 130 137 } 131 138 132 - void BindState::addBind() 139 + void BindState::addBind(uintptr_t offset) 133 140 { 134 141 MachO::Bind* bind = new MachO::Bind(); 135 142 uint64_t vmaddr; ··· 148 155 bind->type = type; 149 156 bind->ordinal = ordinal; 150 157 bind->is_weak = is_weak; 158 + bind->is_lazy = is_lazy; 159 + 160 + if (is_lazy) 161 + bind->offset = offset; 162 + 151 163 mach->m_binds.push_back(bind); 152 164 153 165 seg_offset += mach->m_ptrsize;
+5 -4
src/libmach-o/BindState.h
··· 32 32 33 33 struct BindState 34 34 { 35 - BindState(MachOImpl* mach0, bool is_weak0); 35 + BindState(MachOImpl* mach0, bool is_weak0, bool is_lazy0); 36 36 37 - void readBindOp(const uint8_t*& p); 37 + void readBindOp(const uint8_t* bindsStart, const uint8_t*& p); 38 38 39 - void addBind(); 39 + void addBind(uintptr_t offset); 40 40 41 41 MachOImpl* mach; 42 42 uint8_t ordinal; ··· 45 45 int64_t addend; 46 46 int seg_index; 47 47 uint64_t seg_offset; 48 - bool is_weak; 48 + bool is_weak, is_lazy; 49 + const uint8_t* last_start; 49 50 }; 50 51 51 52
+2 -2
src/libmach-o/MachO.h
··· 60 60 }; 61 61 uint8_t type; 62 62 uint8_t ordinal; 63 - bool is_weak; 64 - bool is_classic; 63 + bool is_weak, is_lazy, is_classic; 64 + uintptr_t offset; // Needed to find the right bind when doing lazy binding 65 65 }; 66 66 67 67 struct Export
+6 -4
src/libmach-o/MachOImpl.cpp
··· 208 208 } 209 209 210 210 211 - void MachOImpl::readBind(const uint8_t* p, const uint8_t* end, bool is_weak) 211 + void MachOImpl::readBind(const uint8_t* start, const uint8_t* end, bool is_weak, bool is_lazy) 212 212 { 213 - BindState state(this, is_weak); 213 + BindState state(this, is_weak, is_lazy); 214 + const uint8_t* p = start; 214 215 while (p < end) 215 216 { 216 - state.readBindOp(p); 217 + state.readBindOp(start, p); 217 218 } 218 219 } 219 220 ··· 380 381 const uint8_t* p = reinterpret_cast<uint8_t*>( 381 382 m_base + dyinfo->lazy_bind_off); 382 383 const uint8_t* end = p + dyinfo->lazy_bind_size; 383 - readBind(p, end, false); 384 + LOG << "Lazy bindings start at " << (void*)p << std::endl; 385 + readBind(p, end, false, true); 384 386 } 385 387 386 388 {
+1 -1
src/libmach-o/MachOImpl.h
··· 49 49 void readSegment(char* cmds_ptr, std::vector<segment_command*>* segments, std::vector<section*>* bind_sections); 50 50 51 51 void readRebase(const uint8_t* p, const uint8_t* end); 52 - void readBind(const uint8_t* p, const uint8_t* end, bool is_weak); 52 + void readBind(const uint8_t* p, const uint8_t* end, bool is_weak, bool is_lazy = false); 53 53 void readExport(const uint8_t* start, const uint8_t* p, const uint8_t* end, std::string* name_buf); 54 54 55 55 template <class section>
+2
src/motool/motool.cpp
··· 185 185 std::cout << 'W'; 186 186 if (b->is_classic) 187 187 std::cout << 'C'; 188 + if (b->is_lazy) 189 + std::cout << 'L'; 188 190 189 191 std::cout << std::dec << std::endl; 190 192 }
+22
src/util/stlutils.cpp
··· 16 16 return str.compare(str.size()-what.size(), what.size(), what) == 0; 17 17 } 18 18 19 + std::vector<std::string> string_explode(const std::string& str, char delim, bool keepEmpty) 20 + { 21 + std::vector<std::string> rv; 22 + size_t start = 0, end; 23 + 24 + do 25 + { 26 + std::string substr; 27 + 28 + end = str.find(delim, start); 29 + substr = str.substr(start, (end != std::string::npos) ? end-start : std::string::npos); 30 + 31 + if (keepEmpty || !substr.empty()) 32 + rv.push_back(substr); 33 + 34 + start = end+1; 35 + } 36 + while (end != std::string::npos); 37 + 38 + return rv; 39 + } 40 +
+2
src/util/stlutils.h
··· 3 3 #include <string> 4 4 #include <map> 5 5 #include <cassert> 6 + #include <vector> 6 7 7 8 bool string_startsWith(const std::string& str, const std::string& what); 8 9 bool string_endsWith(const std::string& str, const std::string& what); 10 + std::vector<std::string> string_explode(const std::string& str, char delim, bool keepEmpty = true); 9 11 10 12 template<typename K, typename V, typename KK> bool map_contains(const std::map<K,V>& map, const KK& k) 11 13 {
+31
tests/src/cfurl_fm_basic.c
··· 1 + // CFLAGS: -framework corefoundation -framework coreservices 2 + #include <CoreFoundation/CFURL.h> 3 + #include <Carbon/Carbon.h> 4 + #include <assert.h> 5 + #include <string.h> 6 + #include <stdio.h> 7 + 8 + #define TESTPATH "/home" 9 + 10 + int main() 11 + { 12 + CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSTR(TESTPATH), kCFURLPOSIXPathStyle, 1); 13 + FSRef fsref; 14 + Boolean b; 15 + char* buffer = (char*) malloc(100); 16 + OSStatus status; 17 + 18 + b = CFURLGetFSRef(url, &fsref); 19 + assert(b != 0); 20 + 21 + status = FSRefMakePath(&fsref, buffer, 100); 22 + assert(status == 0); 23 + 24 + puts(buffer); 25 + assert(strcmp(TESTPATH, buffer) == 0); 26 + 27 + free(buffer); 28 + CFRelease(url); 29 + return 0; 30 + } 31 +