1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 * 3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25// work around until conformance work is complete rdar://problem/4508801 26#define __srr0 srr0 27#define __eip eip 28#define __rip rip 29 30 31#include <string.h> 32#include <fcntl.h> 33#include <errno.h> 34#include <sys/types.h> 35#include <sys/fcntl.h> 36#include <sys/stat.h> 37#include <sys/mman.h> 38#include <mach/mach.h> 39#include <mach/thread_status.h> 40#include <mach-o/loader.h> 41#include <mach-o/reloc.h> 42#include <mach-o/nlist.h> 43#include <sys/sysctl.h> 44#include <libkern/OSAtomic.h> 45#include <libkern/OSCacheControl.h> 46 47#if __x86_64__ 48 #include <mach-o/x86_64/reloc.h> 49#endif 50#if __arm__ 51 #include <mach-o/arm/reloc.h> 52#endif 53 54#include "ImageLoaderMachOClassic.h" 55#include "mach-o/dyld_images.h" 56 57// in dyldStartup.s 58extern "C" void fast_stub_binding_helper_interface(); 59 60 61#if __x86_64__ 62 #define POINTER_RELOC X86_64_RELOC_UNSIGNED 63#else 64 #define POINTER_RELOC GENERIC_RELOC_VANILLA 65#endif 66 67 68// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables 69#if __LP64__ 70 #define RELOC_SIZE 3 71 #define LC_SEGMENT_COMMAND LC_SEGMENT_64 72 #define LC_ROUTINES_COMMAND LC_ROUTINES_64 73 struct macho_segment_command : public segment_command_64 {}; 74 struct macho_section : public section_64 {}; 75 struct macho_routines_command : public routines_command_64 {}; 76#else 77 #define RELOC_SIZE 2 78 #define LC_SEGMENT_COMMAND LC_SEGMENT 79 #define LC_ROUTINES_COMMAND LC_ROUTINES 80 struct macho_segment_command : public segment_command {}; 81 struct macho_section : public section {}; 82 struct macho_routines_command : public routines_command {}; 83#endif 84 85 86 87 88// create image for main executable 89ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, 90 unsigned int segCount, unsigned int libCount, const LinkContext& context) 91{ 92 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount); 93 94 // set slide for PIE programs 95 image->setSlide(slide); 96 97 // for PIE record end of program, to know where to start loading dylibs 98 if ( slide != 0 ) 99 fgNextPIEDylibAddress = (uintptr_t)image->getEnd(); 100 101 image->instantiateFinish(context); 102 image->setMapped(context); 103 104#if __i386__ 105 // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding 106 if ( image->fReadOnlyImportSegment ) { 107 for(unsigned int i=0; i < image->fSegmentsCount; ++i) { 108 if ( image->segIsReadOnlyImport(i) ) 109 image->segMakeWritable(i, context); 110 } 111 } 112#endif 113 114 if ( context.verboseMapping ) { 115 dyld::log("dyld: Main executable mapped %s\n", path); 116 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) { 117 const char* name = image->segName(i); 118 if ( (strcmp(name, "__PAGEZERO") == 0) || (strcmp(name, "__UNIXSTACK") == 0) ) 119 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segPreferredLoadAddress(i), image->segPreferredLoadAddress(i)+image->segSize(i)); 120 else 121 dyld::log("%18s at 0x%08lX->0x%08lX\n", name, image->segActualLoadAddress(i), image->segActualEndAddress(i)); 122 } 123 } 124 125 return image; 126} 127 128// create image by mapping in a mach-o file 129ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromFile(const char* path, int fd, const uint8_t* fileData, 130 uint64_t offsetInFat, uint64_t lenInFat, const struct stat& info, 131 unsigned int segCount, unsigned int libCount, 132 const struct linkedit_data_command* codeSigCmd, const LinkContext& context) 133{ 134 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart((macho_header*)fileData, path, segCount, libCount); 135 try { 136 // record info about file 137 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime); 138 139 // if this image is code signed, let kernel validate signature before mapping any pages from image 140 image->loadCodeSignature(codeSigCmd, fd, offsetInFat, context); 141 142 // mmap segments 143 image->mapSegmentsClassic(fd, offsetInFat, lenInFat, info.st_size, context); 144 145 // finish up 146 image->instantiateFinish(context); 147 148 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path 149 const char* installName = image->getInstallPath(); 150 if ( (installName != NULL) && (strcmp(installName, path) == 0) && (path[0] == '/') ) 151 image->setPathUnowned(installName); 152 else if ( (path[0] != '/') || (strstr(path, "../") != NULL) ) { 153 // rdar://problem/10733082 Fix up @path based paths during introspection 154 // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them 155 char realPath[MAXPATHLEN]; 156 if ( fcntl(fd, F_GETPATH, realPath) == 0 ) 157 image->setPaths(path, realPath); 158 else 159 image->setPath(path); 160 } 161 else 162 image->setPath(path); 163 164 // make sure path is stable before recording in dyld_all_image_infos 165 image->setMapped(context); 166 167 // pre-fetch content of __DATA segment for faster launches 168 // don't do this on prebound images or if prefetching is disabled 169 if ( !context.preFetchDisabled && !image->isPrebindable()) 170 image->preFetchDATA(fd, offsetInFat, context); 171 172 } 173 catch (...) { 174 // ImageLoader::setMapped() can throw an exception to block loading of image 175 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 176 delete image; 177 throw; 178 } 179 180 return image; 181} 182 183// create image by using cached mach-o file 184ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, 185 unsigned int segCount, unsigned int libCount, const LinkContext& context) 186{ 187 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, path, segCount, libCount); 188 try { 189 // record info about file 190 image->setFileInfo(info.st_dev, info.st_ino, info.st_mtime); 191 192 // remember this is from shared cache and cannot be unloaded 193 image->fInSharedCache = true; 194 image->setNeverUnload(); 195 196 // segments already mapped in cache 197 if ( context.verboseMapping ) { 198 dyld::log("dyld: Using shared cached for %s\n", path); 199 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) { 200 dyld::log("%18s at 0x%08lX->0x%08lX\n", image->segName(i), image->segActualLoadAddress(i), image->segActualEndAddress(i)); 201 } 202 } 203 204 image->instantiateFinish(context); 205 image->setMapped(context); 206 } 207 catch (...) { 208 // ImageLoader::setMapped() can throw an exception to block loading of image 209 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 210 delete image; 211 throw; 212 } 213 214 return image; 215} 216 217// create image by copying an in-memory mach-o file 218ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, 219 unsigned int segCount, unsigned int libCount, const LinkContext& context) 220{ 221 ImageLoaderMachOClassic* image = ImageLoaderMachOClassic::instantiateStart(mh, moduleName, segCount, libCount); 222 try { 223 // map segments 224 if ( mh->filetype == MH_EXECUTE ) 225 throw "can't load another MH_EXECUTE"; 226 227 // vmcopy segments 228 image->ImageLoaderMachO::mapSegments((const void*)mh, len, context); 229 230 // for compatibility, never unload dylibs loaded from memory 231 image->setNeverUnload(); 232 233 // bundle loads need path copied 234 if ( moduleName != NULL ) 235 image->setPath(moduleName); 236 237 image->instantiateFinish(context); 238 image->setMapped(context); 239 } 240 catch (...) { 241 // ImageLoader::setMapped() can throw an exception to block loading of image 242 // <rdar://problem/6169686> Leaked fSegmentsArray and image segments during failed dlopen_preflight 243 delete image; 244 throw; 245 } 246 247 return image; 248} 249 250 251ImageLoaderMachOClassic::ImageLoaderMachOClassic(const macho_header* mh, const char* path, 252 unsigned int segCount, uint32_t segOffsets[], unsigned int libCount) 253 : ImageLoaderMachO(mh, path, segCount, segOffsets, libCount), fStrings(NULL), fSymbolTable(NULL), fDynamicInfo(NULL) 254{ 255} 256 257// construct ImageLoaderMachOClassic using "placement new" with SegmentMachO objects array at end 258ImageLoaderMachOClassic* ImageLoaderMachOClassic::instantiateStart(const macho_header* mh, const char* path, 259 unsigned int segCount, unsigned int libCount) 260{ 261 size_t size = sizeof(ImageLoaderMachOClassic) + segCount * sizeof(uint32_t) + libCount * sizeof(ImageLoader*); 262 ImageLoaderMachOClassic* allocatedSpace = static_cast<ImageLoaderMachOClassic*>(malloc(size)); 263 if ( allocatedSpace == NULL ) 264 throw "malloc failed"; 265 uint32_t* segOffsets = ((uint32_t*)(((uint8_t*)allocatedSpace) + sizeof(ImageLoaderMachOClassic))); 266 bzero(&segOffsets[segCount], libCount*sizeof(void*)); // zero out lib array 267 return new (allocatedSpace) ImageLoaderMachOClassic(mh, path, segCount, segOffsets, libCount); 268} 269 270 271 272// common code to finish initializing object 273void ImageLoaderMachOClassic::instantiateFinish(const LinkContext& context) 274{ 275 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 276 this->parseLoadCmds(); 277} 278 279ImageLoaderMachOClassic::~ImageLoaderMachOClassic() 280{ 281 // don't do clean up in ~ImageLoaderMachO() because virtual call to segmentCommandOffsets() won't work 282 destroy(); 283} 284 285uint32_t* ImageLoaderMachOClassic::segmentCommandOffsets() const 286{ 287 return ((uint32_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic))); 288} 289 290 291ImageLoader* ImageLoaderMachOClassic::libImage(unsigned int libIndex) const 292{ 293 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t))); 294 // mask off low bits 295 return (ImageLoader*)(images[libIndex] & (-4)); 296} 297 298bool ImageLoaderMachOClassic::libReExported(unsigned int libIndex) const 299{ 300 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t))); 301 // re-export flag is low bit 302 return ((images[libIndex] & 1) != 0); 303} 304 305bool ImageLoaderMachOClassic::libIsUpward(unsigned int libIndex) const 306{ 307 const uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t))); 308 // upward flag is second bit 309 return ((images[libIndex] & 2) != 0); 310} 311 312 313void ImageLoaderMachOClassic::setLibImage(unsigned int libIndex, ImageLoader* image, bool reExported, bool upward) 314{ 315 uintptr_t* images = ((uintptr_t*)(((uint8_t*)this) + sizeof(ImageLoaderMachOClassic) + fSegmentsCount*sizeof(uint32_t))); 316 uintptr_t value = (uintptr_t)image; 317 if ( reExported ) 318 value |= 1; 319 if ( upward ) 320 value |= 2; 321 images[libIndex] = value; 322} 323 324 325void ImageLoaderMachOClassic::setSymbolTableInfo(const macho_nlist* symbols, const char* strings, const dysymtab_command* dynSym) 326{ 327 fSymbolTable = symbols; 328 fStrings = strings; 329 fDynamicInfo = dynSym; 330} 331 332void ImageLoaderMachOClassic::prefetchLINKEDIT(const LinkContext& context) 333{ 334 // always prefetch a subrange of __LINKEDIT pages 335 uintptr_t symbolTableStart = (uintptr_t)fSymbolTable; 336 uintptr_t stringTableStart = (uintptr_t)fStrings; 337 uintptr_t start; 338 // if image did not load at preferred address 339 if ( segPreferredLoadAddress(0) != (uintptr_t)fMachOData ) { 340 // local relocations will be processed, so start pre-fetch at local symbols 341 start = (uintptr_t)fMachOData + fDynamicInfo->locreloff; 342 } 343 else { 344 // otherwise start pre-fetch at global symbols section of symbol table 345 start = symbolTableStart + fDynamicInfo->iextdefsym * sizeof(macho_nlist); 346 } 347 // prefetch ends at end of last undefined string in string pool 348 uintptr_t end = stringTableStart; 349 if ( fDynamicInfo->nundefsym != 0 ) 350 end += fSymbolTable[fDynamicInfo->iundefsym+fDynamicInfo->nundefsym-1].n_un.n_strx; 351 else if ( fDynamicInfo->nextdefsym != 0 ) 352 end += fSymbolTable[fDynamicInfo->iextdefsym+fDynamicInfo->nextdefsym-1].n_un.n_strx; 353 354 // round to whole pages 355 start = start & (-4096); 356 end = (end + 4095) & (-4096); 357 358 // skip if there is only one page 359 if ( (end-start) > 4096 ) { 360 madvise((void*)start, end-start, MADV_WILLNEED); 361 fgTotalBytesPreFetched += (end-start); 362 if ( context.verboseMapping ) { 363 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", "__LINKEDIT", start, end-1); 364 } 365 } 366} 367 368 369#if SPLIT_SEG_DYLIB_SUPPORT 370unsigned int 371ImageLoaderMachOClassic::getExtraZeroFillEntriesCount() 372{ 373 // calculate mapping entries 374 unsigned int extraZeroFillEntries = 0; 375 for(unsigned int i=0; i < fSegmentsCount; ++i) { 376 if ( segHasTrailingZeroFill(i) ) 377 ++extraZeroFillEntries; 378 } 379 380 return extraZeroFillEntries; 381} 382 383void 384ImageLoaderMachOClassic::initMappingTable(uint64_t offsetInFat, 385 shared_file_mapping_np *mappingTable) 386{ 387 for(unsigned int i=0,entryIndex=0; i < fSegmentsCount; ++i, ++entryIndex) { 388 shared_file_mapping_np* entry = &mappingTable[entryIndex]; 389 entry->sfm_address = segActualLoadAddress(i); 390 entry->sfm_size = segFileSize(i); 391 entry->sfm_file_offset = segFileOffset(i) + offsetInFat; 392 entry->sfm_init_prot = VM_PROT_NONE; 393 if ( !segUnaccessible(i) ) { 394 if ( segExecutable(i) ) 395 entry->sfm_init_prot |= VM_PROT_EXECUTE; 396 if ( segReadable(i) ) 397 entry->sfm_init_prot |= VM_PROT_READ; 398 if ( segWriteable(i) ) 399 entry->sfm_init_prot |= VM_PROT_WRITE | VM_PROT_COW; 400 } 401 entry->sfm_max_prot = entry->sfm_init_prot; 402 if ( segHasTrailingZeroFill(i) ) { 403 shared_file_mapping_np* zfentry = &mappingTable[++entryIndex]; 404 zfentry->sfm_address = entry->sfm_address + segFileSize(i); 405 zfentry->sfm_size = segSize(i) - segFileSize(i); 406 zfentry->sfm_file_offset = 0; 407 zfentry->sfm_init_prot = entry->sfm_init_prot | VM_PROT_COW | VM_PROT_ZF; 408 zfentry->sfm_max_prot = zfentry->sfm_init_prot; 409 } 410 } 411} 412 413int 414ImageLoaderMachOClassic::mapSplitSegDylibOutsideSharedRegion(int fd, 415 uint64_t offsetInFat, 416 uint64_t lenInFat, 417 uint64_t fileLen, 418 const LinkContext& context) 419{ 420 uintptr_t nextAltLoadAddress = 0; 421 const unsigned int segmentCount = fSegmentsCount; 422 const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount(); 423 const unsigned int regionCount = segmentCount+extraZeroFillEntries; 424 shared_file_mapping_np regions[regionCount]; 425 initMappingTable(offsetInFat, regions); 426 int r = -1; 427 // find space somewhere to allocate split seg 428 bool foundRoom = false; 429 while ( ! foundRoom ) { 430 foundRoom = true; 431 for(unsigned int i=0; i < regionCount; ++i) { 432 vm_address_t addr = nextAltLoadAddress + regions[i].sfm_address - regions[0].sfm_address; 433 vm_size_t size = regions[i].sfm_size ; 434 r = vm_allocate(mach_task_self(), &addr, size, false /*only this range*/); 435 if ( 0 != r ) { 436 // no room here, deallocate what has succeeded so far 437 for(unsigned int j=0; j < i; ++j) { 438 vm_address_t addr = nextAltLoadAddress + regions[j].sfm_address - regions[0].sfm_address; 439 vm_size_t size = regions[j].sfm_size ; 440 (void)vm_deallocate(mach_task_self(), addr, size); 441 } 442 nextAltLoadAddress += 0x00100000; // skip ahead 1MB and try again 443 // skip over shared region 444 if ( (SHARED_REGION_BASE <= nextAltLoadAddress) && (nextAltLoadAddress < (SHARED_REGION_BASE + SHARED_REGION_SIZE)) ) 445 nextAltLoadAddress = (SHARED_REGION_BASE + SHARED_REGION_SIZE); 446 if ( nextAltLoadAddress > 0xFF000000 ) 447 throw "can't map split seg anywhere"; 448 foundRoom = false; 449 break; 450 } 451 } 452 } 453 454 // map in each region 455 uintptr_t slide = nextAltLoadAddress - regions[0].sfm_address; 456 this->setSlide(slide); 457 for(unsigned int i=0; i < regionCount; ++i) { 458 if ( ((regions[i].sfm_init_prot & VM_PROT_ZF) != 0) || (regions[i].sfm_size == 0) ) { 459 // nothing to mmap for zero-fills areas, they are just vm_allocated 460 } 461 else { 462 void* mmapAddress = (void*)(uintptr_t)(regions[i].sfm_address + slide); 463 size_t size = regions[i].sfm_size; 464 int protection = 0; 465 if ( regions[i].sfm_init_prot & VM_PROT_EXECUTE ) 466 protection |= PROT_EXEC; 467 if ( regions[i].sfm_init_prot & VM_PROT_READ ) 468 protection |= PROT_READ; 469 if ( regions[i].sfm_init_prot & VM_PROT_WRITE ) 470 protection |= PROT_WRITE; 471 off_t offset = regions[i].sfm_file_offset; 472 //dyld::log("mmap(%p, 0x%08lX, %s\n", mmapAddress, size, fPath); 473 mmapAddress = mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset); 474 if ( mmapAddress == ((void*)(-1)) ) 475 throw "mmap error"; 476 } 477 } 478 479 // logging 480 if ( context.verboseMapping ) { 481 dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide, this->getPath()); 482 for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ 483 const shared_file_mapping_np* entry = ®ions[entryIndex]; 484 if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 ) 485 dyld::log("%18s at 0x%08lX->0x%08lX\n", 486 segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1); 487 if ( entryIndex < (regionCount-1) ) { 488 const shared_file_mapping_np* nextEntry = ®ions[entryIndex+1]; 489 if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) { 490 uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address; 491 dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n", 492 segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1)); 493 ++entryIndex; 494 } 495 } 496 } 497 } 498 499 return r; 500} 501#endif // SPLIT_SEG_DYLIB_SUPPORT 502 503 504void ImageLoaderMachOClassic::mapSegmentsClassic(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context) 505{ 506 // non-split segment libraries handled by super class 507 if ( !fIsSplitSeg ) 508 return ImageLoaderMachO::mapSegments(fd, offsetInFat, lenInFat, fileLen, context); 509 510#if SPLIT_SEG_SHARED_REGION_SUPPORT 511 // don't map split-seg dylibs into shared region if shared cache is in use 512 if ( ! context.dyldLoadedAtSameAddressNeededBySharedCache ) { 513 // try to map into shared region at preferred address 514 if ( mapSplitSegDylibInfoSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) == 0) 515 return; 516 } 517 // if there is a problem, fall into case where we map file somewhere outside the shared region 518#endif 519 520#if SPLIT_SEG_DYLIB_SUPPORT 521 // support old split-seg dylibs by mapping them where ever we find space 522 if ( mapSplitSegDylibOutsideSharedRegion(fd, offsetInFat, lenInFat, fileLen, context) != 0 ) 523#endif 524 throw "mapping error"; 525} 526 527 528#if SPLIT_SEG_SHARED_REGION_SUPPORT 529static int _shared_region_map_np(int fd, uint32_t count, const shared_file_mapping_np mappings[]) 530{ 531 return syscall(295, fd, count, mappings); 532} 533 534int 535ImageLoaderMachOClassic::mapSplitSegDylibInfoSharedRegion(int fd, 536 uint64_t offsetInFat, 537 uint64_t lenInFat, 538 uint64_t fileLen, 539 const LinkContext& context) 540{ 541 // build table of segments to map 542 const unsigned int segmentCount = fSegmentsCount; 543 const unsigned int extraZeroFillEntries = getExtraZeroFillEntriesCount(); 544 const unsigned int mappingTableCount = segmentCount+extraZeroFillEntries; 545 shared_file_mapping_np mappingTable[mappingTableCount]; 546 initMappingTable(offsetInFat, mappingTable); 547 548 // try to map it in shared 549 int r = _shared_region_map_np(fd, mappingTableCount, mappingTable); 550 if ( 0 == r ) { 551 this->setNeverUnload(); 552 if ( context.verboseMapping ) { 553 dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath()); 554 for(unsigned int segIndex=0,entryIndex=0; segIndex < segmentCount; ++segIndex, ++entryIndex){ 555 const shared_file_mapping_np* entry = &mappingTable[entryIndex]; 556 if ( (entry->sfm_init_prot & VM_PROT_ZF) == 0 ) 557 dyld::log("%18s at 0x%08lX->0x%08lX\n", 558 segName(segIndex), segActualLoadAddress(segIndex), segActualEndAddress(segIndex)-1); 559 if ( entryIndex < (mappingTableCount-1) ) { 560 const shared_file_mapping_np* nextEntry = &mappingTable[entryIndex+1]; 561 if ( (nextEntry->sfm_init_prot & VM_PROT_ZF) != 0 ) { 562 uint64_t segOffset = nextEntry->sfm_address - entry->sfm_address; 563 dyld::log("%18s at 0x%08lX->0x%08lX\n", 564 segName(segIndex), (uintptr_t)(segActualLoadAddress(segIndex) + segOffset), 565 (uintptr_t)(segActualLoadAddress(segIndex) + segOffset + nextEntry->sfm_size - 1)); 566 ++entryIndex; 567 } 568 } 569 } 570 } 571 } 572 return r; 573} 574 575#endif // SPLIT_SEG_SHARED_REGION_SUPPORT 576 577// test if this image is re-exported through parent (the image that loaded this one) 578bool ImageLoaderMachOClassic::isSubframeworkOf(const LinkContext& context, const ImageLoader* parent) const 579{ 580 if ( fInUmbrella ) { 581 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 582 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 583 const struct load_command* cmd = cmds; 584 for (uint32_t i = 0; i < cmd_count; ++i) { 585 if (cmd->cmd == LC_SUB_FRAMEWORK) { 586 const struct sub_framework_command* subf = (struct sub_framework_command*)cmd; 587 const char* exportThruName = (char*)cmd + subf->umbrella.offset; 588 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent... 589 const char* parentInstallPath = parent->getInstallPath(); 590 if ( parentInstallPath != NULL ) { 591 const char* lastSlash = strrchr(parentInstallPath, '/'); 592 if ( lastSlash != NULL ) { 593 if ( strcmp(&lastSlash[1], exportThruName) == 0 ) 594 return true; 595 if ( context.imageSuffix != NULL ) { 596 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 597 char reexportAndSuffix[strlen(context.imageSuffix)+strlen(exportThruName)+1]; 598 strcpy(reexportAndSuffix, exportThruName); 599 strcat(reexportAndSuffix, context.imageSuffix); 600 if ( strcmp(&lastSlash[1], reexportAndSuffix) == 0 ) 601 return true; 602 } 603 } 604 } 605 } 606 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 607 } 608 } 609 return false; 610} 611 612// test if child is re-exported 613bool ImageLoaderMachOClassic::hasSubLibrary(const LinkContext& context, const ImageLoader* child) const 614{ 615 if ( fHasSubLibraries ) { 616 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child... 617 const char* childInstallPath = child->getInstallPath(); 618 if ( childInstallPath != NULL ) { 619 const char* lastSlash = strrchr(childInstallPath, '/'); 620 if ( lastSlash != NULL ) { 621 const char* firstDot = strchr(lastSlash, '.'); 622 int len; 623 if ( firstDot == NULL ) 624 len = strlen(lastSlash); 625 else 626 len = firstDot-lastSlash-1; 627 char childLeafName[len+1]; 628 strncpy(childLeafName, &lastSlash[1], len); 629 childLeafName[len] = '\0'; 630 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 631 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 632 const struct load_command* cmd = cmds; 633 for (uint32_t i = 0; i < cmd_count; ++i) { 634 switch (cmd->cmd) { 635 case LC_SUB_LIBRARY: 636 { 637 const struct sub_library_command* lib = (struct sub_library_command*)cmd; 638 const char* aSubLibName = (char*)cmd + lib->sub_library.offset; 639 if ( strcmp(aSubLibName, childLeafName) == 0 ) 640 return true; 641 if ( context.imageSuffix != NULL ) { 642 // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end 643 char aSubLibNameAndSuffix[strlen(context.imageSuffix)+strlen(aSubLibName)+1]; 644 strcpy(aSubLibNameAndSuffix, aSubLibName); 645 strcat(aSubLibNameAndSuffix, context.imageSuffix); 646 if ( strcmp(aSubLibNameAndSuffix, childLeafName) == 0 ) 647 return true; 648 } 649 } 650 break; 651 } 652 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 653 } 654 } 655 } 656 } 657 if ( fHasSubUmbrella ) { 658 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child... 659 const char* childInstallPath = child->getInstallPath(); 660 if ( childInstallPath != NULL ) { 661 const char* lastSlash = strrchr(childInstallPath, '/'); 662 if ( lastSlash != NULL ) { 663 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 664 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 665 const struct load_command* cmd = cmds; 666 for (uint32_t i = 0; i < cmd_count; ++i) { 667 switch (cmd->cmd) { 668 case LC_SUB_UMBRELLA: 669 { 670 const struct sub_umbrella_command* um = (struct sub_umbrella_command*)cmd; 671 const char* aSubUmbrellaName = (char*)cmd + um->sub_umbrella.offset; 672 if ( strcmp(aSubUmbrellaName, &lastSlash[1]) == 0 ) 673 return true; 674 if ( context.imageSuffix != NULL ) { 675 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end 676 char umbrellaAndSuffix[strlen(context.imageSuffix)+strlen(aSubUmbrellaName)+1]; 677 strcpy(umbrellaAndSuffix, aSubUmbrellaName); 678 strcat(umbrellaAndSuffix, context.imageSuffix); 679 if ( strcmp(umbrellaAndSuffix, &lastSlash[1]) == 0 ) 680 return true; 681 } 682 } 683 break; 684 } 685 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 686 } 687 } 688 } 689 } 690 return false; 691} 692 693 694uintptr_t ImageLoaderMachOClassic::getFirstWritableSegmentAddress() 695{ 696 // in split segment libraries r_address is offset from first writable segment 697 for(unsigned int i=0; i < fSegmentsCount; ++i) { 698 if ( segWriteable(i) ) 699 return segActualLoadAddress(i); 700 } 701 throw "no writable segment"; 702} 703 704uintptr_t ImageLoaderMachOClassic::getRelocBase() 705{ 706 // r_address is either an offset from the first segment address 707 // or from the first writable segment address 708#if __x86_64__ 709 return getFirstWritableSegmentAddress(); 710#else 711 if ( fIsSplitSeg ) 712 return getFirstWritableSegmentAddress(); 713 else 714 return segActualLoadAddress(0); 715#endif 716} 717 718 719#if PREBOUND_IMAGE_SUPPORT 720void ImageLoaderMachOClassic::resetPreboundLazyPointers(const LinkContext& context) 721{ 722 // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values 723 const uintptr_t relocBase = this->getRelocBase(); 724 register const uintptr_t slide = this->fSlide; 725 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]); 726 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel]; 727 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { 728 if ( (reloc->r_address & R_SCATTERED) != 0 ) { 729 const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc; 730 if (sreloc->r_length == RELOC_SIZE) { 731 uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase); 732 switch(sreloc->r_type) { 733 #if __i386__ 734 case GENERIC_RELOC_PB_LA_PTR: 735 *locationToFix = sreloc->r_value + slide; 736 break; 737 #endif 738 #if __arm__ 739 case ARM_RELOC_PB_LA_PTR: 740 *locationToFix = sreloc->r_value + slide; 741 break; 742 #endif 743 } 744 } 745 } 746 } 747} 748#endif 749 750 751 752 753void ImageLoaderMachOClassic::rebase(const LinkContext& context) 754{ 755 CRSetCrashLogMessage2(this->getPath()); 756 register const uintptr_t slide = this->fSlide; 757 const uintptr_t relocBase = this->getRelocBase(); 758 759 // prefetch any LINKEDIT pages needed 760 if ( !context.preFetchDisabled && !this->isPrebindable()) 761 this->prefetchLINKEDIT(context); 762 763 // loop through all local (internal) relocation records 764 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->locreloff]); 765 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nlocrel]; 766 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { 767 uintptr_t rebaseAddr; 768 try { 769 #if LINKEDIT_USAGE_DEBUG 770 noteAccessedLinkEditAddress(reloc); 771 #endif 772 #if __x86_64__ 773 // only one kind of local relocation supported for x86_64 774 if ( reloc->r_length != 3 ) 775 throw "bad local relocation length"; 776 if ( reloc->r_type != X86_64_RELOC_UNSIGNED ) 777 throw "unknown local relocation type"; 778 if ( reloc->r_pcrel != 0 ) 779 throw "bad local relocation pc_rel"; 780 if ( reloc->r_extern != 0 ) 781 throw "extern relocation found with local relocations"; 782 rebaseAddr = reloc->r_address + relocBase; 783 if ( ! this->containsAddress((void*)rebaseAddr) ) 784 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr); 785 *((uintptr_t*)rebaseAddr) += slide; 786 if ( context.verboseRebase ) 787 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide); 788 #else 789 if ( (reloc->r_address & R_SCATTERED) == 0 ) { 790 if ( reloc->r_symbolnum == R_ABS ) { 791 // ignore absolute relocations 792 } 793 else if (reloc->r_length == RELOC_SIZE) { 794 switch(reloc->r_type) { 795 case GENERIC_RELOC_VANILLA: 796 rebaseAddr = reloc->r_address + relocBase; 797 if ( ! this->containsAddress((void*)rebaseAddr) ) 798 dyld::throwf("local reloc %p not in mapped image\n", (void*)rebaseAddr); 799 *((uintptr_t*)rebaseAddr) += slide; 800 if ( context.verboseRebase ) 801 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), rebaseAddr, slide); 802 break; 803 default: 804 throw "unknown local relocation type"; 805 } 806 } 807 else { 808 throw "bad local relocation length"; 809 } 810 } 811 else { 812 const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc; 813 if (sreloc->r_length == RELOC_SIZE) { 814 uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase); 815 switch(sreloc->r_type) { 816 case GENERIC_RELOC_VANILLA: 817 if ( ! this->containsAddress((void*)locationToFix) ) 818 dyld::throwf("local scattered reloc %p not in mapped image\n", locationToFix); 819 *locationToFix += slide; 820 if ( context.verboseRebase ) 821 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX\n", this->getShortName(), (uintptr_t)locationToFix, slide); 822 break; 823 #if __i386__ 824 case GENERIC_RELOC_PB_LA_PTR: 825 // do nothing 826 break; 827 #elif __arm__ 828 case ARM_RELOC_PB_LA_PTR: 829 // do nothing 830 break; 831 #endif 832 default: 833 throw "unknown local scattered relocation type"; 834 } 835 } 836 else { 837 throw "bad local scattered relocation length"; 838 } 839 } 840 #endif // x86_64 841 } 842 catch (const char* msg) { 843 const uint8_t* r = (uint8_t*)reloc; 844 dyld::throwf("%s in %s. reloc record at %p: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", 845 msg, this->getPath(), reloc, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); 846 } 847 } 848 849 // update stats 850 fgTotalRebaseFixups += fDynamicInfo->nlocrel; 851 CRSetCrashLogMessage2(NULL); 852} 853 854 855 856const struct macho_nlist* ImageLoaderMachOClassic::binarySearchWithToc(const char* key, const char stringPool[], const struct macho_nlist symbols[], 857 const struct dylib_table_of_contents toc[], uint32_t symbolCount, uint32_t hintIndex) const 858{ 859 int32_t high = symbolCount-1; 860 int32_t mid = hintIndex; 861 862 // handle out of range hint 863 if ( mid >= (int32_t)symbolCount ) 864 mid = symbolCount/2; 865 ++ImageLoaderMachO::fgSymbolTableBinarySearchs; 866 ++fgTotalBindImageSearches; 867 868 //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName()); 869 870 for (int32_t low = 0; low <= high; mid = (low+high)/2) { 871 const uint32_t index = toc[mid].symbol_index; 872 const struct macho_nlist* pivot = &symbols[index]; 873 const char* pivotStr = &stringPool[pivot->n_un.n_strx]; 874#if LINKEDIT_USAGE_DEBUG 875 noteAccessedLinkEditAddress(&toc[mid]); 876 noteAccessedLinkEditAddress(pivot); 877 noteAccessedLinkEditAddress(pivotStr); 878#endif 879 int cmp = strcmp(key, pivotStr); 880 if ( cmp == 0 ) 881 return pivot; 882 if ( cmp > 0 ) { 883 // key > pivot 884 low = mid + 1; 885 } 886 else { 887 // key < pivot 888 high = mid - 1; 889 } 890 } 891 return NULL; 892} 893 894const struct macho_nlist* ImageLoaderMachOClassic::binarySearch(const char* key, const char stringPool[], const struct macho_nlist symbols[], uint32_t symbolCount) const 895{ 896 // update stats 897 ++fgTotalBindImageSearches; 898 ++ImageLoaderMachO::fgSymbolTableBinarySearchs; 899 900 //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n", 901 // key, this->getShortName(), stringPool, symbols, symbolCount); 902 903 const struct macho_nlist* base = symbols; 904 for (uint32_t n = symbolCount; n > 0; n /= 2) { 905 const struct macho_nlist* pivot = &base[n/2]; 906 const char* pivotStr = &stringPool[pivot->n_un.n_strx]; 907#if LINKEDIT_USAGE_DEBUG 908 noteAccessedLinkEditAddress(pivot); 909 noteAccessedLinkEditAddress(pivotStr); 910#endif 911 int cmp = strcmp(key, pivotStr); 912 if ( cmp == 0 ) 913 return pivot; 914 if ( cmp > 0 ) { 915 // key > pivot 916 // move base to symbol after pivot 917 base = &pivot[1]; 918 --n; 919 } 920 else { 921 // key < pivot 922 // keep same base 923 } 924 } 925 return NULL; 926} 927 928 929const ImageLoader::Symbol* ImageLoaderMachOClassic::findExportedSymbol(const char* name, const ImageLoader** foundIn) const 930{ 931 const struct macho_nlist* sym = NULL; 932 if ( fDynamicInfo->tocoff == 0 ) 933 sym = binarySearch(name, fStrings, &fSymbolTable[fDynamicInfo->iextdefsym], fDynamicInfo->nextdefsym); 934 else 935 sym = binarySearchWithToc(name, fStrings, fSymbolTable, (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff], 936 fDynamicInfo->ntoc, fDynamicInfo->nextdefsym); 937 if ( sym != NULL ) { 938 if ( foundIn != NULL ) 939 *foundIn = (ImageLoader*)this; 940 return (const Symbol*)sym; 941 } 942 return NULL; 943} 944 945 946 947bool ImageLoaderMachOClassic::containsSymbol(const void* addr) const 948{ 949 return ( (fSymbolTable <= addr) && (addr < fStrings) ); 950} 951 952 953uintptr_t ImageLoaderMachOClassic::exportedSymbolAddress(const LinkContext& context, const Symbol* symbol, const ImageLoader* requestor, bool runResolver) const 954{ 955 const struct macho_nlist* sym = (macho_nlist*)symbol; 956 uintptr_t result = sym->n_value + fSlide; 957 #if __arm__ 958 // processor assumes code address with low bit set is thumb 959 if (sym->n_desc & N_ARM_THUMB_DEF) 960 result |= 1; 961 #endif 962 return result; 963} 964 965bool ImageLoaderMachOClassic::exportedSymbolIsWeakDefintion(const Symbol* symbol) const 966{ 967 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol; 968 return ( (nlistSym->n_desc & N_WEAK_DEF) != 0 ); 969} 970 971const char* ImageLoaderMachOClassic::exportedSymbolName(const Symbol* symbol) const 972{ 973 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol; 974 return &fStrings[nlistSym->n_un.n_strx]; 975} 976 977unsigned int ImageLoaderMachOClassic::exportedSymbolCount() const 978{ 979 return fDynamicInfo->nextdefsym; 980} 981 982const ImageLoader::Symbol* ImageLoaderMachOClassic::exportedSymbolIndexed(unsigned int index) const 983{ 984 if ( index < fDynamicInfo->nextdefsym ) { 985 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym + index]; 986 return (const ImageLoader::Symbol*)sym; 987 } 988 return NULL; 989} 990 991unsigned int ImageLoaderMachOClassic::importedSymbolCount() const 992{ 993 return fDynamicInfo->nundefsym; 994} 995 996const ImageLoader::Symbol* ImageLoaderMachOClassic::importedSymbolIndexed(unsigned int index) const 997{ 998 if ( index < fDynamicInfo->nundefsym ) { 999 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iundefsym + index]; 1000 return (const ImageLoader::Symbol*)sym; 1001 } 1002 return NULL; 1003} 1004 1005const char* ImageLoaderMachOClassic::importedSymbolName(const Symbol* symbol) const 1006{ 1007 const struct macho_nlist* nlistSym = (const struct macho_nlist*)symbol; 1008 return &fStrings[nlistSym->n_un.n_strx]; 1009} 1010 1011 1012 1013bool ImageLoaderMachOClassic::symbolIsWeakDefinition(const struct macho_nlist* symbol) 1014{ 1015 // if a define and weak ==> coalesced 1016 if ( ((symbol->n_type & N_TYPE) == N_SECT) && ((symbol->n_desc & N_WEAK_DEF) != 0) ) 1017 return true; 1018 1019 // regular symbol 1020 return false; 1021} 1022 1023bool ImageLoaderMachOClassic::symbolIsWeakReference(const struct macho_nlist* symbol) 1024{ 1025 // if an undefine and not referencing a weak symbol ==> coalesced 1026 if ( ((symbol->n_type & N_TYPE) != N_SECT) && ((symbol->n_desc & N_REF_TO_WEAK) != 0) ) 1027 return true; 1028 1029 // regular symbol 1030 return false; 1031} 1032 1033uintptr_t ImageLoaderMachOClassic::getSymbolAddress(const macho_nlist* sym, const LinkContext& context, bool runResolver) const 1034{ 1035 return ImageLoaderMachO::getSymbolAddress((Symbol*)sym, this, context, runResolver); 1036} 1037 1038uintptr_t ImageLoaderMachOClassic::resolveUndefined(const LinkContext& context, const struct macho_nlist* undefinedSymbol, 1039 bool twoLevel, bool dontCoalesce, const ImageLoader** foundIn) 1040{ 1041 ++fgTotalBindSymbolsResolved; 1042 const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx]; 1043 1044#if LINKEDIT_USAGE_DEBUG 1045 noteAccessedLinkEditAddress(undefinedSymbol); 1046 noteAccessedLinkEditAddress(symbolName); 1047#endif 1048 if ( context.bindFlat || !twoLevel ) { 1049 // flat lookup 1050 if ( ((undefinedSymbol->n_type & N_PEXT) != 0) && ((undefinedSymbol->n_type & N_TYPE) == N_SECT) ) { 1051 // is a multi-module private_extern internal reference that the linker did not optimize away 1052 uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false); 1053 *foundIn = this; 1054 return addr; 1055 } 1056 const Symbol* sym; 1057 if ( context.flatExportFinder(symbolName, &sym, foundIn) ) { 1058 if ( *foundIn != this ) 1059 context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn)); 1060 return (*foundIn)->getExportedSymbolAddress(sym, context, this); 1061 } 1062 // if a bundle is loaded privately the above will not find its exports 1063 if ( this->isBundle() && this->hasHiddenExports() ) { 1064 // look in self for needed symbol 1065 sym = this->findExportedSymbol(symbolName, foundIn); 1066 if ( sym != NULL ) 1067 return (*foundIn)->getExportedSymbolAddress(sym, context, this); 1068 } 1069 if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) { 1070 // definition can't be found anywhere 1071 // if reference is weak_import, then it is ok, just return 0 1072 return 0; 1073 } 1074 throwSymbolNotFound(context, symbolName, this->getPath(), "flat namespace"); 1075 } 1076 else { 1077 // symbol requires searching images with coalesced symbols (not done during prebinding) 1078 if ( !context.prebinding && !dontCoalesce && (symbolIsWeakReference(undefinedSymbol) || symbolIsWeakDefinition(undefinedSymbol)) ) { 1079 const Symbol* sym; 1080 if ( context.coalescedExportFinder(symbolName, &sym, foundIn) ) { 1081 if ( *foundIn != this ) 1082 context.addDynamicReference(this, const_cast<ImageLoader*>(*foundIn)); 1083 return (*foundIn)->getExportedSymbolAddress(sym, context, this); 1084 } 1085 //throwSymbolNotFound(context, symbolName, this->getPath(), "coalesced namespace"); 1086 //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName); 1087 } 1088 1089 // if this is a real definition (not an undefined symbol) there is no ordinal 1090 if ( (undefinedSymbol->n_type & N_TYPE) == N_SECT ) { 1091 // static linker should never generate this case, but if it does, do something sane 1092 uintptr_t addr = this->getSymbolAddress(undefinedSymbol, context, false); 1093 *foundIn = this; 1094 return addr; 1095 } 1096 1097 // two level lookup 1098 ImageLoader* target = NULL; 1099 uint8_t ord = GET_LIBRARY_ORDINAL(undefinedSymbol->n_desc); 1100 if ( ord == EXECUTABLE_ORDINAL ) { 1101 target = context.mainExecutable; 1102 } 1103 else if ( ord == SELF_LIBRARY_ORDINAL ) { 1104 target = this; 1105 } 1106 else if ( ord == DYNAMIC_LOOKUP_ORDINAL ) { 1107 // rnielsen: HACKHACK 1108 // flat lookup 1109 const Symbol* sym; 1110 if ( context.flatExportFinder(symbolName, &sym, foundIn) ) 1111 return (*foundIn)->getExportedSymbolAddress(sym, context, this); 1112 // no image has exports this symbol 1113 // report error 1114 context.undefinedHandler(symbolName); 1115 // try looking again 1116 if ( context.flatExportFinder(symbolName, &sym, foundIn) ) 1117 return (*foundIn)->getExportedSymbolAddress(sym, context, this); 1118 1119 throwSymbolNotFound(context, symbolName, this->getPath(), "dynamic lookup"); 1120 } 1121 else if ( ord <= libraryCount() ) { 1122 target = libImage(ord-1); 1123 if ( target == NULL ) { 1124 // if target library not loaded and reference is weak or library is weak return 0 1125 return 0; 1126 } 1127 } 1128 else { 1129 dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s", 1130 ord, libraryCount(), symbolName, this->getPath()); 1131 } 1132 1133 if ( target == NULL ) { 1134 //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath()); 1135 throw "symbol not found"; 1136 } 1137 1138 const Symbol* sym = target->findExportedSymbol(symbolName, true, foundIn); 1139 if ( sym!= NULL ) { 1140 return (*foundIn)->getExportedSymbolAddress(sym, context, this); 1141 } 1142 else if ( (undefinedSymbol->n_type & N_PEXT) != 0 ) { 1143 // don't know why the static linker did not eliminate the internal reference to a private extern definition 1144 *foundIn = this; 1145 return this->getSymbolAddress(undefinedSymbol, context, false); 1146 } 1147 else if ( (undefinedSymbol->n_desc & N_WEAK_REF) != 0 ) { 1148 // if definition not found and reference is weak return 0 1149 return 0; 1150 } 1151 1152 // nowhere to be found 1153 throwSymbolNotFound(context, symbolName, this->getPath(), target->getPath()); 1154 } 1155} 1156 1157 1158 1159// returns if 'addr' is within the address range of section 'sectionIndex' 1160// fSlide is not used. 'addr' is assumed to be a prebound address in this image 1161bool ImageLoaderMachOClassic::isAddrInSection(uintptr_t addr, uint8_t sectionIndex) 1162{ 1163 uint8_t currentSectionIndex = 1; 1164 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1165 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1166 const struct load_command* cmd = cmds; 1167 for (uint32_t i = 0; i < cmd_count; ++i) { 1168 if ( cmd->cmd == LC_SEGMENT_COMMAND ) { 1169 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1170 if ( (currentSectionIndex <= sectionIndex) && (sectionIndex < currentSectionIndex+seg->nsects) ) { 1171 // 'sectionIndex' is in this segment, get section info 1172 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1173 const struct macho_section* const section = §ionsStart[sectionIndex-currentSectionIndex]; 1174 return ( (section->addr <= addr) && (addr < section->addr+section->size) ); 1175 } 1176 else { 1177 // 'sectionIndex' not in this segment, skip to next segment 1178 currentSectionIndex += seg->nsects; 1179 } 1180 } 1181 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1182 } 1183 1184 return false; 1185} 1186 1187void ImageLoaderMachOClassic::doBindExternalRelocations(const LinkContext& context) 1188{ 1189 const uintptr_t relocBase = this->getRelocBase(); 1190 const bool twoLevel = this->usesTwoLevelNameSpace(); 1191 const bool prebound = this->isPrebindable(); 1192 1193#if TEXT_RELOC_SUPPORT 1194 // if there are __TEXT fixups, temporarily make __TEXT writable 1195 if ( fTextSegmentBinds ) 1196 this->makeTextSegmentWritable(context, true); 1197#endif 1198 // cache last lookup 1199 const struct macho_nlist* lastUndefinedSymbol = NULL; 1200 uintptr_t symbolAddr = 0; 1201 const ImageLoader* image = NULL; 1202 1203 // loop through all external relocation records and bind each 1204 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]); 1205 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel]; 1206 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { 1207 if (reloc->r_length == RELOC_SIZE) { 1208 switch(reloc->r_type) { 1209 case POINTER_RELOC: 1210 { 1211 const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum]; 1212 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase)); 1213 if ( ! this->containsAddress((void*)location) ) 1214 dyld::throwf("external reloc %p not in mapped image %s\n", (void*)location, this->getPath()); 1215 uintptr_t value = *location; 1216 bool symbolAddrCached = true; 1217 #if __i386__ 1218 if ( reloc->r_pcrel ) { 1219 value += (uintptr_t)location + 4 - fSlide; 1220 } 1221 #endif 1222 if ( prebound ) { 1223 // we are doing relocations, so prebinding was not usable 1224 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound 1225 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address 1226 // if mach-o relocation structs had an "addend" field this complication would not be necessary. 1227 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) { 1228 // weak symbols need special casing, since *location may have been prebound to a definition in another image. 1229 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume 1230 // that we can subtract off the weak symbol address to get the addend. 1231 // If prebound elsewhere, we've lost the addend and have to assume it is zero. 1232 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs 1233 if ( (value == undefinedSymbol->n_value) || this->isAddrInSection(value, undefinedSymbol->n_sect) ) { 1234 value -= undefinedSymbol->n_value; 1235 #if __arm__ 1236 // if weak and thumb subtract off extra thumb bit 1237 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 ) 1238 value -= 1; 1239 #endif 1240 } 1241 else 1242 value = 0; 1243 } 1244 #if __arm__ 1245 else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) { 1246 // it was prebound to a defined symbol for thumb code in the same linkage unit 1247 // we need to subtract off one to get real addend 1248 value -= (undefinedSymbol->n_value+1); 1249 } 1250 #endif 1251 else { 1252 // is undefined or non-weak symbol, so do subtraction to get addend 1253 value -= undefinedSymbol->n_value; 1254 } 1255 } 1256 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too 1257 if ( undefinedSymbol != lastUndefinedSymbol ) { 1258 bool dontCoalesce = true; 1259 if ( symbolIsWeakReference(undefinedSymbol) ) { 1260 // when weakbind() is run on a classic mach-o encoding, it won't try 1261 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted 1262 // range of global symbols. To handle that case we do the coalesing now. 1263 dontCoalesce = false; 1264 } 1265 symbolAddr = this->resolveUndefined(context, undefinedSymbol, twoLevel, dontCoalesce, &image); 1266 lastUndefinedSymbol = undefinedSymbol; 1267 symbolAddrCached = false; 1268 } 1269 if ( context.verboseBind ) { 1270 const char *path = NULL; 1271 if ( image != NULL ) { 1272 path = image->getShortName(); 1273 } 1274 const char* cachedString = "(cached)"; 1275 if ( !symbolAddrCached ) 1276 cachedString = ""; 1277 if ( value == 0 ) { 1278 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n", 1279 this->getShortName(), (uintptr_t)location, 1280 path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString); 1281 } 1282 else { 1283 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n", 1284 this->getShortName(), (uintptr_t)location, 1285 path, &fStrings[undefinedSymbol->n_un.n_strx], (uintptr_t)location, symbolAddr, cachedString, value); 1286 } 1287 } 1288 value += symbolAddr; 1289 #if __i386__ 1290 if ( reloc->r_pcrel ) { 1291 *location = value - ((uintptr_t)location + 4); 1292 } 1293 else { 1294 // don't dirty page if prebound value was correct 1295 if ( !prebound || (*location != value) ) 1296 *location = value; 1297 } 1298 #else 1299 // don't dirty page if prebound value was correct 1300 if ( !prebound || (*location != value) ) 1301 *location = value; 1302 #endif 1303 // update stats 1304 ++fgTotalBindFixups; 1305 } 1306 break; 1307 default: 1308 throw "unknown external relocation type"; 1309 } 1310 } 1311 else { 1312 throw "bad external relocation length"; 1313 } 1314 } 1315 1316#if TEXT_RELOC_SUPPORT 1317 // if there were __TEXT fixups, restore write protection 1318 if ( fTextSegmentBinds ) { 1319 this->makeTextSegmentWritable(context, true); 1320 } 1321#endif 1322} 1323 1324 1325 1326uintptr_t ImageLoaderMachOClassic::bindIndirectSymbol(uintptr_t* ptrToBind, const struct macho_section* sect, const char* symbolName, uintptr_t targetAddr, const ImageLoader* targetImage, const LinkContext& context) 1327{ 1328 if ( context.verboseBind ) { 1329 const char* path = NULL; 1330 if ( targetImage != NULL ) 1331 path = targetImage->getShortName(); 1332 dyld::log("dyld: bind indirect sym: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n", 1333 this->getShortName(), symbolName, (((sect->flags & SECTION_TYPE)==S_NON_LAZY_SYMBOL_POINTERS) ? "non_lazy_ptr" : "lazy_ptr"), 1334 ((path != NULL) ? path : "<weak_import-not-found>"), symbolName, (uintptr_t)ptrToBind, targetAddr); 1335 } 1336 if ( context.bindingHandler != NULL ) { 1337 const char* path = NULL; 1338 if ( targetImage != NULL ) 1339 path = targetImage->getShortName(); 1340 targetAddr = (uintptr_t)context.bindingHandler(path, symbolName, (void *)targetAddr); 1341 } 1342#if __i386__ 1343 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32" 1344 if ( ((sect->flags & SECTION_TYPE) == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) { 1345 uint32_t rel32 = targetAddr - (((uint32_t)ptrToBind)+5); 1346 // re-write instruction in a thread-safe manner 1347 // use 8-byte compare-and-swap to alter 5-byte jump table entries 1348 // loop is required in case the extra three bytes that cover the next entry are altered by another thread 1349 bool done = false; 1350 while ( !done ) { 1351 volatile int64_t* jumpPtr = (int64_t*)ptrToBind; 1352 int pad = 0; 1353 // By default the three extra bytes swapped follow the 5-byte JMP. 1354 // But, if the 5-byte jump is up against the end of the __IMPORT segment 1355 // We don't want to access bytes off the end of the segment, so we shift 1356 // the extra bytes to precede the 5-byte JMP. 1357 if ( (((uint32_t)ptrToBind + 8) & 0x00000FFC) == 0x00000000 ) { 1358 jumpPtr = (int64_t*)((uint32_t)ptrToBind - 3); 1359 pad = 3; 1360 } 1361 int64_t oldEntry = *jumpPtr; 1362 union { 1363 int64_t int64; 1364 uint8_t bytes[8]; 1365 } newEntry; 1366 newEntry.int64 = oldEntry; 1367 newEntry.bytes[pad+0] = 0xE9; // JMP rel32 1368 newEntry.bytes[pad+1] = rel32 & 0xFF; 1369 newEntry.bytes[pad+2] = (rel32 >> 8) & 0xFF; 1370 newEntry.bytes[pad+3] = (rel32 >> 16) & 0xFF; 1371 newEntry.bytes[pad+4] = (rel32 >> 24) & 0xFF; 1372 done = OSAtomicCompareAndSwap64Barrier(oldEntry, newEntry.int64, (int64_t*)jumpPtr); 1373 } 1374 } 1375 else 1376#endif 1377 *ptrToBind = targetAddr; 1378 return targetAddr; 1379} 1380 1381uintptr_t ImageLoaderMachOClassic::doBindFastLazySymbol(uint32_t lazyBindingInfoOffset, const LinkContext& context, void (*lock)(), void (*unlock)()) 1382{ 1383 throw "compressed LINKEDIT lazy binder called with classic LINKEDIT"; 1384} 1385 1386uintptr_t ImageLoaderMachOClassic::doBindLazySymbol(uintptr_t* lazyPointer, const LinkContext& context) 1387{ 1388 // scan for all lazy-pointer sections 1389 const bool twoLevel = this->usesTwoLevelNameSpace(); 1390 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1391 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1392 const struct load_command* cmd = cmds; 1393 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff]; 1394 for (uint32_t i = 0; i < cmd_count; ++i) { 1395 switch (cmd->cmd) { 1396 case LC_SEGMENT_COMMAND: 1397 { 1398 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1399 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1400 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1401 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1402 const uint8_t type = sect->flags & SECTION_TYPE; 1403 uint32_t symbolIndex = INDIRECT_SYMBOL_LOCAL; 1404 if ( type == S_LAZY_SYMBOL_POINTERS ) { 1405 const uint32_t pointerCount = sect->size / sizeof(uintptr_t); 1406 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide); 1407 if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) { 1408 const uint32_t indirectTableOffset = sect->reserved1; 1409 const uint32_t lazyIndex = lazyPointer - symbolPointers; 1410 symbolIndex = indirectTable[indirectTableOffset + lazyIndex]; 1411 } 1412 } 1413 #if __i386__ 1414 else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) { 1415 // 5 bytes stubs on i386 are new "fast stubs" 1416 uint8_t* const jmpTableBase = (uint8_t*)(sect->addr + fSlide); 1417 uint8_t* const jmpTableEnd = jmpTableBase + sect->size; 1418 // initial CALL instruction in jump table leaves pointer to next entry, so back up 1419 uint8_t* const jmpTableEntryToPatch = ((uint8_t*)lazyPointer) - 5; 1420 lazyPointer = (uintptr_t*)jmpTableEntryToPatch; 1421 if ( (jmpTableEntryToPatch >= jmpTableBase) && (jmpTableEntryToPatch < jmpTableEnd) ) { 1422 const uint32_t indirectTableOffset = sect->reserved1; 1423 const uint32_t entryIndex = (jmpTableEntryToPatch - jmpTableBase)/5; 1424 symbolIndex = indirectTable[indirectTableOffset + entryIndex]; 1425 } 1426 } 1427 #endif 1428 if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) { 1429 const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx]; 1430 const ImageLoader* image = NULL; 1431 uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], twoLevel, false, &image); 1432 symbolAddr = this->bindIndirectSymbol(lazyPointer, sect, symbolName, symbolAddr, image, context); 1433 ++fgTotalLazyBindFixups; 1434 return symbolAddr; 1435 } 1436 } 1437 } 1438 break; 1439 } 1440 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1441 } 1442 dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer, this->getPath()); 1443} 1444 1445 1446 1447void ImageLoaderMachOClassic::initializeCoalIterator(CoalIterator& it, unsigned int loadOrder) 1448{ 1449 it.image = this; 1450 it.symbolName = " "; 1451 it.loadOrder = loadOrder; 1452 it.weakSymbol = false; 1453 it.symbolMatches = false; 1454 it.done = false; 1455 it.type = 0; 1456 if ( fDynamicInfo->tocoff != 0 ) { 1457 it.curIndex = 0; 1458 it.endIndex = fDynamicInfo->ntoc; 1459 } 1460 else { 1461 it.curIndex = 0; 1462 it.endIndex = fDynamicInfo->nextdefsym; 1463 } 1464} 1465 1466 1467bool ImageLoaderMachOClassic::incrementCoalIterator(CoalIterator& it) 1468{ 1469 if ( it.done ) 1470 return false; 1471 1472 if ( fDynamicInfo->tocoff != 0 ) { 1473 if ( it.curIndex >= fDynamicInfo->ntoc ) { 1474 it.done = true; 1475 it.symbolName = "~~~"; 1476 return true; 1477 } 1478 else { 1479 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff]; 1480 const uint32_t index = toc[it.curIndex].symbol_index; 1481 const struct macho_nlist* sym = &fSymbolTable[index]; 1482 const char* symStr = &fStrings[sym->n_un.n_strx]; 1483 it.symbolName = symStr; 1484 it.weakSymbol = (sym->n_desc & N_WEAK_DEF); 1485 it.symbolMatches = false; 1486 it.type = 0; // clear flag that says we applied updates for this symbol 1487 //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath()); 1488 it.curIndex++; 1489 return false; 1490 } 1491 } 1492 else { 1493 if ( it.curIndex >= fDynamicInfo->nextdefsym ) { 1494 it.done = true; 1495 it.symbolName = "~~~"; 1496 return true; 1497 } 1498 else { 1499 const struct macho_nlist* sym = &fSymbolTable[fDynamicInfo->iextdefsym+it.curIndex]; 1500 const char* symStr = &fStrings[sym->n_un.n_strx]; 1501 it.symbolName = symStr; 1502 it.weakSymbol = (sym->n_desc & N_WEAK_DEF); 1503 it.symbolMatches = false; 1504 it.type = 0; // clear flag that says we applied updates for this symbol 1505 //dyld::log("incrementCoalIterator() curIndex=%ld, symbolName=%s in %s\n", it.curIndex, symStr, this->getPath()); 1506 it.curIndex++; 1507 return false; 1508 } 1509 } 1510 1511 return false; 1512} 1513 1514uintptr_t ImageLoaderMachOClassic::getAddressCoalIterator(CoalIterator& it, const LinkContext& context) 1515{ 1516 uint32_t symbol_index = 0; 1517 if ( fDynamicInfo->tocoff != 0 ) { 1518 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff]; 1519 symbol_index = toc[it.curIndex-1].symbol_index; 1520 } 1521 else { 1522 symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1; 1523 } 1524 const struct macho_nlist* sym = &fSymbolTable[symbol_index]; 1525 //dyld::log("getAddressCoalIterator() => 0x%llX, %s symbol_index=%d, in %s\n", (uint64_t)(sym->n_value + fSlide), &fStrings[sym->n_un.n_strx], symbol_index, this->getPath()); 1526#if __arm__ 1527 // processor assumes code address with low bit set is thumb 1528 if (sym->n_desc & N_ARM_THUMB_DEF) 1529 return (sym->n_value | 1) + fSlide ; 1530 else 1531 return sym->n_value + fSlide; 1532#else 1533 return sym->n_value + fSlide; 1534#endif 1535} 1536 1537 1538void ImageLoaderMachOClassic::updateUsesCoalIterator(CoalIterator& it, uintptr_t value, ImageLoader* targetImage, const LinkContext& context) 1539{ 1540 // flat_namespace images with classic LINKEDIT do not need late coalescing. 1541 // They still need to be iterated becuase they may implement 1542 // something needed by other coalescing images. 1543 // But they need no updating because during the bind phase every symbol lookup is a full scan. 1544 if ( !this->usesTwoLevelNameSpace() ) 1545 return; 1546 1547 // <rdar://problem/6570879> weak binding done too early with inserted libraries 1548 if ( this->getState() < dyld_image_state_bound ) 1549 return; 1550 1551 uint32_t symbol_index = 0; 1552 if ( fDynamicInfo->tocoff != 0 ) { 1553 const dylib_table_of_contents* toc = (dylib_table_of_contents*)&fLinkEditBase[fDynamicInfo->tocoff]; 1554 symbol_index = toc[it.curIndex-1].symbol_index; 1555 } 1556 else { 1557 symbol_index = fDynamicInfo->iextdefsym+it.curIndex-1; 1558 } 1559 1560 // if this image's copy of the symbol is not a weak definition nor a weak reference then nothing to coalesce here 1561 if ( !symbolIsWeakReference(&fSymbolTable[symbol_index]) && !symbolIsWeakDefinition(&fSymbolTable[symbol_index]) ) { 1562 return; 1563 } 1564 1565 // <rdar://problem/6555720> malformed dylib with duplicate weak symbols causes re-binding 1566 if ( it.type ) 1567 return; 1568 1569 bool boundSomething = false; 1570 // scan external relocations for uses of symbol_index 1571 const uintptr_t relocBase = this->getRelocBase(); 1572 const bool prebound = this->isPrebindable(); 1573 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]); 1574 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel]; 1575 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { 1576 if ( reloc->r_symbolnum == symbol_index ) { 1577 //dyld::log("found external reloc using symbol_index=%d in %s\n",symbol_index, this->getPath()); 1578 const struct macho_nlist* undefinedSymbol = &fSymbolTable[reloc->r_symbolnum]; 1579 const char* symbolName = &fStrings[undefinedSymbol->n_un.n_strx]; 1580 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase)); 1581 const uintptr_t initialValue = *location; 1582 uintptr_t addend = 0; 1583 if ( prebound ) { 1584 // we are doing relocations, so prebinding was not usable 1585 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound 1586 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address 1587 // if mach-o relocation structs had an "addend" field this complication would not be necessary. 1588 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) { 1589 // weak symbols need special casing, since *location may have been prebound to a definition in another image. 1590 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume 1591 // that we can subtract off the weak symbol address to get the addend. 1592 // If prebound elsewhere, we've lost the addend and have to assume it is zero. 1593 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs 1594 if ( (initialValue == undefinedSymbol->n_value) || this->isAddrInSection(initialValue, undefinedSymbol->n_sect) ) { 1595 addend = initialValue - undefinedSymbol->n_value; 1596 #if __arm__ 1597 // if weak and thumb subtract off extra thumb bit 1598 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 ) 1599 addend &= -2; 1600 #endif 1601 } 1602 } 1603 #if __arm__ 1604 else if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0) ) { 1605 // it was prebound to a defined symbol for thumb code in the same linkage unit 1606 // we need to subtract off one to get real addend 1607 addend = initialValue - (undefinedSymbol->n_value+1); 1608 } 1609 #endif 1610 else { 1611 // is undefined or non-weak symbol, so do subtraction to get addend 1612 addend = initialValue - undefinedSymbol->n_value; 1613 } 1614 } 1615 else { 1616 // non-prebound case 1617 if ( ((undefinedSymbol->n_type & N_TYPE) == N_SECT) && ((undefinedSymbol->n_desc & N_WEAK_DEF) != 0) ) { 1618 // if target is weak-def in same linkage unit, then bind phase has already set initialValue 1619 // to be definition address plus addend 1620 //dyld::log("weak def, initialValue=0x%lX, undefAddr=0x%lX\n", initialValue, undefinedSymbol->n_value+fSlide); 1621 addend = initialValue - (undefinedSymbol->n_value + fSlide); 1622 #if __arm__ 1623 // if weak and thumb subtract off extra thumb bit 1624 if ( (undefinedSymbol->n_desc & N_ARM_THUMB_DEF) != 0 ) 1625 addend &= -2; 1626 #endif 1627 } 1628 else { 1629 // nothing fixed up yet, addend is just initial value 1630 //dyld::log("addend=0x%lX\n", initialValue); 1631 addend = initialValue; 1632 } 1633 } 1634 1635 uint8_t type = BIND_TYPE_POINTER; 1636 #if __i386__ 1637 if ( reloc->r_pcrel ) 1638 type = BIND_TYPE_TEXT_PCREL32; 1639 #endif 1640 this->bindLocation(context, (uintptr_t)location, value, targetImage, type, symbolName, addend, "weak "); 1641 boundSomething = true; 1642 } 1643 } 1644 1645 // scan lazy and non-lazy pointers for uses of symbol_index 1646 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1647 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1648 const struct load_command* cmd = cmds; 1649 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff]; 1650 for (uint32_t i = 0; i < cmd_count; ++i) { 1651 if ( cmd->cmd == LC_SEGMENT_COMMAND ) { 1652 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1653 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1654 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1655 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1656 uint32_t elementSize = sizeof(uintptr_t); 1657 switch ( sect->flags & SECTION_TYPE ) { 1658 #if __i386__ 1659 case S_SYMBOL_STUBS: 1660 if ( ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) ==0) || (sect->reserved2 != 5) ) 1661 continue; 1662 elementSize = 5; 1663 #endif 1664 case S_NON_LAZY_SYMBOL_POINTERS: 1665 case S_LAZY_SYMBOL_POINTERS: 1666 { 1667 uint32_t elementCount = sect->size / elementSize; 1668 const uint32_t indirectTableOffset = sect->reserved1; 1669 uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide); 1670 //dyld::log(" scanning section %s of %s starting at %p\n", sect->sectname, this->getShortName(), ptrToBind); 1671 for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) { 1672 if ( indirectTable[indirectTableOffset + j] == symbol_index ) { 1673 //dyld::log(" found symbol index match at %d/%d, ptrToBind=%p\n", j, elementCount, ptrToBind); 1674 // update pointer 1675 this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, it.symbolName, value, targetImage, context); 1676 boundSomething = true; 1677 } 1678 } 1679 } 1680 break; 1681 } 1682 } 1683 } 1684 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1685 } 1686 if ( boundSomething && (targetImage != this) ) { 1687 context.addDynamicReference(this, targetImage); 1688 } 1689 1690 // mark that this symbol has already been bound, so we don't try to bind again 1691 it.type = 1; 1692} 1693 1694 1695void ImageLoaderMachOClassic::bindIndirectSymbolPointers(const LinkContext& context, bool bindNonLazys, bool bindLazys) 1696{ 1697 // scan for all non-lazy-pointer sections 1698 const bool twoLevel = this->usesTwoLevelNameSpace(); 1699 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1700 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1701 const struct load_command* cmd = cmds; 1702 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff]; 1703 for (uint32_t i = 0; i < cmd_count; ++i) { 1704 switch (cmd->cmd) { 1705 case LC_SEGMENT_COMMAND: 1706 { 1707 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1708 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1709 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1710 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1711 bool isLazySymbol = false; 1712 const uint8_t type = sect->flags & SECTION_TYPE; 1713 uint32_t elementSize = sizeof(uintptr_t); 1714 uint32_t elementCount = sect->size / elementSize; 1715 if ( type == S_NON_LAZY_SYMBOL_POINTERS ) { 1716 if ( ! bindNonLazys ) 1717 continue; 1718 } 1719 else if ( type == S_LAZY_SYMBOL_POINTERS ) { 1720 // process each symbol pointer in this section 1721 fgTotalPossibleLazyBindFixups += elementCount; 1722 isLazySymbol = true; 1723 if ( ! bindLazys ) 1724 continue; 1725 } 1726 #if __i386__ 1727 else if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) { 1728 // process each jmp entry in this section 1729 elementCount = sect->size / 5; 1730 elementSize = 5; 1731 fgTotalPossibleLazyBindFixups += elementCount; 1732 isLazySymbol = true; 1733 if ( ! bindLazys ) 1734 continue; 1735 } 1736 #endif 1737 else { 1738 continue; 1739 } 1740 const uint32_t indirectTableOffset = sect->reserved1; 1741 uint8_t* ptrToBind = (uint8_t*)(sect->addr + fSlide); 1742 for (uint32_t j=0; j < elementCount; ++j, ptrToBind += elementSize) { 1743 #if LINKEDIT_USAGE_DEBUG 1744 noteAccessedLinkEditAddress(&indirectTable[indirectTableOffset + j]); 1745 #endif 1746 uint32_t symbolIndex = indirectTable[indirectTableOffset + j]; 1747 if ( symbolIndex == INDIRECT_SYMBOL_LOCAL) { 1748 *((uintptr_t*)ptrToBind) += this->fSlide; 1749 } 1750 else if ( symbolIndex == INDIRECT_SYMBOL_ABS) { 1751 // do nothing since already has absolute address 1752 } 1753 else { 1754 const struct macho_nlist* sym = &fSymbolTable[symbolIndex]; 1755 if ( symbolIndex == 0 ) { 1756 // This could be rdar://problem/3534709 1757 if ( ((const macho_header*)fMachOData)->filetype == MH_EXECUTE ) { 1758 static bool alreadyWarned = false; 1759 if ( (sym->n_type & N_TYPE) != N_UNDF ) { 1760 // The indirect table parallels the (non)lazy pointer sections. For 1761 // instance, to find info about the fifth lazy pointer you look at the 1762 // fifth entry in the indirect table. (try otool -Iv on a file). 1763 // The entry in the indirect table contains an index into the symbol table. 1764 1765 // The bug in ld caused the entry in the indirect table to be zero 1766 // (instead of a magic value that means a local symbol). So, if the 1767 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid 1768 // symbol table index. The check I put in place is to see if the zero'th 1769 // symbol table entry is an import entry (usually it is a local symbol 1770 // definition). 1771 if ( context.verboseWarnings && !alreadyWarned ) { 1772 dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n", 1773 this->getPath(), &fStrings[sym->n_un.n_strx]); 1774 alreadyWarned = true; 1775 } 1776 continue; 1777 } 1778 } 1779 } 1780 const ImageLoader* image = NULL; 1781 // let weak definitions resolve to themselves, later coalescing may overwrite them 1782 bool dontCoalesce = true; 1783 if ( bindLazys && isLazySymbol ) { 1784 // if this is something normally lazy bound, but we are forcing 1785 // it to be bound now, do coalescing 1786 dontCoalesce = false; 1787 } 1788 if ( symbolIsWeakReference(sym) ) { 1789 // when weakbind() is run on a classic mach-o encoding, it won't try 1790 // to coalesce N_REF_TO_WEAK symbols because they are not in the sorted 1791 // range of global symbols. To handle that case we do the coalesing now. 1792 dontCoalesce = false; 1793 } 1794 uintptr_t symbolAddr = resolveUndefined(context, sym, twoLevel, dontCoalesce, &image); 1795 // update pointer 1796 symbolAddr = this->bindIndirectSymbol((uintptr_t*)ptrToBind, sect, &fStrings[sym->n_un.n_strx], symbolAddr, image, context); 1797 // update stats 1798 ++fgTotalBindFixups; 1799 } 1800 } 1801 } 1802 } 1803 break; 1804 } 1805 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1806 } 1807} 1808 1809 1810 1811#if __i386__ 1812void ImageLoaderMachOClassic::initializeLazyStubs(const LinkContext& context) 1813{ 1814 if ( ! this->usablePrebinding(context) ) { 1815 // reset all "fast" stubs 1816 const macho_header* mh = (macho_header*)fMachOData; 1817 const uint32_t cmd_count = mh->ncmds; 1818 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1819 const struct load_command* cmd = cmds; 1820 for (uint32_t i = 0; i < cmd_count; ++i) { 1821 switch (cmd->cmd) { 1822 case LC_SEGMENT_COMMAND: 1823 { 1824 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1825 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1826 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1827 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1828 const uint8_t type = sect->flags & SECTION_TYPE; 1829 if ( (type == S_SYMBOL_STUBS) && (sect->flags & S_ATTR_SELF_MODIFYING_CODE) && (sect->reserved2 == 5) ) { 1830 // reset each jmp entry in this section 1831 const uint32_t indirectTableOffset = sect->reserved1; 1832 const uint32_t* const indirectTable = (uint32_t*)&fLinkEditBase[fDynamicInfo->indirectsymoff]; 1833 uint8_t* start = (uint8_t*)(sect->addr + this->fSlide); 1834 uint8_t* end = start + sect->size; 1835 uintptr_t dyldHandler = (uintptr_t)&fast_stub_binding_helper_interface; 1836 uint32_t entryIndex = 0; 1837 for (uint8_t* entry = start; entry < end; entry += 5, ++entryIndex) { 1838 bool installLazyHandler = true; 1839 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes 1840 // if the instruction is updated by one thread while being executed by another 1841 if ( ((uint32_t)entry & 0xFFFFFFC0) != ((uint32_t)entry+4 & 0xFFFFFFC0) ) { 1842 // need to bind this now to avoid a potential problem if bound lazily 1843 uint32_t symbolIndex = indirectTable[indirectTableOffset + entryIndex]; 1844 // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used 1845 if ( symbolIndex != INDIRECT_SYMBOL_ABS ) { 1846 const char* symbolName = &fStrings[fSymbolTable[symbolIndex].n_un.n_strx]; 1847 const ImageLoader* image = NULL; 1848 try { 1849 uintptr_t symbolAddr = this->resolveUndefined(context, &fSymbolTable[symbolIndex], this->usesTwoLevelNameSpace(), false, &image); 1850 symbolAddr = this->bindIndirectSymbol((uintptr_t*)entry, sect, symbolName, symbolAddr, image, context); 1851 ++fgTotalBindFixups; 1852 uint32_t rel32 = symbolAddr - (((uint32_t)entry)+5); 1853 entry[0] = 0xE9; // JMP rel32 1854 entry[1] = rel32 & 0xFF; 1855 entry[2] = (rel32 >> 8) & 0xFF; 1856 entry[3] = (rel32 >> 16) & 0xFF; 1857 entry[4] = (rel32 >> 24) & 0xFF; 1858 installLazyHandler = false; 1859 } 1860 catch (const char* msg) { 1861 // ignore errors when binding symbols early 1862 // maybe the function is never called, and therefore erroring out now would be a regression 1863 } 1864 } 1865 } 1866 if ( installLazyHandler ) { 1867 uint32_t rel32 = dyldHandler - (((uint32_t)entry)+5); 1868 entry[0] = 0xE8; // CALL rel32 1869 entry[1] = rel32 & 0xFF; 1870 entry[2] = (rel32 >> 8) & 0xFF; 1871 entry[3] = (rel32 >> 16) & 0xFF; 1872 entry[4] = (rel32 >> 24) & 0xFF; 1873 } 1874 } 1875 } 1876 } 1877 } 1878 } 1879 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1880 } 1881 } 1882} 1883#endif // __i386__ 1884 1885 1886void ImageLoaderMachOClassic::doBind(const LinkContext& context, bool forceLazysBound) 1887{ 1888 CRSetCrashLogMessage2(this->getPath()); 1889#if __i386__ 1890 this->initializeLazyStubs(context); 1891#endif 1892 1893 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 1894 // note: flat-namespace binaries need to have imports rebound (even if correctly prebound) 1895 if ( this->usablePrebinding(context) ) { 1896 // binding already up to date 1897 } 1898 else { 1899 // no valid prebinding, so bind symbols. 1900 // values bound by name are stored two different ways in classic mach-o: 1901 1902 #if TEXT_RELOC_SUPPORT 1903 // if there are __TEXT fixups, temporarily make __TEXT writable 1904 if ( fTextSegmentBinds ) 1905 this->makeTextSegmentWritable(context, true); 1906 #endif 1907 1908 // 1) external relocations are used for data initialized to external symbols 1909 this->doBindExternalRelocations(context); 1910 1911 // 2) "indirect symbols" are used for code references to external symbols 1912 // if this image is in the shared cache, there is no way to reset the lazy pointers, so bind them now 1913 this->bindIndirectSymbolPointers(context, true, forceLazysBound || fInSharedCache); 1914 1915 #if TEXT_RELOC_SUPPORT 1916 // if there were __TEXT fixups, restore write protection 1917 if ( fTextSegmentBinds ) 1918 this->makeTextSegmentWritable(context, false); 1919 #endif 1920 } 1921 1922 // set up dyld entry points in image 1923 this->setupLazyPointerHandler(context); 1924 1925 CRSetCrashLogMessage2(NULL); 1926} 1927 1928void ImageLoaderMachOClassic::doBindJustLazies(const LinkContext& context) 1929{ 1930 // some API called requested that all lazy pointers in this image be force bound 1931 this->bindIndirectSymbolPointers(context, false, true); 1932} 1933 1934void ImageLoaderMachOClassic::doInterpose(const LinkContext& context) 1935{ 1936 if ( context.verboseInterposing ) 1937 dyld::log("dyld: interposing %lu tuples onto: %s\n", fgInterposingTuples.size(), this->getPath()); 1938 1939 // scan indirect symbols 1940 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1941 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1942 const struct load_command* cmd = cmds; 1943 for (uint32_t i = 0; i < cmd_count; ++i) { 1944 switch (cmd->cmd) { 1945 case LC_SEGMENT_COMMAND: 1946 { 1947 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1948 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1949 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1950 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1951 const uint8_t type = sect->flags & SECTION_TYPE; 1952 if ( (type == S_NON_LAZY_SYMBOL_POINTERS) || (type == S_LAZY_SYMBOL_POINTERS) ) { 1953 const uint32_t pointerCount = sect->size / sizeof(uintptr_t); 1954 uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + fSlide); 1955 for (uint32_t pointerIndex=0; pointerIndex < pointerCount; ++pointerIndex) { 1956 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) { 1957 // replace all references to 'replacee' with 'replacement' 1958 if ( (symbolPointers[pointerIndex] == it->replacee) && (this != it->replacementImage) ) { 1959 if ( context.verboseInterposing ) { 1960 dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 1961 &symbolPointers[pointerIndex], it->replacee, it->replacement, this->getPath()); 1962 } 1963 symbolPointers[pointerIndex] = it->replacement; 1964 } 1965 } 1966 } 1967 } 1968 #if __i386__ 1969 // i386 has special self-modifying stubs that might be prebound to "JMP rel32" that need checking 1970 else if ( (type == S_SYMBOL_STUBS) && ((sect->flags & S_ATTR_SELF_MODIFYING_CODE) != 0) && (sect->reserved2 == 5) ) { 1971 // check each jmp entry in this section 1972 uint8_t* start = (uint8_t*)(sect->addr + this->fSlide); 1973 uint8_t* end = start + sect->size; 1974 for (uint8_t* entry = start; entry < end; entry += 5) { 1975 if ( entry[0] == 0xE9 ) { // 0xE9 == JMP 1976 uint32_t rel32 = *((uint32_t*)&entry[1]); // assume unaligned load of uint32_t is ok 1977 uint32_t target = (uint32_t)&entry[5] + rel32; 1978 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) { 1979 // replace all references to 'replacee' with 'replacement' 1980 if ( (it->replacee == target) && (this != it->replacementImage) ) { 1981 if ( context.verboseInterposing ) { 1982 dyld::log("dyld: interposing: at %p replace JMP 0x%lX with JMP 0x%lX in %s\n", 1983 &entry[1], it->replacee, it->replacement, this->getPath()); 1984 } 1985 uint32_t newRel32 = it->replacement - (uint32_t)&entry[5]; 1986 *((uint32_t*)&entry[1]) = newRel32; // assume unaligned store of uint32_t is ok 1987 } 1988 } 1989 } 1990 } 1991 } 1992 #endif 1993 } 1994 } 1995 break; 1996 } 1997 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1998 } 1999 2000 // scan external relocations 2001 const uintptr_t relocBase = this->getRelocBase(); 2002 const relocation_info* const relocsStart = (struct relocation_info*)(&fLinkEditBase[fDynamicInfo->extreloff]); 2003 const relocation_info* const relocsEnd = &relocsStart[fDynamicInfo->nextrel]; 2004 for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { 2005 if (reloc->r_length == RELOC_SIZE) { 2006 switch(reloc->r_type) { 2007 case POINTER_RELOC: 2008 { 2009 uintptr_t* location = ((uintptr_t*)(reloc->r_address + relocBase)); 2010 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) { 2011 // replace all references to 'replacee' with 'replacement' 2012 if ( (*location == it->replacee) && (this != it->replacementImage) ) { 2013 if ( context.verboseInterposing ) { 2014 dyld::log("dyld: interposing: at %p replace 0x%lX with 0x%lX in %s\n", 2015 location, it->replacee, it->replacement, this->getPath()); 2016 } 2017 *location = it->replacement; 2018 } 2019 } 2020 } 2021 break; 2022 } 2023 } 2024 } 2025} 2026 2027 2028const char* ImageLoaderMachOClassic::findClosestSymbol(const void* addr, const void** closestAddr) const 2029{ 2030 uintptr_t targetAddress = (uintptr_t)addr - fSlide; 2031 const struct macho_nlist* bestSymbol = NULL; 2032 // first walk all global symbols 2033 const struct macho_nlist* const globalsStart = &fSymbolTable[fDynamicInfo->iextdefsym]; 2034 const struct macho_nlist* const globalsEnd= &globalsStart[fDynamicInfo->nextdefsym]; 2035 for (const struct macho_nlist* s = globalsStart; s < globalsEnd; ++s) { 2036 if ( (s->n_type & N_TYPE) == N_SECT ) { 2037 if ( bestSymbol == NULL ) { 2038 if ( s->n_value <= targetAddress ) 2039 bestSymbol = s; 2040 } 2041 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) { 2042 bestSymbol = s; 2043 } 2044 } 2045 } 2046 // next walk all local symbols 2047 const struct macho_nlist* const localsStart = &fSymbolTable[fDynamicInfo->ilocalsym]; 2048 const struct macho_nlist* const localsEnd= &localsStart[fDynamicInfo->nlocalsym]; 2049 for (const struct macho_nlist* s = localsStart; s < localsEnd; ++s) { 2050 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) { 2051 if ( bestSymbol == NULL ) { 2052 if ( s->n_value <= targetAddress ) 2053 bestSymbol = s; 2054 } 2055 else if ( (s->n_value <= targetAddress) && (bestSymbol->n_value < s->n_value) ) { 2056 bestSymbol = s; 2057 } 2058 } 2059 } 2060 if ( bestSymbol != NULL ) { 2061#if __arm__ 2062 if (bestSymbol->n_desc & N_ARM_THUMB_DEF) 2063 *closestAddr = (void*)((bestSymbol->n_value | 1) + fSlide); 2064 else 2065 *closestAddr = (void*)(bestSymbol->n_value + fSlide); 2066#else 2067 *closestAddr = (void*)(bestSymbol->n_value + fSlide); 2068#endif 2069 return &fStrings[bestSymbol->n_un.n_strx]; 2070 } 2071 return NULL; 2072} 2073 2074 2075