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#define __STDC_LIMIT_MACROS 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/nlist.h> 42#include <sys/sysctl.h> 43#include <sys/syscall.h> 44#include <libkern/OSAtomic.h> 45#include <libkern/OSCacheControl.h> 46#include <stdint.h> 47#include <System/sys/codesign.h> 48 49#include "ImageLoaderMachO.h" 50#include "ImageLoaderMachOCompressed.h" 51#if SUPPORT_CLASSIC_MACHO 52#include "ImageLoaderMachOClassic.h" 53#endif 54#include "mach-o/dyld_images.h" 55 56// <rdar://problem/8718137> use stack guard random value to add padding between dylibs 57extern "C" long __stack_chk_guard; 58 59#ifndef LC_LOAD_UPWARD_DYLIB 60 #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */ 61#endif 62 63// relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables 64#if __LP64__ 65 #define LC_SEGMENT_COMMAND LC_SEGMENT_64 66 #define LC_ROUTINES_COMMAND LC_ROUTINES_64 67 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT 68 struct macho_segment_command : public segment_command_64 {}; 69 struct macho_section : public section_64 {}; 70 struct macho_routines_command : public routines_command_64 {}; 71#else 72 #define LC_SEGMENT_COMMAND LC_SEGMENT 73 #define LC_ROUTINES_COMMAND LC_ROUTINES 74 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64 75 struct macho_segment_command : public segment_command {}; 76 struct macho_section : public section {}; 77 struct macho_routines_command : public routines_command {}; 78#endif 79 80uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs = 0; 81uint32_t ImageLoaderMachO::fgSymbolTrieSearchs = 0; 82 83 84ImageLoaderMachO::ImageLoaderMachO(const macho_header* mh, const char* path, unsigned int segCount, 85 uint32_t segOffsets[], unsigned int libCount) 86 : ImageLoader(path, libCount), fMachOData((uint8_t*)mh), fLinkEditBase(NULL), fSlide(0), 87 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0), 88 fSegmentsCount(segCount), fIsSplitSeg(false), fInSharedCache(false), 89#if TEXT_RELOC_SUPPORT 90 fTextSegmentRebases(false), 91 fTextSegmentBinds(false), 92#endif 93#if __i386__ 94 fReadOnlyImportSegment(false), 95#endif 96 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false), 97 fHasInitializers(false), fHasTerminators(false), fRegisteredAsRequiresCoalescing(false) 98{ 99 fIsSplitSeg = ((mh->flags & MH_SPLIT_SEGS) != 0); 100 101 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put 102 // each SegmentMachO object in array at end of ImageLoaderMachO object 103 const uint32_t cmd_count = mh->ncmds; 104 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 105 const struct load_command* cmd = cmds; 106 for (uint32_t i = 0, segIndex=0; i < cmd_count; ++i) { 107 if ( cmd->cmd == LC_SEGMENT_COMMAND ) { 108 const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd; 109 // ignore zero-sized segments 110 if ( segCmd->vmsize != 0 ) { 111 // record offset of load command 112 segOffsets[segIndex++] = (uint8_t*)segCmd - fMachOData; 113 } 114 } 115 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 116 } 117 118} 119 120 121// determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has 122void ImageLoaderMachO::sniffLoadCommands(const macho_header* mh, const char* path, bool* compressed, 123 unsigned int* segCount, unsigned int* libCount, const LinkContext& context, 124 const linkedit_data_command** codeSigCmd) 125{ 126 *compressed = false; 127 *segCount = 0; 128 *libCount = 0; 129 *codeSigCmd = NULL; 130 struct macho_segment_command* segCmd; 131 bool foundLoadCommandSegment = false; 132 uint32_t loadCommandSegmentIndex = 0xFFFFFFFF; 133 uintptr_t loadCommandSegmentVMStart = 0; 134 uintptr_t loadCommandSegmentVMEnd = 0; 135 136 const uint32_t cmd_count = mh->ncmds; 137 const struct load_command* const startCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header)); 138 const struct load_command* const endCmds = (struct load_command*)(((uint8_t*)mh) + sizeof(macho_header) + mh->sizeofcmds); 139 const struct load_command* cmd = startCmds; 140 for (uint32_t i = 0; i < cmd_count; ++i) { 141 switch (cmd->cmd) { 142 case LC_DYLD_INFO: 143 case LC_DYLD_INFO_ONLY: 144 *compressed = true; 145 break; 146 case LC_SEGMENT_COMMAND: 147 segCmd = (struct macho_segment_command*)cmd; 148 // ignore zero-sized segments 149 if ( segCmd->vmsize != 0 ) 150 *segCount += 1; 151 // <rdar://problem/7942521> all load commands must be in an executable segment 152 if ( context.codeSigningEnforced && (segCmd->fileoff < mh->sizeofcmds) && (segCmd->filesize != 0) ) { 153 if ( (segCmd->fileoff != 0) || (segCmd->filesize < (mh->sizeofcmds+sizeof(macho_header))) ) 154 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd->segname); 155 if ( segCmd->initprot != (VM_PROT_READ | VM_PROT_EXECUTE) ) 156 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd->segname); 157 if ( foundLoadCommandSegment ) 158 throw "load commands in multiple segments"; 159 foundLoadCommandSegment = true; 160 loadCommandSegmentIndex = i; 161 loadCommandSegmentVMStart = segCmd->vmaddr; 162 loadCommandSegmentVMEnd = segCmd->vmaddr + segCmd->vmsize; 163 } 164 break; 165 case LC_SEGMENT_COMMAND_WRONG: 166 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture"); 167 break; 168 case LC_LOAD_DYLIB: 169 case LC_LOAD_WEAK_DYLIB: 170 case LC_REEXPORT_DYLIB: 171 case LC_LOAD_UPWARD_DYLIB: 172 *libCount += 1; 173 break; 174 case LC_CODE_SIGNATURE: 175 *codeSigCmd = (struct linkedit_data_command*)cmd; // only support one LC_CODE_SIGNATURE per image 176 break; 177 } 178 uint32_t cmdLength = cmd->cmdsize; 179 cmd = (const struct load_command*)(((char*)cmd)+cmdLength); 180 if ( (cmd > endCmds) || (cmd < startCmds) ) { 181 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s", 182 i, cmdLength, mh->sizeofcmds, path); 183 } 184 } 185 186 if ( context.codeSigningEnforced && !foundLoadCommandSegment ) 187 throw "load commands not in a segment"; 188 // <rdar://problem/13145644> verify another segment does not over-map load commands 189 cmd = startCmds; 190 if ( context.codeSigningEnforced ) { 191 for (uint32_t i = 0; i < cmd_count; ++i) { 192 switch (cmd->cmd) { 193 case LC_SEGMENT_COMMAND: 194 if ( i != loadCommandSegmentIndex ) { 195 segCmd = (struct macho_segment_command*)cmd; 196 uintptr_t start = segCmd->vmaddr; 197 uintptr_t end = segCmd->vmaddr + segCmd->vmsize; 198 if ( ((start <= loadCommandSegmentVMStart) && (end > loadCommandSegmentVMStart)) 199 || ((start >= loadCommandSegmentVMStart) && (start < loadCommandSegmentVMEnd)) ) 200 dyld::throwf("malformed mach-o image: segment %s overlaps load commands", segCmd->segname); 201 } 202 break; 203 } 204 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 205 } 206 } 207 208 // fSegmentsArrayCount is only 8-bits 209 if ( *segCount > 255 ) 210 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path); 211 212 // fSegmentsArrayCount is only 8-bits 213 if ( *libCount > 4095 ) 214 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path); 215 216 if ( needsAddedLibSystemDepency(*libCount, mh) ) 217 *libCount = 1; 218} 219 220 221 222// create image for main executable 223ImageLoader* ImageLoaderMachO::instantiateMainExecutable(const macho_header* mh, uintptr_t slide, const char* path, const LinkContext& context) 224{ 225 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n", 226 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed)); 227 bool compressed; 228 unsigned int segCount; 229 unsigned int libCount; 230 const linkedit_data_command* codeSigCmd; 231 sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, context, &codeSigCmd); 232 // instantiate concrete class based on content of load commands 233 if ( compressed ) 234 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh, slide, path, segCount, libCount, context); 235 else 236#if SUPPORT_CLASSIC_MACHO 237 return ImageLoaderMachOClassic::instantiateMainExecutable(mh, slide, path, segCount, libCount, context); 238#else 239 throw "missing LC_DYLD_INFO load command"; 240#endif 241} 242 243 244// create image by mapping in a mach-o file 245ImageLoader* ImageLoaderMachO::instantiateFromFile(const char* path, int fd, const uint8_t firstPage[4096], uint64_t offsetInFat, 246 uint64_t lenInFat, const struct stat& info, const LinkContext& context) 247{ 248 // get load commands 249 const unsigned int dataSize = sizeof(macho_header) + ((macho_header*)firstPage)->sizeofcmds; 250 uint8_t buffer[dataSize]; 251 const uint8_t* fileData = firstPage; 252 if ( dataSize > 4096 ) { 253 // only read more if cmds take up more space than first page 254 fileData = buffer; 255 memcpy(buffer, firstPage, 4096); 256 pread(fd, &buffer[4096], dataSize-4096, offsetInFat+4096); 257 } 258 259 bool compressed; 260 unsigned int segCount; 261 unsigned int libCount; 262 const linkedit_data_command* codeSigCmd; 263 sniffLoadCommands((const macho_header*)fileData, path, &compressed, &segCount, &libCount, context, &codeSigCmd); 264 // instantiate concrete class based on content of load commands 265 if ( compressed ) 266 return ImageLoaderMachOCompressed::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context); 267 else 268#if SUPPORT_CLASSIC_MACHO 269 return ImageLoaderMachOClassic::instantiateFromFile(path, fd, fileData, offsetInFat, lenInFat, info, segCount, libCount, codeSigCmd, context); 270#else 271 throw "missing LC_DYLD_INFO load command"; 272#endif 273} 274 275// create image by using cached mach-o file 276ImageLoader* ImageLoaderMachO::instantiateFromCache(const macho_header* mh, const char* path, long slide, const struct stat& info, const LinkContext& context) 277{ 278 // instantiate right concrete class 279 bool compressed; 280 unsigned int segCount; 281 unsigned int libCount; 282 const linkedit_data_command* codeSigCmd; 283 sniffLoadCommands(mh, path, &compressed, &segCount, &libCount, context, &codeSigCmd); 284 // instantiate concrete class based on content of load commands 285 if ( compressed ) 286 return ImageLoaderMachOCompressed::instantiateFromCache(mh, path, slide, info, segCount, libCount, context); 287 else 288#if SUPPORT_CLASSIC_MACHO 289 return ImageLoaderMachOClassic::instantiateFromCache(mh, path, slide, info, segCount, libCount, context); 290#else 291 throw "missing LC_DYLD_INFO load command"; 292#endif 293} 294 295// create image by copying an in-memory mach-o file 296ImageLoader* ImageLoaderMachO::instantiateFromMemory(const char* moduleName, const macho_header* mh, uint64_t len, const LinkContext& context) 297{ 298 bool compressed; 299 unsigned int segCount; 300 unsigned int libCount; 301 const linkedit_data_command* sigcmd; 302 sniffLoadCommands(mh, moduleName, &compressed, &segCount, &libCount, context, &sigcmd); 303 // instantiate concrete class based on content of load commands 304 if ( compressed ) 305 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context); 306 else 307#if SUPPORT_CLASSIC_MACHO 308 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName, mh, len, segCount, libCount, context); 309#else 310 throw "missing LC_DYLD_INFO load command"; 311#endif 312} 313 314 315int ImageLoaderMachO::crashIfInvalidCodeSignature() 316{ 317 // Now that segments are mapped in, try reading from first executable segment. 318 // If code signing is enabled the kernel will validate the code signature 319 // when paging in, and kill the process if invalid. 320 for(unsigned int i=0; i < fSegmentsCount; ++i) { 321 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) { 322 // return read value to ensure compiler does not optimize away load 323 int* p = (int*)segActualLoadAddress(i); 324 return *p; 325 } 326 } 327 return 0; 328} 329 330 331void ImageLoaderMachO::parseLoadCmds() 332{ 333 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide 334 for(unsigned int i=0; i < fSegmentsCount; ++i) { 335 // set up pointer to __LINKEDIT segment 336 if ( strcmp(segName(i),"__LINKEDIT") == 0 ) 337 fLinkEditBase = (uint8_t*)(segActualLoadAddress(i) - segFileOffset(i)); 338#if TEXT_RELOC_SUPPORT 339 // __TEXT segment always starts at beginning of file and contains mach_header and load commands 340 if ( strcmp(segName(i),"__TEXT") == 0 ) { 341 if ( segHasRebaseFixUps(i) && (fSlide != 0) ) 342 fTextSegmentRebases = true; 343 if ( segHasBindFixUps(i) ) 344 fTextSegmentBinds = true; 345 } 346#endif 347#if __i386__ 348 if ( segIsReadOnlyImport(i) ) 349 fReadOnlyImportSegment = true; 350#endif 351 // some segment always starts at beginning of file and contains mach_header and load commands 352 if ( (segFileOffset(i) == 0) && (segFileSize(i) != 0) ) { 353 fMachOData = (uint8_t*)(segActualLoadAddress(i)); 354 } 355 } 356 357 // keep count of prebound images with weak exports 358 if ( this->participatesInCoalescing() ) { 359 ++fgImagesRequiringCoalescing; 360 fRegisteredAsRequiresCoalescing = true; 361 if ( this->hasCoalescedExports() ) 362 ++fgImagesHasWeakDefinitions; 363 } 364 365 // keep count of images used in shared cache 366 if ( fInSharedCache ) 367 ++fgImagesUsedFromSharedCache; 368 369 // walk load commands (mapped in at start of __TEXT segment) 370 const dyld_info_command* dyldInfo = NULL; 371 const macho_nlist* symbolTable = NULL; 372 const char* symbolTableStrings = NULL; 373 const struct load_command* firstUnknownCmd = NULL; 374 const struct version_min_command* minOSVersionCmd = NULL; 375 const dysymtab_command* dynSymbolTable = NULL; 376 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 377 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 378 const struct load_command* cmd = cmds; 379 for (uint32_t i = 0; i < cmd_count; ++i) { 380 switch (cmd->cmd) { 381 case LC_SYMTAB: 382 { 383 const struct symtab_command* symtab = (struct symtab_command*)cmd; 384 symbolTableStrings = (const char*)&fLinkEditBase[symtab->stroff]; 385 symbolTable = (macho_nlist*)(&fLinkEditBase[symtab->symoff]); 386 } 387 break; 388 case LC_DYSYMTAB: 389 dynSymbolTable = (struct dysymtab_command*)cmd; 390 break; 391 case LC_SUB_UMBRELLA: 392 fHasSubUmbrella = true; 393 break; 394 case LC_SUB_FRAMEWORK: 395 fInUmbrella = true; 396 break; 397 case LC_SUB_LIBRARY: 398 fHasSubLibraries = true; 399 break; 400 case LC_ROUTINES_COMMAND: 401 fHasDashInit = true; 402 break; 403 case LC_DYLD_INFO: 404 case LC_DYLD_INFO_ONLY: 405 dyldInfo = (struct dyld_info_command*)cmd; 406 break; 407 case LC_SEGMENT_COMMAND: 408 { 409 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 410 const bool isTextSeg = (strcmp(seg->segname, "__TEXT") == 0); 411 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 412 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 413 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 414 const uint8_t type = sect->flags & SECTION_TYPE; 415 if ( type == S_MOD_INIT_FUNC_POINTERS ) 416 fHasInitializers = true; 417 else if ( type == S_MOD_TERM_FUNC_POINTERS ) 418 fHasTerminators = true; 419 else if ( type == S_DTRACE_DOF ) 420 fHasDOFSections = true; 421 else if ( isTextSeg && (strcmp(sect->sectname, "__eh_frame") == 0) ) 422 fEHFrameSectionOffset = (uint8_t*)sect - fMachOData; 423 else if ( isTextSeg && (strcmp(sect->sectname, "__unwind_info") == 0) ) 424 fUnwindInfoSectionOffset = (uint8_t*)sect - fMachOData;; 425 } 426 } 427 break; 428 case LC_TWOLEVEL_HINTS: 429 // no longer supported 430 break; 431 case LC_ID_DYLIB: 432 { 433 fDylibIDOffset = (uint8_t*)cmd - fMachOData; 434 } 435 break; 436 case LC_RPATH: 437 case LC_LOAD_WEAK_DYLIB: 438 case LC_REEXPORT_DYLIB: 439 case LC_LOAD_UPWARD_DYLIB: 440 case LC_MAIN: 441 // do nothing, just prevent LC_REQ_DYLD exception from occuring 442 break; 443 case LC_VERSION_MIN_MACOSX: 444 case LC_VERSION_MIN_IPHONEOS: 445 minOSVersionCmd = (version_min_command*)cmd; 446 break; 447 default: 448 if ( (cmd->cmd & LC_REQ_DYLD) != 0 ) { 449 if ( firstUnknownCmd == NULL ) 450 firstUnknownCmd = cmd; 451 } 452 break; 453 } 454 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 455 } 456 if ( firstUnknownCmd != NULL ) { 457 if ( minOSVersionCmd != NULL ) { 458 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)", 459 this->getShortName(), 460 minOSVersionCmd->version >> 16, ((minOSVersionCmd->version >> 8) & 0xff), 461 firstUnknownCmd->cmd); 462 } 463 else { 464 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd->cmd); 465 } 466 } 467 468 469 if ( dyldInfo != NULL ) 470 this->setDyldInfo(dyldInfo); 471 if ( symbolTable != NULL) 472 this->setSymbolTableInfo(symbolTable, symbolTableStrings, dynSymbolTable); 473 474} 475 476// don't do this work in destructor because we need object to be full subclass 477// for UnmapSegments() to work 478void ImageLoaderMachO::destroy() 479{ 480 // update count of images with weak exports 481 if ( fRegisteredAsRequiresCoalescing ) { 482 --fgImagesRequiringCoalescing; 483 if ( this->hasCoalescedExports() ) 484 --fgImagesHasWeakDefinitions; 485 } 486 487 // keep count of images used in shared cache 488 if ( fInSharedCache ) 489 --fgImagesUsedFromSharedCache; 490 491 // unmap image when done 492 UnmapSegments(); 493} 494 495 496unsigned int ImageLoaderMachO::segmentCount() const 497{ 498 return fSegmentsCount; 499} 500 501 502const macho_segment_command* ImageLoaderMachO::segLoadCommand(unsigned int segIndex) const 503{ 504 uint32_t* lcOffsets = this->segmentCommandOffsets(); 505 uint32_t lcOffset = lcOffsets[segIndex]; 506 return (macho_segment_command*)(&fMachOData[lcOffset]); 507} 508 509const char* ImageLoaderMachO::segName(unsigned int segIndex) const 510{ 511 return segLoadCommand(segIndex)->segname; 512} 513 514 515uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex) const 516{ 517 return segLoadCommand(segIndex)->vmsize; 518} 519 520 521uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex) const 522{ 523 return segLoadCommand(segIndex)->filesize; 524} 525 526 527bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex) 528{ 529 return ( segWriteable(segIndex) && (segSize(segIndex) > segFileSize(segIndex)) ); 530} 531 532 533uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex) const 534{ 535 return segLoadCommand(segIndex)->fileoff; 536} 537 538 539bool ImageLoaderMachO::segReadable(unsigned int segIndex) const 540{ 541 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_READ) != 0); 542} 543 544 545bool ImageLoaderMachO::segWriteable(unsigned int segIndex) const 546{ 547 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_WRITE) != 0); 548} 549 550 551bool ImageLoaderMachO::segExecutable(unsigned int segIndex) const 552{ 553 return ( (segLoadCommand(segIndex)->initprot & VM_PROT_EXECUTE) != 0); 554} 555 556 557bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex) const 558{ 559 return (segLoadCommand(segIndex)->initprot == 0); 560} 561 562bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex) const 563{ 564 return (segLoadCommand(segIndex)->vmaddr != 0); 565} 566 567uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex) const 568{ 569 return segLoadCommand(segIndex)->vmaddr; 570} 571 572uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex) const 573{ 574 return segLoadCommand(segIndex)->vmaddr + fSlide; 575} 576 577 578uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex) const 579{ 580 return segActualLoadAddress(segIndex) + segSize(segIndex); 581} 582 583bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex) const 584{ 585 // scan sections for fix-up bit 586 const macho_segment_command* segCmd = segLoadCommand(segIndex); 587 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command)); 588 const struct macho_section* const sectionsEnd = §ionsStart[segCmd->nsects]; 589 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 590 if ( (sect->flags & S_ATTR_LOC_RELOC) != 0 ) 591 return true; 592 } 593 return false; 594} 595 596bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex) const 597{ 598 // scan sections for fix-up bit 599 const macho_segment_command* segCmd = segLoadCommand(segIndex); 600 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)segCmd + sizeof(struct macho_segment_command)); 601 const struct macho_section* const sectionsEnd = §ionsStart[segCmd->nsects]; 602 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 603 if ( (sect->flags & S_ATTR_EXT_RELOC) != 0 ) 604 return true; 605 } 606 return false; 607} 608 609#if __i386__ 610bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex) const 611{ 612 const macho_segment_command* segCmd = segLoadCommand(segIndex); 613 return ( (segCmd->initprot & VM_PROT_EXECUTE) 614 && ((segCmd->initprot & VM_PROT_WRITE) == 0) 615 && (strcmp(segCmd->segname, "__IMPORT") == 0) ); 616} 617#endif 618 619 620void ImageLoaderMachO::UnmapSegments() 621{ 622 // usually unmap image when done 623 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped) ) { 624 // unmap TEXT segment last because it contains load command being inspected 625 unsigned int textSegmentIndex = 0; 626 for(unsigned int i=0; i < fSegmentsCount; ++i) { 627 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this)); 628 if ( strcmp(segName(i), "__TEXT") == 0 ) { 629 textSegmentIndex = i; 630 } 631 else { 632 // update stats 633 --ImageLoader::fgTotalSegmentsMapped; 634 ImageLoader::fgTotalBytesMapped -= segSize(i); 635 munmap((void*)segActualLoadAddress(i), segSize(i)); 636 } 637 } 638 // now unmap TEXT 639 --ImageLoader::fgTotalSegmentsMapped; 640 ImageLoader::fgTotalBytesMapped -= segSize(textSegmentIndex); 641 munmap((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex)); 642 } 643} 644 645 646// prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code 647void ImageLoaderMachO::preFetchDATA(int fd, uint64_t offsetInFat, const LinkContext& context) 648{ 649 if ( context.linkingMainExecutable ) { 650 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 651 if ( segWriteable(i) && (segFileSize(i) > 0) ) { 652 // prefetch writable segment that have mmap'ed regions 653 radvisory advice; 654 advice.ra_offset = offsetInFat + segFileOffset(i); 655 advice.ra_count = segFileSize(i); 656 // limit prefetch to 1MB (256 pages) 657 if ( advice.ra_count > 1024*1024 ) 658 advice.ra_count = 1024*1024; 659 // don't prefetch single pages, let them fault in 660 fgTotalBytesPreFetched += advice.ra_count; 661 fcntl(fd, F_RDADVISE, &advice); 662 if ( context.verboseMapping ) { 663 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n", 664 segName(i), segActualLoadAddress(i), segActualLoadAddress(i)+advice.ra_count-1); 665 } 666 } 667 } 668 } 669} 670 671 672bool ImageLoaderMachO::segmentsMustSlideTogether() const 673{ 674 return true; 675} 676 677bool ImageLoaderMachO::segmentsCanSlide() const 678{ 679 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable()); 680} 681 682bool ImageLoaderMachO::isBundle() const 683{ 684 const macho_header* mh = (macho_header*)fMachOData; 685 return ( mh->filetype == MH_BUNDLE ); 686} 687 688bool ImageLoaderMachO::isDylib() const 689{ 690 const macho_header* mh = (macho_header*)fMachOData; 691 return ( mh->filetype == MH_DYLIB ); 692} 693 694bool ImageLoaderMachO::isExecutable() const 695{ 696 const macho_header* mh = (macho_header*)fMachOData; 697 return ( mh->filetype == MH_EXECUTE ); 698} 699 700bool ImageLoaderMachO::isPositionIndependentExecutable() const 701{ 702 const macho_header* mh = (macho_header*)fMachOData; 703 return ( (mh->filetype == MH_EXECUTE) && ((mh->flags & MH_PIE) != 0) ); 704} 705 706 707bool ImageLoaderMachO::forceFlat() const 708{ 709 const macho_header* mh = (macho_header*)fMachOData; 710 return ( (mh->flags & MH_FORCE_FLAT) != 0 ); 711} 712 713bool ImageLoaderMachO::usesTwoLevelNameSpace() const 714{ 715 const macho_header* mh = (macho_header*)fMachOData; 716 return ( (mh->flags & MH_TWOLEVEL) != 0 ); 717} 718 719bool ImageLoaderMachO::isPrebindable() const 720{ 721 const macho_header* mh = (macho_header*)fMachOData; 722 return ( (mh->flags & MH_PREBOUND) != 0 ); 723} 724 725bool ImageLoaderMachO::hasCoalescedExports() const 726{ 727 const macho_header* mh = (macho_header*)fMachOData; 728 return ( (mh->flags & MH_WEAK_DEFINES) != 0 ); 729} 730 731bool ImageLoaderMachO::hasReferencesToWeakSymbols() const 732{ 733 const macho_header* mh = (macho_header*)fMachOData; 734 return ( (mh->flags & MH_BINDS_TO_WEAK) != 0 ); 735} 736 737bool ImageLoaderMachO::participatesInCoalescing() const 738{ 739 const macho_header* mh = (macho_header*)fMachOData; 740 // if image is loaded with RTLD_LOCAL, then its symbols' visibility 741 // is reduced and it can't coalesce with other images 742 if ( this->hasHiddenExports() ) 743 return false; 744 return ( (mh->flags & (MH_WEAK_DEFINES|MH_BINDS_TO_WEAK)) != 0 ); 745} 746 747 748 749void ImageLoaderMachO::setSlide(intptr_t slide) 750{ 751 fSlide = slide; 752} 753 754void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command* codeSigCmd, int fd, uint64_t offsetInFatFile, const LinkContext& context) 755{ 756 // if dylib being loaded has no code signature load command 757 if ( codeSigCmd == NULL ) { 758#if __MAC_OS_X_VERSION_MIN_REQUIRED 759 bool codeSigningEnforced = context.codeSigningEnforced; 760 if ( context.mainExecutableCodeSigned && !codeSigningEnforced ) { 761 static bool codeSignEnforcementDynamicallyEnabled = false; 762 if ( !codeSignEnforcementDynamicallyEnabled ) { 763 uint32_t flags; 764 if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) { 765 if ( flags & CS_ENFORCEMENT ) { 766 codeSignEnforcementDynamicallyEnabled = true; 767 } 768 } 769 } 770 codeSigningEnforced = codeSignEnforcementDynamicallyEnabled; 771 } 772 // if we require dylibs to be code signed 773 if ( codeSigningEnforced ) { 774 // if there is a non-load command based code signature, use it 775 off_t offset = (off_t)offsetInFatFile; 776 if ( fcntl(fd, F_FINDSIGS, &offset, sizeof(offset)) != -1 ) 777 return; 778 // otherwise gracefully return from dlopen() 779 dyld::throwf("required code signature missing for '%s'\n", this->getPath()); 780 } 781#endif 782 } 783 else { 784#if __MAC_OS_X_VERSION_MIN_REQUIRED 785 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools 786 if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9 ) { 787 return; 788 } 789#endif 790 fsignatures_t siginfo; 791 siginfo.fs_file_start=offsetInFatFile; // start of mach-o slice in fat file 792 siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff); // start of CD in mach-o file 793 siginfo.fs_blob_size=codeSigCmd->datasize; // size of CD 794 int result = fcntl(fd, F_ADDFILESIGS, &siginfo); 795 if ( result == -1 ) { 796 if ( (errno == EPERM) || (errno == EBADEXEC) ) 797 dyld::throwf("code signature invalid for '%s'\n", this->getPath()); 798 if ( context.verboseCodeSignatures ) 799 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno); 800 else 801 dyld::log("dyld: Registered code signature for %s\n", this->getPath()); 802 } 803 } 804} 805 806 807const char* ImageLoaderMachO::getInstallPath() const 808{ 809 if ( fDylibIDOffset != 0 ) { 810 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]); 811 return (char*)dylibID + dylibID->dylib.name.offset; 812 } 813 return NULL; 814} 815 816void ImageLoaderMachO::registerInterposing() 817{ 818 // mach-o files advertise interposing by having a __DATA __interpose section 819 struct InterposeData { uintptr_t replacement; uintptr_t replacee; }; 820 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 821 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 822 const struct load_command* cmd = cmds; 823 for (uint32_t i = 0; i < cmd_count; ++i) { 824 switch (cmd->cmd) { 825 case LC_SEGMENT_COMMAND: 826 { 827 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 828 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 829 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 830 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 831 if ( ((sect->flags & SECTION_TYPE) == S_INTERPOSING) || ((strcmp(sect->sectname, "__interpose") == 0) && (strcmp(seg->segname, "__DATA") == 0)) ) { 832 const InterposeData* interposeArray = (InterposeData*)(sect->addr + fSlide); 833 const unsigned int count = sect->size / sizeof(InterposeData); 834 for (uint32_t i=0; i < count; ++i) { 835 ImageLoader::InterposeTuple tuple; 836 tuple.replacement = interposeArray[i].replacement; 837 tuple.replacementImage = this; 838 tuple.replacee = interposeArray[i].replacee; 839 // <rdar://problem/7937695> verify that replacement is in this image 840 if ( this->containsAddress((void*)tuple.replacement) ) { 841 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) { 842 if ( it->replacee == tuple.replacee ) { 843 tuple.replacee = it->replacement; 844 } 845 } 846 ImageLoader::fgInterposingTuples.push_back(tuple); 847 } 848 } 849 } 850 } 851 } 852 break; 853 } 854 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 855 } 856} 857 858uint32_t ImageLoaderMachO::sdkVersion() const 859{ 860 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 861 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 862 const struct load_command* cmd = cmds; 863 const struct version_min_command* versCmd; 864 for (uint32_t i = 0; i < cmd_count; ++i) { 865 switch ( cmd->cmd ) { 866 case LC_VERSION_MIN_MACOSX: 867 case LC_VERSION_MIN_IPHONEOS: 868 versCmd = (version_min_command*)cmd; 869 return versCmd->sdk; 870 } 871 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 872 } 873 return 0; 874} 875 876void* ImageLoaderMachO::getThreadPC() const 877{ 878 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 879 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 880 const struct load_command* cmd = cmds; 881 for (uint32_t i = 0; i < cmd_count; ++i) { 882 if ( cmd->cmd == LC_MAIN ) { 883 entry_point_command* mainCmd = (entry_point_command*)cmd; 884 void* entry = (void*)(mainCmd->entryoff + (char*)fMachOData); 885 // <rdar://problem/8543820&9228031> verify entry point is in image 886 if ( this->containsAddress(entry) ) 887 return entry; 888 else 889 throw "LC_MAIN entryoff is out of range"; 890 } 891 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 892 } 893 return NULL; 894} 895 896 897void* ImageLoaderMachO::getMain() const 898{ 899 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 900 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 901 const struct load_command* cmd = cmds; 902 for (uint32_t i = 0; i < cmd_count; ++i) { 903 switch (cmd->cmd) { 904 case LC_UNIXTHREAD: 905 { 906 #if __i386__ 907 const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16); 908 void* entry = (void*)(registers->eip + fSlide); 909 #elif __x86_64__ 910 const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16); 911 void* entry = (void*)(registers->rip + fSlide); 912 #elif __arm__ 913 const arm_thread_state_t* registers = (arm_thread_state_t*)(((char*)cmd) + 16); 914 void* entry = (void*)(registers->__pc + fSlide); 915 #else 916 #warning need processor specific code 917 #endif 918 // <rdar://problem/8543820&9228031> verify entry point is in image 919 if ( this->containsAddress(entry) ) { 920 return entry; 921 } 922 } 923 break; 924 } 925 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 926 } 927 throw "no valid entry point"; 928} 929 930bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount, const macho_header* mh) 931{ 932 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem 933 if ( libCount > 1 ) 934 return false; 935 936 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind 937 if ( mh->filetype == MH_EXECUTE ) 938 return false; 939 940 bool isNonOSdylib = false; 941 const uint32_t cmd_count = mh->ncmds; 942 const struct load_command* const cmds = (struct load_command*)((uint8_t*)mh+sizeof(macho_header)); 943 const struct load_command* cmd = cmds; 944 for (uint32_t i = 0; i < cmd_count; ++i) { 945 switch (cmd->cmd) { 946 case LC_LOAD_DYLIB: 947 case LC_LOAD_WEAK_DYLIB: 948 case LC_REEXPORT_DYLIB: 949 case LC_LOAD_UPWARD_DYLIB: 950 return false; 951 case LC_ID_DYLIB: 952 { 953 const dylib_command* dylibID = (dylib_command*)cmd; 954 const char* installPath = (char*)cmd + dylibID->dylib.name.offset; 955 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents 956 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first 957 // <rdar://problem/6497528> rosetta circular dependency spew 958 isNonOSdylib = ( (strncmp(installPath, "/usr/lib/", 9) != 0) && (strncmp(installPath, "/usr/libexec/oah/Shims", 9) != 0) ); 959 } 960 break; 961 } 962 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 963 } 964 return isNonOSdylib; 965} 966 967 968void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs[]) 969{ 970 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header*)fMachOData) ) { 971 DependentLibraryInfo* lib = &libs[0]; 972 lib->name = "/usr/lib/libSystem.B.dylib"; 973 lib->info.checksum = 0; 974 lib->info.minVersion = 0; 975 lib->info.maxVersion = 0; 976 lib->required = false; 977 lib->reExported = false; 978 lib->upward = false; 979 } 980 else { 981 uint32_t index = 0; 982 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 983 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 984 const struct load_command* cmd = cmds; 985 for (uint32_t i = 0; i < cmd_count; ++i) { 986 switch (cmd->cmd) { 987 case LC_LOAD_DYLIB: 988 case LC_LOAD_WEAK_DYLIB: 989 case LC_REEXPORT_DYLIB: 990 case LC_LOAD_UPWARD_DYLIB: 991 { 992 const struct dylib_command* dylib = (struct dylib_command*)cmd; 993 DependentLibraryInfo* lib = &libs[index++]; 994 lib->name = (char*)cmd + dylib->dylib.name.offset; 995 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset); 996 lib->info.checksum = dylib->dylib.timestamp; 997 lib->info.minVersion = dylib->dylib.compatibility_version; 998 lib->info.maxVersion = dylib->dylib.current_version; 999 lib->required = (cmd->cmd != LC_LOAD_WEAK_DYLIB); 1000 lib->reExported = (cmd->cmd == LC_REEXPORT_DYLIB); 1001 lib->upward = (cmd->cmd == LC_LOAD_UPWARD_DYLIB); 1002 } 1003 break; 1004 } 1005 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1006 } 1007 } 1008} 1009 1010ImageLoader::LibraryInfo ImageLoaderMachO::doGetLibraryInfo() 1011{ 1012 LibraryInfo info; 1013 if ( fDylibIDOffset != 0 ) { 1014 const dylib_command* dylibID = (dylib_command*)(&fMachOData[fDylibIDOffset]); 1015 info.minVersion = dylibID->dylib.compatibility_version; 1016 info.maxVersion = dylibID->dylib.current_version; 1017 info.checksum = dylibID->dylib.timestamp; 1018 } 1019 else { 1020 info.minVersion = 0; 1021 info.maxVersion = 0; 1022 info.checksum = 0; 1023 } 1024 return info; 1025} 1026 1027void ImageLoaderMachO::getRPaths(const LinkContext& context, std::vector<const char*>& paths) const 1028{ 1029 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1030 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1031 const struct load_command* cmd = cmds; 1032 for (uint32_t i = 0; i < cmd_count; ++i) { 1033 switch (cmd->cmd) { 1034 case LC_RPATH: 1035 const char* pathToAdd = NULL; 1036 const char* path = (char*)cmd + ((struct rpath_command*)cmd)->path.offset; 1037 if ( strncmp(path, "@loader_path/", 13) == 0 ) { 1038 if ( context.processIsRestricted && (context.mainExecutable == this) ) { 1039 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path, this->getPath()); 1040 break; 1041 } 1042 char resolvedPath[PATH_MAX]; 1043 if ( realpath(this->getPath(), resolvedPath) != NULL ) { 1044 char newRealPath[strlen(resolvedPath) + strlen(path)]; 1045 strcpy(newRealPath, resolvedPath); 1046 char* addPoint = strrchr(newRealPath,'/'); 1047 if ( addPoint != NULL ) 1048 strcpy(&addPoint[1], &path[13]); 1049 else 1050 strcpy(newRealPath, &path[13]); 1051 pathToAdd = strdup(newRealPath); 1052 } 1053 } 1054 else if ( strncmp(path, "@executable_path/", 17) == 0 ) { 1055 if ( context.processIsRestricted ) { 1056 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path, this->getPath()); 1057 break; 1058 } 1059 char resolvedPath[PATH_MAX]; 1060 if ( realpath(context.mainExecutable->getPath(), resolvedPath) != NULL ) { 1061 char newRealPath[strlen(resolvedPath) + strlen(path)]; 1062 strcpy(newRealPath, resolvedPath); 1063 char* addPoint = strrchr(newRealPath,'/'); 1064 if ( addPoint != NULL ) 1065 strcpy(&addPoint[1], &path[17]); 1066 else 1067 strcpy(newRealPath, &path[17]); 1068 pathToAdd = strdup(newRealPath); 1069 } 1070 } 1071 else if ( (path[0] != '/') && context.processIsRestricted ) { 1072 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path, this->getPath()); 1073 break; 1074 } 1075 else if ( (path[0] == '/') && (context.rootPaths != NULL) ) { 1076 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths 1077 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists 1078 bool found = false; 1079 for(const char** rp = context.rootPaths; *rp != NULL; ++rp) { 1080 char newPath[PATH_MAX]; 1081 strlcpy(newPath, *rp, PATH_MAX); 1082 strlcat(newPath, path, PATH_MAX); 1083 struct stat stat_buf; 1084 if ( stat(newPath, &stat_buf) != -1 ) { 1085 //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath); 1086 pathToAdd = strdup(newPath); 1087 found = true; 1088 break; 1089 } 1090 } 1091 if ( ! found ) { 1092 // make copy so that all elements of 'paths' can be freed 1093 pathToAdd = strdup(path); 1094 } 1095 } 1096 else { 1097 // make copy so that all elements of 'paths' can be freed 1098 pathToAdd = strdup(path); 1099 } 1100 if ( pathToAdd != NULL ) 1101 paths.push_back(pathToAdd); 1102 break; 1103 } 1104 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1105 } 1106} 1107 1108bool ImageLoaderMachO::getUUID(uuid_t uuid) const 1109{ 1110 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1111 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1112 const struct load_command* cmd = cmds; 1113 for (uint32_t i = 0; i < cmd_count; ++i) { 1114 switch (cmd->cmd) { 1115 case LC_UUID: 1116 uuid_command* uc = (uuid_command*)cmd; 1117 memcpy(uuid, uc->uuid, 16); 1118 return true; 1119 } 1120 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1121 } 1122 bzero(uuid, 16); 1123 return false; 1124} 1125 1126void ImageLoaderMachO::doRebase(const LinkContext& context) 1127{ 1128 // if prebound and loaded at prebound address, then no need to rebase 1129 if ( this->usablePrebinding(context) ) { 1130 // skip rebasing because prebinding is valid 1131 ++fgImagesWithUsedPrebinding; // bump totals for statistics 1132 return; 1133 } 1134 1135 // print why prebinding was not used 1136 if ( context.verbosePrebinding ) { 1137 if ( !this->isPrebindable() ) { 1138 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath()); 1139 } 1140 else if ( fSlide != 0 ) { 1141 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath()); 1142 } 1143 else if ( !this->allDependentLibrariesAsWhenPreBound() ) { 1144 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath()); 1145 } 1146 else if ( !this->usesTwoLevelNameSpace() ){ 1147 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath()); 1148 } 1149 else { 1150 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath()); 1151 } 1152 } 1153 1154 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath()); 1155 1156#if PREBOUND_IMAGE_SUPPORT 1157 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers 1158 // if this image is in the shared cache, do not reset, they will be bound in doBind() 1159 if ( this->isPrebindable() && !fInSharedCache ) 1160 this->resetPreboundLazyPointers(context); 1161#endif 1162 1163 // if loaded at preferred address, no rebasing necessary 1164 if ( this->fSlide == 0 ) 1165 return; 1166 1167#if TEXT_RELOC_SUPPORT 1168 // if there are __TEXT fixups, temporarily make __TEXT writable 1169 if ( fTextSegmentRebases ) 1170 this->makeTextSegmentWritable(context, true); 1171#endif 1172 1173 // do actual rebasing 1174 this->rebase(context); 1175 1176#if TEXT_RELOC_SUPPORT 1177 // if there were __TEXT fixups, restore write protection 1178 if ( fTextSegmentRebases ) 1179 this->makeTextSegmentWritable(context, false); 1180 1181#endif 1182} 1183 1184#if TEXT_RELOC_SUPPORT 1185void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext& context, bool writeable) 1186{ 1187 int textSegmentIndex = 0; 1188 for(unsigned int i=0; i < fSegmentsCount; ++i) { 1189 if ( strcmp(segName(i), "__TEXT") == 0 ) { 1190 textSegmentIndex = i; 1191 break; 1192 } 1193 } 1194 1195 if ( writeable ) { 1196 segMakeWritable(textSegmentIndex, context); 1197 } 1198 else { 1199 #if !__i386__ && !__x86_64__ 1200 // some processors require range to be invalidated before it is made executable 1201 sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex), segSize(textSegmentIndex)); 1202 #endif 1203 segProtect(textSegmentIndex, context); 1204 } 1205} 1206#endif 1207 1208const ImageLoader::Symbol* ImageLoaderMachO::findExportedSymbol(const char* name, bool searchReExports, const ImageLoader** foundIn) const 1209{ 1210 // look in this image first 1211 const ImageLoader::Symbol* result = this->findExportedSymbol(name, foundIn); 1212 if ( result != NULL ) 1213 return result; 1214 1215 if ( searchReExports ) { 1216 for(unsigned int i=0; i < libraryCount(); ++i){ 1217 if ( libReExported(i) ) { 1218 ImageLoader* image = libImage(i); 1219 if ( image != NULL ) { 1220 const Symbol* result = image->findExportedSymbol(name, searchReExports, foundIn); 1221 if ( result != NULL ) 1222 return result; 1223 } 1224 } 1225 } 1226 } 1227 1228 1229 return NULL; 1230} 1231 1232 1233 1234uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol* sym, const LinkContext& context, 1235 const ImageLoader* requestor, bool runResolver) const 1236{ 1237 return this->getSymbolAddress(sym, requestor, context, runResolver); 1238} 1239 1240uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol* sym, const ImageLoader* requestor, 1241 const LinkContext& context, bool runResolver) const 1242{ 1243 uintptr_t result = exportedSymbolAddress(context, sym, requestor, runResolver); 1244 // check for interposing overrides 1245 for (std::vector<InterposeTuple>::iterator it=fgInterposingTuples.begin(); it != fgInterposingTuples.end(); it++) { 1246 // replace all references to 'replacee' with 'replacement' 1247 if ( (result == it->replacee) && (requestor != it->replacementImage) ) { 1248 if ( context.verboseInterposing ) { 1249 dyld::log("dyld interposing: replace 0x%lX with 0x%lX in %s\n", 1250 it->replacee, it->replacement, this->getPath()); 1251 } 1252 result = it->replacement; 1253 } 1254 } 1255 return result; 1256} 1257 1258ImageLoader::DefinitionFlags ImageLoaderMachO::getExportedSymbolInfo(const Symbol* sym) const 1259{ 1260 if ( exportedSymbolIsWeakDefintion(sym) ) 1261 return kWeakDefinition; 1262 else 1263 return kNoDefinitionOptions; 1264} 1265 1266const char* ImageLoaderMachO::getExportedSymbolName(const Symbol* sym) const 1267{ 1268 return exportedSymbolName(sym); 1269} 1270 1271uint32_t ImageLoaderMachO::getExportedSymbolCount() const 1272{ 1273 return exportedSymbolCount(); 1274} 1275 1276 1277const ImageLoader::Symbol* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index) const 1278{ 1279 return exportedSymbolIndexed(index); 1280} 1281 1282 1283uint32_t ImageLoaderMachO::getImportedSymbolCount() const 1284{ 1285 return importedSymbolCount(); 1286} 1287 1288 1289const ImageLoader::Symbol* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index) const 1290{ 1291 return importedSymbolIndexed(index); 1292} 1293 1294 1295ImageLoader::ReferenceFlags ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol* sym) const 1296{ 1297 ImageLoader::ReferenceFlags flags = kNoReferenceOptions; 1298 return flags; 1299} 1300 1301 1302const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol* sym) const 1303{ 1304 return importedSymbolName(sym); 1305} 1306 1307 1308bool ImageLoaderMachO::getSectionContent(const char* segmentName, const char* sectionName, void** start, size_t* length) 1309{ 1310 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1311 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1312 const struct load_command* cmd = cmds; 1313 for (uint32_t i = 0; i < cmd_count; ++i) { 1314 switch (cmd->cmd) { 1315 case LC_SEGMENT_COMMAND: 1316 { 1317 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1318 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1319 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1320 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1321 if ( (strcmp(sect->segname, segmentName) == 0) && (strcmp(sect->sectname, sectionName) == 0) ) { 1322 *start = (uintptr_t*)(sect->addr + fSlide); 1323 *length = sect->size; 1324 return true; 1325 } 1326 } 1327 } 1328 break; 1329 } 1330 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1331 } 1332 *start = NULL; 1333 *length = 0; 1334 return false; 1335} 1336 1337void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections* info) 1338{ 1339 info->mh = this->machHeader(); 1340 info->dwarf_section = 0; 1341 info->dwarf_section_length = 0; 1342 info->compact_unwind_section = 0; 1343 info->compact_unwind_section_length = 0; 1344 if ( fEHFrameSectionOffset != 0 ) { 1345 const macho_section* sect = (macho_section*)&fMachOData[fEHFrameSectionOffset]; 1346 info->dwarf_section = (void*)(sect->addr + fSlide); 1347 info->dwarf_section_length = sect->size; 1348 } 1349 if ( fUnwindInfoSectionOffset != 0 ) { 1350 const macho_section* sect = (macho_section*)&fMachOData[fUnwindInfoSectionOffset]; 1351 info->compact_unwind_section = (void*)(sect->addr + fSlide); 1352 info->compact_unwind_section_length = sect->size; 1353 } 1354} 1355 1356 1357bool ImageLoaderMachO::findSection(const void* imageInterior, const char** segmentName, const char** sectionName, size_t* sectionOffset) 1358{ 1359 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1360 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1361 const struct load_command* cmd = cmds; 1362 const uintptr_t unslidInteriorAddress = (uintptr_t)imageInterior - this->getSlide(); 1363 for (uint32_t i = 0; i < cmd_count; ++i) { 1364 switch (cmd->cmd) { 1365 case LC_SEGMENT_COMMAND: 1366 { 1367 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1368 if ( (unslidInteriorAddress >= seg->vmaddr) && (unslidInteriorAddress < (seg->vmaddr+seg->vmsize)) ) { 1369 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1370 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1371 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1372 if ((sect->addr <= unslidInteriorAddress) && (unslidInteriorAddress < (sect->addr+sect->size))) { 1373 if ( segmentName != NULL ) 1374 *segmentName = sect->segname; 1375 if ( sectionName != NULL ) 1376 *sectionName = sect->sectname; 1377 if ( sectionOffset != NULL ) 1378 *sectionOffset = unslidInteriorAddress - sect->addr; 1379 return true; 1380 } 1381 } 1382 } 1383 } 1384 break; 1385 } 1386 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1387 } 1388 return false; 1389} 1390 1391 1392void __attribute__((noreturn)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext& context, const char* symbol, 1393 const char* referencedFrom, const char* expectedIn) 1394{ 1395 // record values for possible use by CrashReporter or Finder 1396 (*context.setErrorStrings)(dyld_error_kind_symbol_missing, referencedFrom, expectedIn, symbol); 1397 dyld::throwf("Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n", symbol, referencedFrom, expectedIn); 1398} 1399 1400const mach_header* ImageLoaderMachO::machHeader() const 1401{ 1402 return (mach_header*)fMachOData; 1403} 1404 1405uintptr_t ImageLoaderMachO::getSlide() const 1406{ 1407 return fSlide; 1408} 1409 1410// hmm. maybe this should be up in ImageLoader?? 1411const void* ImageLoaderMachO::getEnd() const 1412{ 1413 uintptr_t lastAddress = 0; 1414 for(unsigned int i=0; i < fSegmentsCount; ++i) { 1415 uintptr_t segEnd = segActualEndAddress(i); 1416 if ( strcmp(segName(i), "__UNIXSTACK") != 0 ) { 1417 if ( segEnd > lastAddress ) 1418 lastAddress = segEnd; 1419 } 1420 } 1421 return (const void*)lastAddress; 1422} 1423 1424 1425uintptr_t ImageLoaderMachO::bindLocation(const LinkContext& context, uintptr_t location, uintptr_t value, 1426 const ImageLoader* targetImage, uint8_t type, const char* symbolName, 1427 intptr_t addend, const char* msg) 1428{ 1429 // log 1430 if ( context.verboseBind ) { 1431 if ( addend != 0 ) 1432 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n", 1433 msg, this->getShortName(), (uintptr_t)location, 1434 ((targetImage != NULL) ? targetImage->getShortName() : "<weak_import-missing>"), 1435 symbolName, (uintptr_t)location, value, addend); 1436 else 1437 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n", 1438 msg, this->getShortName(), (uintptr_t)location, 1439 ((targetImage != NULL) ? targetImage->getShortName() : "<weak>import-missing>"), 1440 symbolName, (uintptr_t)location, value); 1441 } 1442#if LOG_BINDINGS 1443// dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName); 1444#endif 1445 1446 // do actual update 1447 uintptr_t* locationToFix = (uintptr_t*)location; 1448 uint32_t* loc32; 1449 uintptr_t newValue = value+addend; 1450 uint32_t value32; 1451 switch (type) { 1452 case BIND_TYPE_POINTER: 1453 // test first so we don't needless dirty pages 1454 if ( *locationToFix != newValue ) 1455 *locationToFix = newValue; 1456 break; 1457 case BIND_TYPE_TEXT_ABSOLUTE32: 1458 loc32 = (uint32_t*)locationToFix; 1459 value32 = (uint32_t)newValue; 1460 if ( *loc32 != value32 ) 1461 *loc32 = value32; 1462 break; 1463 case BIND_TYPE_TEXT_PCREL32: 1464 loc32 = (uint32_t*)locationToFix; 1465 value32 = (uint32_t)newValue - (((uintptr_t)locationToFix) + 4); 1466 if ( *loc32 != value32 ) 1467 *loc32 = value32; 1468 break; 1469 default: 1470 dyld::throwf("bad bind type %d", type); 1471 } 1472 1473 // update statistics 1474 ++fgTotalBindFixups; 1475 1476 return newValue; 1477} 1478 1479 1480 1481 1482 1483#if SUPPORT_OLD_CRT_INITIALIZATION 1484// first 16 bytes of "start" in crt1.o 1485#if __i386__ 1486 static uint8_t sStandardEntryPointInstructions[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 }; 1487#endif 1488#endif 1489 1490struct DATAdyld { 1491 void* dyldLazyBinder; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface 1492 void* dyldFuncLookup; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup 1493 // the following only exist in main executables built for 10.5 or later 1494 ProgramVars vars; 1495}; 1496 1497// These are defined in dyldStartup.s 1498extern "C" void stub_binding_helper(); 1499extern "C" bool dyld_func_lookup(const char* name, uintptr_t* address); 1500 1501 1502void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext& context) 1503{ 1504 const macho_header* mh = (macho_header*)fMachOData; 1505 const uint32_t cmd_count = mh->ncmds; 1506 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1507 const struct load_command* cmd; 1508 // There used to be some optimizations to skip this section scan, but we need to handle the 1509 // __dyld section in libdyld.dylib, so everything needs to be scanned for now. 1510 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv 1511 if ( true ) { 1512 cmd = cmds; 1513 for (uint32_t i = 0; i < cmd_count; ++i) { 1514 if ( cmd->cmd == LC_SEGMENT_COMMAND ) { 1515 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1516 if ( strcmp(seg->segname, "__DATA") == 0 ) { 1517 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1518 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1519 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1520 if ( strcmp(sect->sectname, "__dyld" ) == 0 ) { 1521 struct DATAdyld* dd = (struct DATAdyld*)(sect->addr + fSlide); 1522 if ( sect->size > offsetof(DATAdyld, dyldLazyBinder) ) { 1523 if ( dd->dyldLazyBinder != (void*)&stub_binding_helper ) 1524 dd->dyldLazyBinder = (void*)&stub_binding_helper; 1525 } 1526 if ( sect->size > offsetof(DATAdyld, dyldFuncLookup) ) { 1527 if ( dd->dyldFuncLookup != (void*)&dyld_func_lookup ) 1528 dd->dyldFuncLookup = (void*)&dyld_func_lookup; 1529 } 1530 if ( mh->filetype == MH_EXECUTE ) { 1531 // there are two ways to get the program variables 1532 if ( (sect->size > offsetof(DATAdyld, vars)) && (dd->vars.mh == mh) ) { 1533 // some really old binaries have space for vars, but it is zero filled 1534 // main executable has 10.5 style __dyld section that has program variable pointers 1535 context.setNewProgramVars(dd->vars); 1536 } 1537 else { 1538 // main executable is pre-10.5 and requires the symbols names to be looked up 1539 this->lookupProgramVars(context); 1540 #if SUPPORT_OLD_CRT_INITIALIZATION 1541 // If the first 16 bytes of the entry point's instructions do not 1542 // match what crt1.o supplies, then the program has a custom entry point. 1543 // This means it might be doing something that needs to be executed before 1544 // initializers are run. 1545 if ( memcmp(this->getMain(), sStandardEntryPointInstructions, 16) != 0 ) { 1546 if ( context.verboseInit ) 1547 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n"); 1548 context.setRunInitialzersOldWay(); 1549 } 1550 #endif 1551 } 1552 } 1553 else if ( mh->filetype == MH_DYLIB ) { 1554 const char* installPath = this->getInstallPath(); 1555 if ( (installPath != NULL) && (strncmp(installPath, "/usr/lib/", 9) == 0) ) { 1556 if ( sect->size > offsetof(DATAdyld, vars) ) { 1557 // use ProgramVars from libdyld.dylib but tweak mh field to correct value 1558 dd->vars.mh = context.mainExecutable->machHeader(); 1559 context.setNewProgramVars(dd->vars); 1560 } 1561 } 1562 } 1563 } 1564 else if ( (strcmp(sect->sectname, "__program_vars" ) == 0) && (mh->filetype == MH_EXECUTE) ) { 1565 // this is a Mac OS X 10.6 or later main executable 1566 struct ProgramVars* pv = (struct ProgramVars*)(sect->addr + fSlide); 1567 context.setNewProgramVars(*pv); 1568 } 1569 } 1570 } 1571 } 1572 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1573 } 1574 } 1575} 1576 1577 1578void ImageLoaderMachO::lookupProgramVars(const LinkContext& context) const 1579{ 1580 ProgramVars vars = context.programVars; 1581 const ImageLoader::Symbol* sym; 1582 1583 // get mach header directly 1584 vars.mh = (macho_header*)fMachOData; 1585 1586 // lookup _NXArgc 1587 sym = this->findExportedSymbol("_NXArgc", false, NULL); 1588 if ( sym != NULL ) 1589 vars.NXArgcPtr = (int*)this->getExportedSymbolAddress(sym, context, this, false); 1590 1591 // lookup _NXArgv 1592 sym = this->findExportedSymbol("_NXArgv", false, NULL); 1593 if ( sym != NULL ) 1594 vars.NXArgvPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false); 1595 1596 // lookup _environ 1597 sym = this->findExportedSymbol("_environ", false, NULL); 1598 if ( sym != NULL ) 1599 vars.environPtr = (const char***)this->getExportedSymbolAddress(sym, context, this, false); 1600 1601 // lookup __progname 1602 sym = this->findExportedSymbol("___progname", false, NULL); 1603 if ( sym != NULL ) 1604 vars.__prognamePtr = (const char**)this->getExportedSymbolAddress(sym, context, this, false); 1605 1606 context.setNewProgramVars(vars); 1607} 1608 1609 1610bool ImageLoaderMachO::usablePrebinding(const LinkContext& context) const 1611{ 1612 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind 1613 if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache) 1614 && this->usesTwoLevelNameSpace() 1615 && this->allDependentLibrariesAsWhenPreBound() ) { 1616 // allow environment variables to disable prebinding 1617 if ( context.bindFlat ) 1618 return false; 1619 switch ( context.prebindUsage ) { 1620 case kUseAllPrebinding: 1621 return true; 1622 case kUseSplitSegPrebinding: 1623 return this->fIsSplitSeg; 1624 case kUseAllButAppPredbinding: 1625 return (this != context.mainExecutable); 1626 case kUseNoPrebinding: 1627 return false; 1628 } 1629 } 1630 return false; 1631} 1632 1633 1634void ImageLoaderMachO::doImageInit(const LinkContext& context) 1635{ 1636 if ( fHasDashInit ) { 1637 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1638 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1639 const struct load_command* cmd = cmds; 1640 for (uint32_t i = 0; i < cmd_count; ++i) { 1641 switch (cmd->cmd) { 1642 case LC_ROUTINES_COMMAND: 1643 Initializer func = (Initializer)(((struct macho_routines_command*)cmd)->init_address + fSlide); 1644 // <rdar://problem/8543820&9228031> verify initializers are in image 1645 if ( ! this->containsAddress((void*)func) ) { 1646 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath()); 1647 } 1648 if ( context.verboseInit ) 1649 dyld::log("dyld: calling -init function %p in %s\n", func, this->getPath()); 1650 func(context.argc, context.argv, context.envp, context.apple, &context.programVars); 1651 break; 1652 } 1653 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1654 } 1655 } 1656} 1657 1658void ImageLoaderMachO::doModInitFunctions(const LinkContext& context) 1659{ 1660 if ( fHasInitializers ) { 1661 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1662 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1663 const struct load_command* cmd = cmds; 1664 for (uint32_t i = 0; i < cmd_count; ++i) { 1665 if ( cmd->cmd == LC_SEGMENT_COMMAND ) { 1666 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1667 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1668 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1669 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1670 const uint8_t type = sect->flags & SECTION_TYPE; 1671 if ( type == S_MOD_INIT_FUNC_POINTERS ) { 1672 Initializer* inits = (Initializer*)(sect->addr + fSlide); 1673 const uint32_t count = sect->size / sizeof(uintptr_t); 1674 for (uint32_t i=0; i < count; ++i) { 1675 Initializer func = inits[i]; 1676 // <rdar://problem/8543820&9228031> verify initializers are in image 1677 if ( ! this->containsAddress((void*)func) ) { 1678 dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath()); 1679 } 1680 if ( context.verboseInit ) 1681 dyld::log("dyld: calling initializer function %p in %s\n", func, this->getPath()); 1682 func(context.argc, context.argv, context.envp, context.apple, &context.programVars); 1683 } 1684 } 1685 } 1686 } 1687 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1688 } 1689 } 1690} 1691 1692 1693 1694 1695 1696 1697void ImageLoaderMachO::doGetDOFSections(const LinkContext& context, std::vector<ImageLoader::DOFInfo>& dofs) 1698{ 1699 if ( fHasDOFSections ) { 1700 // walk load commands (mapped in at start of __TEXT segment) 1701 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1702 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1703 const struct load_command* cmd = cmds; 1704 for (uint32_t i = 0; i < cmd_count; ++i) { 1705 switch (cmd->cmd) { 1706 case LC_SEGMENT_COMMAND: 1707 { 1708 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1709 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1710 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1711 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1712 if ( (sect->flags & SECTION_TYPE) == S_DTRACE_DOF ) { 1713 ImageLoader::DOFInfo info; 1714 info.dof = (void*)(sect->addr + fSlide); 1715 info.imageHeader = this->machHeader(); 1716 info.imageShortName = this->getShortName(); 1717 dofs.push_back(info); 1718 } 1719 } 1720 } 1721 break; 1722 } 1723 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1724 } 1725 } 1726} 1727 1728 1729bool ImageLoaderMachO::doInitialization(const LinkContext& context) 1730{ 1731 CRSetCrashLogMessage2(this->getPath()); 1732 1733 // mach-o has -init and static initializers 1734 doImageInit(context); 1735 doModInitFunctions(context); 1736 1737 CRSetCrashLogMessage2(NULL); 1738 1739 return (fHasDashInit || fHasInitializers); 1740} 1741 1742bool ImageLoaderMachO::needsInitialization() 1743{ 1744 return ( fHasDashInit || fHasInitializers ); 1745} 1746 1747 1748bool ImageLoaderMachO::needsTermination() 1749{ 1750 return fHasTerminators; 1751} 1752 1753 1754void ImageLoaderMachO::doTermination(const LinkContext& context) 1755{ 1756 if ( fHasTerminators ) { 1757 const uint32_t cmd_count = ((macho_header*)fMachOData)->ncmds; 1758 const struct load_command* const cmds = (struct load_command*)&fMachOData[sizeof(macho_header)]; 1759 const struct load_command* cmd = cmds; 1760 for (uint32_t i = 0; i < cmd_count; ++i) { 1761 if ( cmd->cmd == LC_SEGMENT_COMMAND ) { 1762 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; 1763 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); 1764 const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; 1765 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { 1766 const uint8_t type = sect->flags & SECTION_TYPE; 1767 if ( type == S_MOD_TERM_FUNC_POINTERS ) { 1768 Terminator* terms = (Terminator*)(sect->addr + fSlide); 1769 const uint32_t count = sect->size / sizeof(uintptr_t); 1770 for (uint32_t i=count; i > 0; --i) { 1771 Terminator func = terms[i-1]; 1772 // <rdar://problem/8543820&9228031> verify terminators are in image 1773 if ( ! this->containsAddress((void*)func) ) { 1774 dyld::throwf("termination function %p not in mapped image for %s\n", func, this->getPath()); 1775 } 1776 if ( context.verboseInit ) 1777 dyld::log("dyld: calling termination function %p in %s\n", func, this->getPath()); 1778 func(); 1779 } 1780 } 1781 } 1782 } 1783 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 1784 } 1785 } 1786} 1787 1788 1789void ImageLoaderMachO::printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo) 1790{ 1791 ImageLoader::printStatistics(imageCount, timingInfo); 1792 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs); 1793 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs); 1794 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions); 1795 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing); 1796} 1797 1798 1799intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context) 1800{ 1801 // preflight and calculate slide if needed 1802 const bool inPIE = (fgNextPIEDylibAddress != 0); 1803 intptr_t slide = 0; 1804 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) { 1805 bool needsToSlide = false; 1806 bool imageHasPreferredLoadAddress = segHasPreferredLoadAddress(0); 1807 uintptr_t lowAddr = (unsigned long)(-1); 1808 uintptr_t highAddr = 0; 1809 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 1810 const uintptr_t segLow = segPreferredLoadAddress(i); 1811 const uintptr_t segHigh = (segLow + segSize(i) + 4095) & -4096; 1812 if ( segLow < lowAddr ) 1813 lowAddr = segLow; 1814 if ( segHigh > highAddr ) 1815 highAddr = segHigh; 1816 1817 if ( needsToSlide || !imageHasPreferredLoadAddress || inPIE || !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) ) 1818 needsToSlide = true; 1819 } 1820 if ( needsToSlide ) { 1821 // find a chunk of address space to hold all segments 1822 uintptr_t addr = reserveAnAddressRange(highAddr-lowAddr, context); 1823 slide = addr - lowAddr; 1824 } 1825 } 1826 else if ( ! this->segmentsCanSlide() ) { 1827 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 1828 if ( strcmp(segName(i), "__PAGEZERO") == 0 ) 1829 continue; 1830 if ( !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) ) 1831 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i), segPreferredLoadAddress(i), segSize(i)); 1832 } 1833 } 1834 else { 1835 throw "mach-o does not support independently sliding segments"; 1836 } 1837 return slide; 1838} 1839 1840 1841uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context) 1842{ 1843 vm_address_t addr = 0; 1844 vm_size_t size = length; 1845 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either 1846 if ( fgNextPIEDylibAddress != 0 ) { 1847 // add small (0-3 pages) random padding between dylibs 1848 addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*4096; 1849 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard)); 1850 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB)); 1851 if ( r == KERN_SUCCESS ) { 1852 fgNextPIEDylibAddress = addr + size; 1853 return addr; 1854 } 1855 fgNextPIEDylibAddress = 0; 1856 } 1857 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_DYLIB)); 1858 if ( r != KERN_SUCCESS ) 1859 throw "out of address space"; 1860 1861 return addr; 1862} 1863 1864bool ImageLoaderMachO::reserveAddressRange(uintptr_t start, size_t length) 1865{ 1866 vm_address_t addr = start; 1867 vm_size_t size = length; 1868 kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB)); 1869 if ( r != KERN_SUCCESS ) 1870 return false; 1871 return true; 1872} 1873 1874 1875 1876void ImageLoaderMachO::mapSegments(int fd, uint64_t offsetInFat, uint64_t lenInFat, uint64_t fileLen, const LinkContext& context) 1877{ 1878 // find address range for image 1879 intptr_t slide = this->assignSegmentAddresses(context); 1880 if ( context.verboseMapping ) 1881 dyld::log("dyld: Mapping %s\n", this->getPath()); 1882 // map in all segments 1883 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 1884 vm_offset_t fileOffset = segFileOffset(i) + offsetInFat; 1885 vm_size_t size = segFileSize(i); 1886 uintptr_t requestedLoadAddress = segPreferredLoadAddress(i) + slide; 1887 int protection = 0; 1888 if ( !segUnaccessible(i) ) { 1889 // If has text-relocs, don't set x-bit initially. 1890 // Instead set it later after text-relocs have been done. 1891 // The iPhone OS does not like it when you make executable code writable. 1892 if ( segExecutable(i) && !(segHasRebaseFixUps(i) && (slide != 0)) ) 1893 protection |= PROT_EXEC; 1894 if ( segReadable(i) ) 1895 protection |= PROT_READ; 1896 if ( segWriteable(i) ) 1897 protection |= PROT_WRITE; 1898 } 1899 #if __i386__ 1900 // initially map __IMPORT segments R/W so dyld can update them 1901 if ( segIsReadOnlyImport(i) ) 1902 protection |= PROT_WRITE; 1903 #endif 1904 // wholly zero-fill segments have nothing to mmap() in 1905 if ( size > 0 ) { 1906 if ( (fileOffset+size) > fileLen ) { 1907 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu", 1908 segName(i), (uint64_t)(fileOffset+size), fileLen); 1909 } 1910 void* loadAddress = xmmap((void*)requestedLoadAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, fileOffset); 1911 if ( loadAddress == ((void*)(-1)) ) { 1912 dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s", 1913 errno, requestedLoadAddress, (uintptr_t)size, segName(i), getPath()); 1914 } 1915 } 1916 // update stats 1917 ++ImageLoader::fgTotalSegmentsMapped; 1918 ImageLoader::fgTotalBytesMapped += size; 1919 if ( context.verboseMapping ) 1920 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i), requestedLoadAddress, requestedLoadAddress+size-1, 1921 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' ); 1922 } 1923 1924 // update slide to reflect load location 1925 this->setSlide(slide); 1926} 1927 1928void ImageLoaderMachO::mapSegments(const void* memoryImage, uint64_t imageLen, const LinkContext& context) 1929{ 1930 // find address range for image 1931 intptr_t slide = this->assignSegmentAddresses(context); 1932 if ( context.verboseMapping ) 1933 dyld::log("dyld: Mapping memory %p\n", memoryImage); 1934 // map in all segments 1935 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 1936 vm_address_t loadAddress = segPreferredLoadAddress(i) + slide; 1937 vm_address_t srcAddr = (uintptr_t)memoryImage + segFileOffset(i); 1938 vm_size_t size = segFileSize(i); 1939 kern_return_t r = vm_copy(mach_task_self(), srcAddr, size, loadAddress); 1940 if ( r != KERN_SUCCESS ) 1941 throw "can't map segment"; 1942 if ( context.verboseMapping ) 1943 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i), (uintptr_t)loadAddress, (uintptr_t)loadAddress+size-1); 1944 } 1945 // update slide to reflect load location 1946 this->setSlide(slide); 1947 // set R/W permissions on all segments at slide location 1948 for(unsigned int i=0, e=segmentCount(); i < e; ++i) { 1949 segProtect(i, context); 1950 } 1951} 1952 1953 1954void ImageLoaderMachO::segProtect(unsigned int segIndex, const ImageLoader::LinkContext& context) 1955{ 1956 vm_prot_t protection = 0; 1957 if ( !segUnaccessible(segIndex) ) { 1958 if ( segExecutable(segIndex) ) 1959 protection |= PROT_EXEC; 1960 if ( segReadable(segIndex) ) 1961 protection |= PROT_READ; 1962 if ( segWriteable(segIndex) ) 1963 protection |= PROT_WRITE; 1964 } 1965 vm_address_t addr = segActualLoadAddress(segIndex); 1966 vm_size_t size = segSize(segIndex); 1967 const bool setCurrentPermissions = false; 1968 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection); 1969 if ( r != KERN_SUCCESS ) { 1970 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s", 1971 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath()); 1972 } 1973 if ( context.verboseMapping ) { 1974 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1, 1975 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' ); 1976 } 1977} 1978 1979void ImageLoaderMachO::segMakeWritable(unsigned int segIndex, const ImageLoader::LinkContext& context) 1980{ 1981 vm_address_t addr = segActualLoadAddress(segIndex); 1982 vm_size_t size = segSize(segIndex); 1983 const bool setCurrentPermissions = false; 1984 vm_prot_t protection = VM_PROT_WRITE | VM_PROT_READ; 1985 if ( segExecutable(segIndex) && !segHasRebaseFixUps(segIndex) ) 1986 protection |= VM_PROT_EXECUTE; 1987 kern_return_t r = vm_protect(mach_task_self(), addr, size, setCurrentPermissions, protection); 1988 if ( r != KERN_SUCCESS ) { 1989 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s", 1990 (long long)addr, (long long)size, protection, r, segName(segIndex), this->getPath()); 1991 } 1992 if ( context.verboseMapping ) { 1993 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex), (uintptr_t)addr, (uintptr_t)addr+size-1, 1994 (protection & PROT_READ) ? 'r' : '.', (protection & PROT_WRITE) ? 'w' : '.', (protection & PROT_EXEC) ? 'x' : '.' ); 1995 } 1996} 1997 1998 1999