1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
25 // work around until conformance work is complete rdar://problem/4508801
33 #include <sys/types.h>
34 #include <sys/fcntl.h>
37 #include <mach/shared_memory_server.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 #if __ppc__ || __ppc64__
47 #include <mach-o/ppc/reloc.h>
50 #include <mach-o/x86_64/reloc.h>
54 #define MH_PIE 0x200000
58 #define S_DTRACE_DOF 0xF
61 #ifndef S_ATTR_SELF_MODIFYING_CODE
62 #define S_ATTR_SELF_MODIFYING_CODE 0x04000000
65 #include "ImageLoaderMachO.h"
66 #include "mach-o/dyld_images.h"
68 // optimize strcmp for ppc
70 #include <ppc_intrinsics.h>
72 #define astrcmp(a,b) strcmp(a,b)
76 extern "C" void _spin_lock(uint32_t*);
77 extern "C" void _spin_unlock(uint32_t*);
80 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
83 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
84 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
85 struct macho_header
: public mach_header_64
{};
86 struct macho_segment_command
: public segment_command_64
{};
87 struct macho_section
: public section_64
{};
88 struct macho_nlist
: public nlist_64
{};
89 struct macho_routines_command
: public routines_command_64
{};
92 #define LC_SEGMENT_COMMAND LC_SEGMENT
93 #define LC_ROUTINES_COMMAND LC_ROUTINES
94 struct macho_header
: public mach_header
{};
95 struct macho_segment_command
: public segment_command
{};
96 struct macho_section
: public section
{};
97 struct macho_nlist
: public nlist
{};
98 struct macho_routines_command
: public routines_command
{};
102 #define POINTER_RELOC X86_64_RELOC_UNSIGNED
104 #define POINTER_RELOC GENERIC_RELOC_VANILLA
107 uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs
= 0;
108 uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
= 0;
109 uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports
= 0;
112 uint32_t ImageLoaderMachO::fgReadOnlyImportSpinLock
= 0;
115 //#define LINKEDIT_USAGE_DEBUG 1
117 #if LINKEDIT_USAGE_DEBUG
119 static std::set
<uintptr_t> sLinkEditPageBuckets
;
122 extern ImageLoader
* findImageContainingAddress(const void* addr
);
125 static void noteAccessedLinkEditAddress(const void* addr
)
127 uintptr_t page
= ((uintptr_t)addr
) & (-4096);
128 if ( sLinkEditPageBuckets
.count(page
) == 0 ) {
129 ImageLoader
* inImage
= dyld::findImageContainingAddress(addr
);
130 dyld::log("dyld: accessing page 0x%016lX in __LINKEDIT of %s\n", page
, inImage
!= NULL
? inImage
->getPath() : "unknown" );
132 sLinkEditPageBuckets
.insert(page
);
136 // only way to share initialization in C++
137 void ImageLoaderMachO::init()
140 fLinkEditBase
= NULL
;
145 fTwoLevelHints
= NULL
;
147 #if TEXT_RELOC_SUPPORT
148 fTextSegmentWithFixups
= NULL
;
151 fReadOnlyImportSegment
= NULL
;
154 fInSharedCache
= false;
156 f4GBWritable
= false;
158 fHasSubLibraries
= false;
159 fHasSubUmbrella
= false;
161 fHasDOFSections
= false;
162 fHasDashInit
= false;
163 fHasInitializers
= false;
164 fHasTerminators
= false;
165 #if IMAGE_NOTIFY_SUPPORT
166 fHasImageNotifySection
= false;
170 // create image for main executable
171 ImageLoaderMachO::ImageLoaderMachO(const struct mach_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
)
177 // temporary use this buffer until TEXT is mapped in
178 fMachOData
= (const uint8_t*)mh
;
181 this->instantiateSegments((const uint8_t*)mh
);
183 // set slide for PIE programs
184 this->setSlide(slide
);
186 // get pointers to interesting things
187 this->parseLoadCmds();
189 // update segments to reference load commands in mapped in __TEXT segment
190 this->adjustSegments();
193 // kernel may have mapped in __IMPORT segment read-only, we need it read/write to do binding
194 if ( fReadOnlyImportSegment
!= NULL
)
195 fReadOnlyImportSegment
->tempWritable(context
, this);
198 // for PIE record end of program, to know where to start loading dylibs
199 if ( mh
->flags
& MH_PIE
)
200 Segment::fgNextPIEDylibAddress
= (uintptr_t)this->getEnd();
202 // notify state change
203 this->setMapped(context
);
205 if ( context
.verboseMapping
) {
206 dyld::log("dyld: Main executable mapped %s\n", this->getPath());
207 for (ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
209 if ( (strcmp(seg
->getName(), "__PAGEZERO") == 0) || (strcmp(seg
->getName(), "__UNIXSTACK") == 0) )
210 dyld::log("%18s at 0x%08lX->0x%08lX\n", seg
->getName(), seg
->getPreferredLoadAddress(), seg
->getPreferredLoadAddress()+seg
->getSize());
212 dyld::log("%18s at 0x%08lX->0x%08lX\n", seg
->getName(), seg
->getActualLoadAddress(this), seg
->getActualLoadAddress(this)+seg
->getSize());
218 // create image by copying an in-memory mach-o file
219 ImageLoaderMachO::ImageLoaderMachO(const char* moduleName
, const struct mach_header
* mh
, uint64_t len
, const LinkContext
& context
)
220 : ImageLoader(moduleName
)
225 // temporary use this buffer until TEXT is mapped in
226 fMachOData
= (const uint8_t*)mh
;
229 this->instantiateSegments((const uint8_t*)mh
);
232 if ( mh
->filetype
== MH_EXECUTE
) {
233 throw "can't load another MH_EXECUTE";
236 ImageLoader::mapSegments((const void*)mh
, len
, context
);
239 // for compatibility, never unload dylibs loaded from memory
240 this->setNeverUnload();
242 // get pointers to interesting things
243 this->parseLoadCmds();
245 // update segments to reference load commands in mapped in __TEXT segment
246 this->adjustSegments();
248 // bundle loads need path copied
249 if ( moduleName
!= NULL
)
250 this->setPath(moduleName
);
252 // notify state change
253 this->setMapped(context
);
257 // create image by using cached mach-o file
258 ImageLoaderMachO::ImageLoaderMachO(const struct mach_header
* mh
, const char* path
, const struct stat
& info
, const LinkContext
& context
)
259 : ImageLoader(path
, 0, info
)
264 // already mapped to mh address
265 fMachOData
= (const uint8_t*)mh
;
267 // usually a split seg
268 fIsSplitSeg
= ((mh
->flags
& MH_SPLIT_SEGS
) != 0);
270 // remember this is from shared cache and cannot be unloaded
271 fInSharedCache
= true;
272 this->setNeverUnload();
275 this->instantiateSegments((const uint8_t*)mh
);
277 // segments already mapped in cache
278 if ( context
.verboseMapping
) {
279 dyld::log("dyld: Using shared cached for %s\n", path
);
280 for (ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
282 dyld::log("%18s at 0x%08lX->0x%08lX\n", seg
->getName(), seg
->getActualLoadAddress(this), seg
->getActualLoadAddress(this)+seg
->getSize());
286 // get pointers to interesting things
287 this->parseLoadCmds();
289 // note: path is mapped into cache so no need for ImageLoader to make a copy
291 // notify state change
292 this->setMapped(context
);
296 // create image by mapping in a mach-o file
297 ImageLoaderMachO::ImageLoaderMachO(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,
298 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
299 : ImageLoader(path
, offsetInFat
, info
)
304 // read load commands
305 const unsigned int dataSize
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
;
306 uint8_t buffer
[dataSize
];
307 const uint8_t* fileData
= firstPage
;
308 if ( dataSize
> 4096 ) {
309 // only read more if cmds take up more space than first page
311 memcpy(buffer
, firstPage
, 4096);
312 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096);
315 // temporary use this buffer until TEXT is mapped in
316 fMachOData
= fileData
;
318 // the meaning of many fields changes in split seg mach-o files
319 fIsSplitSeg
= ((((macho_header
*)fileData
)->flags
& MH_SPLIT_SEGS
) != 0) && (((macho_header
*)fileData
)->filetype
== MH_DYLIB
);
322 this->instantiateSegments(fileData
);
324 // map segments, except for main executable which is already mapped in by kernel
325 if ( ((macho_header
*)fileData
)->filetype
!= MH_EXECUTE
)
326 this->mapSegments(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
);
328 // get pointers to interesting things
329 this->parseLoadCmds();
331 // update segments to reference load commands in mapped in __TEXT segment
332 this->adjustSegments();
334 // notify state change
335 this->setMapped(context
);
337 // if path happens to be same as in LC_DYLIB_ID load command use that, otherwise malloc a copy of the path
338 const char* installName
= getInstallPath();
339 if ( (installName
!= NULL
) && (strcmp(installName
, path
) == 0) && (path
[0] == '/') )
340 this->setPathUnowned(installName
);
341 if ( path
[0] != '/' ) {
342 // rdar://problem/5135363 turn relative paths into absolute paths so gdb, Symbolication can later find them
343 char realPath
[MAXPATHLEN
];
344 if ( realpath(path
, realPath
) != NULL
)
345 this->setPath(realPath
);
352 // tell kernel about pages we are going to need soon
353 if ( ! context
.preFetchDisabled
)
354 this->preFetch(fd
, offsetInFat
, context
);
360 ImageLoaderMachO::~ImageLoaderMachO()
362 // keep count of images with weak exports
363 if ( this->hasCoalescedExports() )
364 --fgCountOfImagesWithWeakExports
;
366 // keep count of images used in shared cache
367 if ( fInSharedCache
)
368 --fgImagesUsedFromSharedCache
;
370 // usually unmap image when done
371 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) {
372 // first segment has load commands, so unmap last
373 Segment
* firstSeg
= *(this->beginSegments());
374 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
376 if ( seg
!= firstSeg
)
379 firstSeg
->unmap(this);
381 // free segment objects
382 free(fSegmentsArray
);
387 void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData
)
389 const uint32_t cmd_count
= ((macho_header
*)fileData
)->ncmds
;
390 const struct load_command
* const cmds
= (struct load_command
*)&fileData
[sizeof(macho_header
)];
392 // count LC_SEGMENT cmd and reserve that many segment slots
393 uint32_t segCount
= 0;
394 const struct load_command
* cmd
= cmds
;
395 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
396 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
397 // ignore zero-sized segments
398 if ( ((struct macho_segment_command
*)cmd
)->vmsize
!= 0 )
401 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
403 // fSegmentsArrayCount is only 8-bits
404 if ( segCount
> 255 )
405 dyld::throwf("more than 255 segments in %s", this->getPath());
407 // allocate array of segment objects in one call to malloc()
408 //fSegmentsArray = static_cast<SegmentMachO*>(operator new[](segCount*sizeof(SegmentMachO)));
409 fSegmentsArray
= static_cast<SegmentMachO
*>(malloc(segCount
*sizeof(SegmentMachO
)));
410 fSegmentsArrayCount
= segCount
;
412 // construct Segment object for each LC_SEGMENT cmd using "placment new"
413 uint32_t segIndex
= 0;
415 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
416 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
417 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
418 // ignore zero-sized segments
419 if ( segCmd
->vmsize
!= 0 )
420 new (&fSegmentsArray
[segIndex
++]) SegmentMachO(segCmd
);
422 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
427 void ImageLoaderMachO::adjustSegments()
429 // tell each segment where is load command is finally mapped
430 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
431 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
432 uint32_t segIndex
= 0;
433 const struct load_command
* cmd
= cmds
;
434 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
435 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
436 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
437 // ignore zero-sized segments
438 if ( segCmd
->vmsize
!= 0 ) {
439 fSegmentsArray
[segIndex
].adjust(segCmd
);
443 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
447 void ImageLoaderMachO::preFetch(int fd
, uint64_t offsetInFat
, const LinkContext
& context
)
449 // always prefetch a subrange of __LINKEDIT pages
450 uintptr_t symbolTableOffset
= (uintptr_t)fSymbolTable
- (uintptr_t)fLinkEditBase
;
451 uintptr_t stringTableOffset
= (uintptr_t)fStrings
- (uintptr_t)fLinkEditBase
;
453 // if image did not load at preferred address
454 if ( fSegmentsArray
[0].getPreferredLoadAddress() != (uintptr_t)fMachOData
) {
455 // local relocations will be processed, so start pre-fetch at local symbols
456 start
= offsetInFat
+ fDynamicInfo
->locreloff
;
459 // otherwise start pre-fetch at global symbols section of symbol table
460 start
= offsetInFat
+ symbolTableOffset
+ fDynamicInfo
->iextdefsym
* sizeof(macho_nlist
);
462 // prefetch ends at end of last undefined string in string pool
463 uintptr_t end
= offsetInFat
+ stringTableOffset
;
464 if ( fDynamicInfo
->nundefsym
!= 0 )
465 end
+= fSymbolTable
[fDynamicInfo
->iundefsym
+fDynamicInfo
->nundefsym
-1].n_un
.n_strx
;
466 else if ( fDynamicInfo
->nextdefsym
!= 0 )
467 end
+= fSymbolTable
[fDynamicInfo
->iextdefsym
+fDynamicInfo
->nextdefsym
-1].n_un
.n_strx
;
470 advice
.ra_offset
= start
& (-4096); // page align
471 advice
.ra_count
= (end
-advice
.ra_offset
+4095) & (-4096);
472 fgTotalBytesPreFetched
+= advice
.ra_count
;
473 fcntl(fd
, F_RDADVISE
, &advice
);
474 if ( context
.verboseMapping
) {
475 dyld::log("%18s prefetching 0x%0llX -> 0x%0llX\n",
476 "__LINKEDIT", advice
.ra_offset
+(uintptr_t)fLinkEditBase
-offsetInFat
, advice
.ra_offset
+advice
.ra_count
+(uintptr_t)fLinkEditBase
-offsetInFat
);
479 // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
480 if ( context
.linkingMainExecutable
) {
481 for (ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
483 if ( seg
->writeable() && (seg
->getFileSize() > 0) ) {
484 // prefetch writable segment that have mmap'ed regions
485 advice
.ra_offset
= offsetInFat
+ seg
->getFileOffset();
486 advice
.ra_count
= seg
->getFileSize();
487 // limit prefetch to 1MB (256 pages)
488 if ( advice
.ra_count
> 1024*1024 )
489 advice
.ra_count
= 1024*1024;
490 fgTotalBytesPreFetched
+= advice
.ra_count
;
491 fcntl(fd
, F_RDADVISE
, &advice
);
492 if ( context
.verboseMapping
) {
493 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n",
494 seg
->getName(), seg
->getActualLoadAddress(this), seg
->getActualLoadAddress(this)+advice
.ra_count
-1);
501 bool ImageLoaderMachO::segmentsMustSlideTogether() const
506 bool ImageLoaderMachO::segmentsCanSlide() const
508 const macho_header
* mh
= (macho_header
*)fMachOData
;
509 return ( (mh
->filetype
== MH_DYLIB
) || (mh
->filetype
== MH_BUNDLE
) );
512 bool ImageLoaderMachO::isBundle() const
514 const macho_header
* mh
= (macho_header
*)fMachOData
;
515 return ( mh
->filetype
== MH_BUNDLE
);
518 bool ImageLoaderMachO::isDylib() const
520 const macho_header
* mh
= (macho_header
*)fMachOData
;
521 return ( mh
->filetype
== MH_DYLIB
);
524 bool ImageLoaderMachO::forceFlat() const
526 const macho_header
* mh
= (macho_header
*)fMachOData
;
527 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
530 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
532 const macho_header
* mh
= (macho_header
*)fMachOData
;
533 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
536 bool ImageLoaderMachO::isPrebindable() const
538 const macho_header
* mh
= (macho_header
*)fMachOData
;
539 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
542 bool ImageLoaderMachO::hasCoalescedExports() const
544 const macho_header
* mh
= (macho_header
*)fMachOData
;
545 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
548 bool ImageLoaderMachO::needsCoalescing() const
550 const macho_header
* mh
= (macho_header
*)fMachOData
;
551 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
559 // hack until kernel headers and glue are in system
560 struct _shared_region_mapping_np
{
561 mach_vm_address_t address
;
563 mach_vm_offset_t file_offset
;
564 vm_prot_t max_prot
; /* read/write/execute/COW/ZF */
565 vm_prot_t init_prot
; /* read/write/execute/COW/ZF */
567 struct _shared_region_range_np
{
568 mach_vm_address_t address
;
572 #if SPLIT_SEG_SHARED_REGION_SUPPORT
574 // Requests the kernel to map a number of regions from the fd into the
575 // shared sections address range (0x90000000-0xAFFFFFFF).
576 // If shared_region_make_private_np() has not been called by this process,
577 // the file mapped in is seen in the address space of all processes that
578 // participate in using the shared region.
579 // If shared_region_make_private_np() _has_ been called by this process,
580 // the file mapped in is only seen by this process.
581 // If the slide parameter is not NULL and then regions cannot be mapped
582 // as requested, the kernel will try to map the file in at a different
583 // address in the shared region and return the distance slid.
584 // If the mapping requesting cannot be fulfilled, returns non-zero.
586 _shared_region_map_file_np(
587 int fd
, // file descriptor to map into shared region
588 unsigned int regionCount
, // number of entres in array of regions
589 const _shared_region_mapping_np regions
[], // the array of regions to map
590 uint64_t* slide
) // the amount all regions were slid, NULL means don't attempt to slide
592 //dyld::log("%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide);
593 //for ( unsigned int i=0; i < regionCount; ++i) {
594 // dyld::log("\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size);
596 int r
= syscall(299, fd
, regionCount
, regions
, slide
);
598 // dyld::log("%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno));
601 // Called by dyld if shared_region_map_file() fails.
602 // Requests the kernel to take this process out of using the shared region.
603 // The specified ranges are created as private copies from the shared region for this process.
605 _shared_region_make_private_np(
606 unsigned int rangeCount
, // number of entres in array of msrp_range
607 const _shared_region_range_np ranges
[]) // the array of shared regions to make private
609 //dyld::log("%s(%u, %8p)\n", __func__, rangeCount, ranges);
610 int r
= syscall(300, rangeCount
, ranges
);
612 // dyld::log("%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno));
615 #define KERN_SHREG_PRIVATIZABLE 54
619 _shared_region_map_file_with_mmap(
620 int fd
, // file descriptor to map into shared region
621 unsigned int regionCount
, // number of entres in array of regions
622 const _shared_region_mapping_np regions
[]) // the array of regions to map
624 // map in each region
625 for(unsigned int i
=0; i
< regionCount
; ++i
) {
626 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
);
627 size_t size
= regions
[i
].size
;
628 if ( (regions
[i
].init_prot
& VM_PROT_ZF
) != 0 ) {
629 // do nothing already vm_allocate() which zero fills
633 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
634 protection
|= PROT_EXEC
;
635 if ( regions
[i
].init_prot
& VM_PROT_READ
)
636 protection
|= PROT_READ
;
637 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
638 protection
|= PROT_WRITE
;
639 off_t offset
= regions
[i
].file_offset
;
640 //dyld::log("mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
641 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
642 if ( mmapAddress
== ((void*)(-1)) )
653 hasSharedRegionMapFile(void)
655 int mib
[CTL_MAXNAME
];
660 mib
[1] = KERN_SHREG_PRIVATIZABLE
;
662 if (sysctl(mib
, 2, &value
, &size
, NULL
, 0) != 0) {
669 #endif // SPLIT_SEG_SHARED_REGION_SUPPORT
672 #if SPLIT_SEG_DYLIB_SUPPORT
674 ImageLoaderMachO::getExtraZeroFillEntriesCount()
676 // calculate mapping entries
677 unsigned int extraZeroFillEntries
= 0;
678 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
680 if ( seg
->hasTrailingZeroFill() )
681 ++extraZeroFillEntries
;
684 return extraZeroFillEntries
;
688 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
689 _shared_region_mapping_np
*mappingTable
)
691 unsigned int segmentCount
= fSegmentsArrayCount
;
692 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
693 Segment
* seg
= &fSegmentsArray
[segIndex
];
694 _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
695 entry
->address
= seg
->getActualLoadAddress(this);
696 entry
->size
= seg
->getFileSize();
697 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
698 entry
->init_prot
= VM_PROT_NONE
;
699 if ( !seg
->unaccessible() ) {
700 if ( seg
->executable() )
701 entry
->init_prot
|= VM_PROT_EXECUTE
;
702 if ( seg
->readable() )
703 entry
->init_prot
|= VM_PROT_READ
;
704 if ( seg
->writeable() )
705 entry
->init_prot
|= VM_PROT_WRITE
| VM_PROT_COW
;
707 entry
->max_prot
= entry
->init_prot
;
708 if ( seg
->hasTrailingZeroFill() ) {
709 _shared_region_mapping_np
* zfentry
= &mappingTable
[++entryIndex
];
710 zfentry
->address
= entry
->address
+ seg
->getFileSize();
711 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
712 zfentry
->file_offset
= 0;
713 zfentry
->init_prot
= entry
->init_prot
| VM_PROT_COW
| VM_PROT_ZF
;
714 zfentry
->max_prot
= zfentry
->init_prot
;
720 ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd
,
721 uint64_t offsetInFat
,
724 const LinkContext
& context
)
726 static uintptr_t sNextAltLoadAddress
733 const unsigned int segmentCount
= fSegmentsArrayCount
;
734 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
735 const unsigned int regionCount
= segmentCount
+extraZeroFillEntries
;
736 _shared_region_mapping_np regions
[regionCount
];
737 initMappingTable(offsetInFat
, regions
);
739 // find space somewhere to allocate split seg
740 bool foundRoom
= false;
741 vm_size_t biggestDiff
= 0;
742 while ( ! foundRoom
) {
744 for(unsigned int i
=0; i
< regionCount
; ++i
) {
745 vm_address_t addr
= sNextAltLoadAddress
+ regions
[i
].address
- regions
[0].address
;
746 vm_size_t size
= regions
[i
].size
;
747 r
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/);
749 // no room here, deallocate what has succeeded so far
750 for(unsigned int j
=0; j
< i
; ++j
) {
751 vm_address_t addr
= sNextAltLoadAddress
+ regions
[j
].address
- regions
[0].address
;
752 vm_size_t size
= regions
[j
].size
;
753 (void)vm_deallocate(mach_task_self(), addr
, size
);
755 sNextAltLoadAddress
+= 0x00100000; // skip ahead 1MB and try again
756 if ( (sNextAltLoadAddress
& 0xF0000000) == 0x90000000 )
757 sNextAltLoadAddress
= 0xB0000000;
758 if ( (sNextAltLoadAddress
& 0xF0000000) == 0xF0000000 )
759 throw "can't map split seg anywhere";
763 vm_size_t high
= (regions
[i
].address
+ size
- regions
[0].address
) & 0x0FFFFFFF;
764 if ( high
> biggestDiff
)
769 // map in each region
770 uintptr_t slide
= sNextAltLoadAddress
- regions
[0].address
;
771 this->setSlide(slide
);
772 for(unsigned int i
=0; i
< regionCount
; ++i
) {
773 if ( ((regions
[i
].init_prot
& VM_PROT_ZF
) != 0) || (regions
[i
].size
== 0) ) {
774 // nothing to mmap for zero-fills areas, they are just vm_allocated
777 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
+ slide
);
778 size_t size
= regions
[i
].size
;
780 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
781 protection
|= PROT_EXEC
;
782 if ( regions
[i
].init_prot
& VM_PROT_READ
)
783 protection
|= PROT_READ
;
784 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
785 protection
|= PROT_WRITE
;
786 off_t offset
= regions
[i
].file_offset
;
787 //dyld::log("mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
788 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
789 if ( mmapAddress
== ((void*)(-1)) )
793 // set so next maps right after this one
794 sNextAltLoadAddress
+= biggestDiff
;
795 sNextAltLoadAddress
= (sNextAltLoadAddress
+ 4095) & (-4096);
798 if ( context
.verboseMapping
) {
799 dyld::log("dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide
, this->getPath());
800 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
801 Segment
* seg
= &fSegmentsArray
[segIndex
];
802 const _shared_region_mapping_np
* entry
= ®ions
[entryIndex
];
803 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
804 dyld::log("%18s at 0x%08lX->0x%08lX\n",
805 seg
->getName(), seg
->getActualLoadAddress(this), seg
->getActualLoadAddress(this)+seg
->getFileSize()-1);
806 if ( entryIndex
< (regionCount
-1) ) {
807 const _shared_region_mapping_np
* nextEntry
= ®ions
[entryIndex
+1];
808 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
809 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
810 dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n",
811 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress(this) + segOffset
), (uintptr_t)(seg
->getActualLoadAddress(this) + segOffset
+ nextEntry
->size
- 1));
822 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
824 // non-split segment libraries handled by super class
826 return ImageLoader::mapSegments(fd
, offsetInFat
, lenInFat
, fileLen
, context
);
828 #if SPLIT_SEG_SHARED_REGION_SUPPORT
829 enum SharedRegionState
831 kSharedRegionStartState
= 0,
832 kSharedRegionMapFileState
,
833 kSharedRegionMapFilePrivateState
,
834 kSharedRegionMapFilePrivateMMapState
,
835 kSharedRegionMapFilePrivateOutsideState
,
837 static SharedRegionState sSharedRegionState
= kSharedRegionStartState
;
839 if ( kSharedRegionStartState
== sSharedRegionState
) {
840 if ( hasSharedRegionMapFile() ) {
841 if ( context
.sharedRegionMode
== kUsePrivateSharedRegion
) {
842 sharedRegionMakePrivate(context
);
843 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
845 else if ( context
.sharedRegionMode
== kDontUseSharedRegion
) {
846 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
848 else if ( context
.sharedRegionMode
== kSharedRegionIsSharedCache
) {
849 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
852 sSharedRegionState
= kSharedRegionMapFileState
;
856 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
860 if ( kSharedRegionMapFileState
== sSharedRegionState
) {
861 if ( 0 != sharedRegionMapFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
862 sharedRegionMakePrivate(context
);
863 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
867 if ( (kSharedRegionMapFilePrivateState
== sSharedRegionState
) || (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
) ) {
868 if ( 0 != sharedRegionMapFilePrivate(fd
, offsetInFat
, lenInFat
, fileLen
, context
, (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
)) ) {
869 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
873 if ( kSharedRegionMapFilePrivateOutsideState
== sSharedRegionState
) {
874 if ( 0 != sharedRegionMapFilePrivateOutside(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
875 throw "mapping error";
879 // support old split-seg dylibs by mapping them where ever we find space
880 if ( sharedRegionMapFilePrivateOutside(fd
, offsetInFat
, lenInFat
, fileLen
, context
) != 0 ) {
881 throw "mapping error";
885 #endif // SPLIT_SEG_DYLIB_SUPPORT
888 #if SPLIT_SEG_SHARED_REGION_SUPPORT
889 int ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext
& context
)
891 if ( context
.verboseMapping
)
892 dyld::log("dyld: making shared regions private\n");
894 // shared mapping failed, so make private copy of shared region and try mapping private
895 MappedRegion allRegions
[context
.imageCount()*8]; // assume average of less that eight segments per image
896 MappedRegion
* end
= context
.getAllMappedRegions(allRegions
);
897 _shared_region_range_np splitSegRegions
[end
-allRegions
];
898 _shared_region_range_np
* sp
= splitSegRegions
;
899 for (MappedRegion
* p
=allRegions
; p
< end
; ++p
) {
900 uint8_t highByte
= p
->address
>> 28;
901 if ( (highByte
== 9) || (highByte
== 0xA) ) {
902 _shared_region_range_np splitRegion
;
903 splitRegion
.address
= p
->address
;
904 splitRegion
.size
= p
->size
;
908 int result
= _shared_region_make_private_np(sp
-splitSegRegions
, splitSegRegions
);
909 // notify gdb or other lurkers that this process is no longer using the shared region
910 dyld_all_image_infos
.processDetachedFromSharedRegion
= true;
915 ImageLoaderMachO::sharedRegionMapFile(int fd
,
916 uint64_t offsetInFat
,
919 const LinkContext
& context
)
921 // build table of segments to map
922 const unsigned int segmentCount
= fSegmentsArrayCount
;
923 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
924 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
925 _shared_region_mapping_np mappingTable
[mappingTableCount
];
926 initMappingTable(offsetInFat
, mappingTable
);
928 uint64_t *slidep
= NULL
;
930 // try to map it in shared
931 int r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, slidep
);
933 if(NULL
!= slidep
&& 0 != *slidep
) {
934 // update with actual load addresses
936 this->setNeverUnload();
937 if ( context
.verboseMapping
) {
938 dyld::log("dyld: Mapping split-seg shared %s\n", this->getPath());
939 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
940 Segment
* seg
= &fSegmentsArray
[segIndex
];
941 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
942 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
943 dyld::log("%18s at 0x%08lX->0x%08lX\n",
944 seg
->getName(), seg
->getActualLoadAddress(this), seg
->getActualLoadAddress(this)+seg
->getFileSize()-1);
945 if ( entryIndex
< (mappingTableCount
-1) ) {
946 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
947 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
948 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
949 dyld::log("%18s at 0x%08lX->0x%08lX\n",
950 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress(this) + segOffset
), (uintptr_t)(seg
->getActualLoadAddress(this) + segOffset
+ nextEntry
->size
- 1));
962 ImageLoaderMachO::sharedRegionMapFilePrivate(int fd
,
963 uint64_t offsetInFat
,
966 const LinkContext
& context
,
969 const unsigned int segmentCount
= fSegmentsArrayCount
;
971 // build table of segments to map
972 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
973 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
974 _shared_region_mapping_np mappingTable
[mappingTableCount
];
975 initMappingTable(offsetInFat
, mappingTable
);
978 // try map it in privately (don't allow sliding if we pre-calculated the load address to pack dylibs)
981 r
= _shared_region_map_file_with_mmap(fd
, mappingTableCount
, mappingTable
);
983 r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, &slide
);
986 slide
= (slide
) & (-4096); // round down to page boundary
987 this->setSlide(slide
);
989 this->setNeverUnload();
990 if ( context
.verboseMapping
) {
992 dyld::log("dyld: Mapping split-seg un-shared %s\n", this->getPath());
994 dyld::log("dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide
, this->getPath());
995 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
996 Segment
* seg
= &fSegmentsArray
[segIndex
];
997 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
998 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
999 dyld::log("%18s at 0x%08lX->0x%08lX\n",
1000 seg
->getName(), seg
->getActualLoadAddress(this), seg
->getActualLoadAddress(this)+seg
->getFileSize()-1);
1001 if ( entryIndex
< (mappingTableCount
-1) ) {
1002 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
1003 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
1004 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
1005 dyld::log("%18s at 0x%08lX->0x%08lX (zerofill)\n",
1006 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress(this) + segOffset
), (uintptr_t)(seg
->getActualLoadAddress(this) + segOffset
+ nextEntry
->size
- 1));
1014 dyld::throwf("can't rebase split-seg dylib %s because shared_region_map_file_np() returned %d", this->getPath(), r
);
1020 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
1021 sf_mapping
*mappingTable
,
1022 uintptr_t baseAddress
)
1024 unsigned int segmentCount
= fSegmentsArrayCount
;
1025 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
1026 Segment
* seg
= &fSegmentsArray
[segIndex
];
1027 sf_mapping
* entry
= &mappingTable
[entryIndex
];
1028 entry
->mapping_offset
= seg
->getPreferredLoadAddress() - baseAddress
;
1029 entry
->size
= seg
->getFileSize();
1030 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
1031 entry
->protection
= VM_PROT_NONE
;
1032 if ( !seg
->unaccessible() ) {
1033 if ( seg
->executable() )
1034 entry
->protection
|= VM_PROT_EXECUTE
;
1035 if ( seg
->readable() )
1036 entry
->protection
|= VM_PROT_READ
;
1037 if ( seg
->writeable() )
1038 entry
->protection
|= VM_PROT_WRITE
| VM_PROT_COW
;
1042 if ( seg
->hasTrailingZeroFill() ) {
1043 sf_mapping
* zfentry
= &mappingTable
[++entryIndex
];
1044 zfentry
->mapping_offset
= entry
->mapping_offset
+ seg
->getFileSize();
1045 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
1046 zfentry
->file_offset
= 0;
1047 zfentry
->protection
= entry
->protection
| VM_PROT_COW
| VM_PROT_ZF
;
1053 #endif // SPLIT_SEG_SHARED_REGION_SUPPORT
1057 void ImageLoaderMachO::setSlide(intptr_t slide
)
1062 void ImageLoaderMachO::parseLoadCmds()
1064 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
1065 for (ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
1067 // set up pointer to __LINKEDIT segment
1068 if ( strcmp(seg
->getName(),"__LINKEDIT") == 0 )
1069 fLinkEditBase
= (uint8_t*)(seg
->getActualLoadAddress(this) - seg
->getFileOffset());
1070 #if TEXT_RELOC_SUPPORT
1071 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
1072 if ( strcmp(seg
->getName(),"__TEXT") == 0 ) {
1073 if ( ((SegmentMachO
*)seg
)->hasFixUps() )
1074 fTextSegmentWithFixups
= (SegmentMachO
*)seg
;
1078 if ( seg
->readOnlyImportStubs() )
1079 fReadOnlyImportSegment
= (SegmentMachO
*)seg
;
1081 // some segment always starts at beginning of file and contains mach_header and load commands
1082 if ( (seg
->getFileOffset() == 0) && (seg
->getFileSize() != 0) ) {
1083 fMachOData
= (uint8_t*)(seg
->getActualLoadAddress(this));
1086 // in 10.5 to support images that span 4GB (including pagezero) switch meaning of r_address
1087 if ( ((seg
->getPreferredLoadAddress() + seg
->getSize() - fSegmentsArray
[0].getPreferredLoadAddress()) > 0x100000000)
1088 && seg
->writeable() )
1089 f4GBWritable
= true;
1093 // keep count of prebound images with weak exports
1094 if ( this->hasCoalescedExports() )
1095 ++fgCountOfImagesWithWeakExports
;
1097 // keep count of images used in shared cache
1098 if ( fInSharedCache
)
1099 ++fgImagesUsedFromSharedCache
;
1101 // walk load commands (mapped in at start of __TEXT segment)
1102 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1103 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1104 const struct load_command
* cmd
= cmds
;
1105 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1109 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
1110 fStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
1111 fSymbolTable
= (struct macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
1115 fDynamicInfo
= (struct dysymtab_command
*)cmd
;
1117 case LC_SUB_UMBRELLA
:
1118 fHasSubUmbrella
= true;
1120 case LC_SUB_FRAMEWORK
:
1123 case LC_SUB_LIBRARY
:
1124 fHasSubLibraries
= true;
1126 case LC_ROUTINES_COMMAND
:
1127 fHasDashInit
= true;
1129 case LC_SEGMENT_COMMAND
:
1131 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1132 #if IMAGE_NOTIFY_SUPPORT
1133 const bool isDataSeg
= (strcmp(seg
->segname
, "__DATA") == 0);
1135 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1136 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1137 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1138 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1139 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
1140 fHasInitializers
= true;
1141 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
1142 fHasTerminators
= true;
1143 else if ( type
== S_DTRACE_DOF
)
1144 fHasDOFSections
= true;
1145 #if IMAGE_NOTIFY_SUPPORT
1146 else if ( isDataSeg
&& (strcmp(sect
->sectname
, "__image_notify") == 0) )
1147 fHasImageNotifySection
= true;
1152 case LC_TWOLEVEL_HINTS
:
1153 fTwoLevelHints
= (struct twolevel_hints_command
*)cmd
;
1157 fDylibID
= (struct dylib_command
*)cmd
;
1161 case LC_LOAD_WEAK_DYLIB
:
1162 case LC_REEXPORT_DYLIB
:
1163 // do nothing, just prevent LC_REQ_DYLD exception from occuring
1166 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 )
1167 dyld::throwf("unknown required load command 0x%08X", cmd
->cmd
);
1169 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1176 const char* ImageLoaderMachO::getInstallPath() const
1178 if ( fDylibID
!= NULL
) {
1179 return (char*)fDylibID
+ fDylibID
->dylib
.name
.offset
;
1184 // test if this image is re-exported through parent (the image that loaded this one)
1185 bool ImageLoaderMachO::isSubframeworkOf(const LinkContext
& context
, const ImageLoader
* parent
) const
1187 if ( fInUmbrella
) {
1188 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1189 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1190 const struct load_command
* cmd
= cmds
;
1191 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1192 if (cmd
->cmd
== LC_SUB_FRAMEWORK
) {
1193 const struct sub_framework_command
* subf
= (struct sub_framework_command
*)cmd
;
1194 const char* exportThruName
= (char*)cmd
+ subf
->umbrella
.offset
;
1195 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
1196 const char* parentInstallPath
= parent
->getInstallPath();
1197 if ( parentInstallPath
!= NULL
) {
1198 const char* lastSlash
= strrchr(parentInstallPath
, '/');
1199 if ( lastSlash
!= NULL
) {
1200 if ( strcmp(&lastSlash
[1], exportThruName
) == 0 )
1202 if ( context
.imageSuffix
!= NULL
) {
1203 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1204 char reexportAndSuffix
[strlen(context
.imageSuffix
)+strlen(exportThruName
)+1];
1205 strcpy(reexportAndSuffix
, exportThruName
);
1206 strcat(reexportAndSuffix
, context
.imageSuffix
);
1207 if ( strcmp(&lastSlash
[1], reexportAndSuffix
) == 0 )
1213 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1219 // test if child is re-exported
1220 bool ImageLoaderMachO::hasSubLibrary(const LinkContext
& context
, const ImageLoader
* child
) const
1222 if ( fHasSubLibraries
) {
1223 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
1224 const char* childInstallPath
= child
->getInstallPath();
1225 if ( childInstallPath
!= NULL
) {
1226 const char* lastSlash
= strrchr(childInstallPath
, '/');
1227 if ( lastSlash
!= NULL
) {
1228 const char* firstDot
= strchr(lastSlash
, '.');
1230 if ( firstDot
== NULL
)
1231 len
= strlen(lastSlash
);
1233 len
= firstDot
-lastSlash
-1;
1234 char childLeafName
[len
+1];
1235 strncpy(childLeafName
, &lastSlash
[1], len
);
1236 childLeafName
[len
] = '\0';
1237 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1238 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1239 const struct load_command
* cmd
= cmds
;
1240 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1242 case LC_SUB_LIBRARY
:
1244 const struct sub_library_command
* lib
= (struct sub_library_command
*)cmd
;
1245 const char* aSubLibName
= (char*)cmd
+ lib
->sub_library
.offset
;
1246 if ( strcmp(aSubLibName
, childLeafName
) == 0 )
1248 if ( context
.imageSuffix
!= NULL
) {
1249 // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
1250 char aSubLibNameAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubLibName
)+1];
1251 strcpy(aSubLibNameAndSuffix
, aSubLibName
);
1252 strcat(aSubLibNameAndSuffix
, context
.imageSuffix
);
1253 if ( strcmp(aSubLibNameAndSuffix
, childLeafName
) == 0 )
1259 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1264 if ( fHasSubUmbrella
) {
1265 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
1266 const char* childInstallPath
= child
->getInstallPath();
1267 if ( childInstallPath
!= NULL
) {
1268 const char* lastSlash
= strrchr(childInstallPath
, '/');
1269 if ( lastSlash
!= NULL
) {
1270 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1271 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1272 const struct load_command
* cmd
= cmds
;
1273 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1275 case LC_SUB_UMBRELLA
:
1277 const struct sub_umbrella_command
* um
= (struct sub_umbrella_command
*)cmd
;
1278 const char* aSubUmbrellaName
= (char*)cmd
+ um
->sub_umbrella
.offset
;
1279 if ( strcmp(aSubUmbrellaName
, &lastSlash
[1]) == 0 )
1281 if ( context
.imageSuffix
!= NULL
) {
1282 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1283 char umbrellaAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubUmbrellaName
)+1];
1284 strcpy(umbrellaAndSuffix
, aSubUmbrellaName
);
1285 strcat(umbrellaAndSuffix
, context
.imageSuffix
);
1286 if ( strcmp(umbrellaAndSuffix
, &lastSlash
[1]) == 0 )
1292 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1302 void* ImageLoaderMachO::getMain() const
1304 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1305 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1306 const struct load_command
* cmd
= cmds
;
1307 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1312 const ppc_thread_state_t
* registers
= (ppc_thread_state_t
*)(((char*)cmd
) + 16);
1313 return (void*)(registers
->srr0
+ fSlide
);
1315 const ppc_thread_state64_t
* registers
= (ppc_thread_state64_t
*)(((char*)cmd
) + 16);
1316 return (void*)(registers
->srr0
+ fSlide
);
1318 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
1319 return (void*)(registers
->eip
+ fSlide
);
1321 const x86_thread_state64_t
* registers
= (x86_thread_state64_t
*)(((char*)cmd
) + 16);
1322 return (void*)(registers
->rip
+ fSlide
);
1324 #warning need processor specific code
1329 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1335 uint32_t ImageLoaderMachO::doGetDependentLibraryCount()
1337 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1338 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1340 const struct load_command
* cmd
= cmds
;
1341 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1344 case LC_LOAD_WEAK_DYLIB
:
1345 case LC_REEXPORT_DYLIB
:
1349 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1354 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[])
1357 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1358 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1359 const struct load_command
* cmd
= cmds
;
1360 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1363 case LC_LOAD_WEAK_DYLIB
:
1364 case LC_REEXPORT_DYLIB
:
1366 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
1367 DependentLibraryInfo
* lib
= &libs
[index
++];
1368 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
1369 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1370 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
1371 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
1372 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
1373 lib
->required
= (cmd
->cmd
!= LC_LOAD_WEAK_DYLIB
);
1374 lib
->reExported
= (cmd
->cmd
== LC_REEXPORT_DYLIB
);
1378 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1382 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo()
1385 if ( fDylibID
!= NULL
) {
1386 info
.minVersion
= fDylibID
->dylib
.compatibility_version
;
1387 info
.maxVersion
= fDylibID
->dylib
.current_version
;
1388 info
.checksum
= fDylibID
->dylib
.timestamp
;
1391 info
.minVersion
= 0;
1392 info
.maxVersion
= 0;
1398 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const
1400 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1401 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1402 const struct load_command
* cmd
= cmds
;
1403 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1406 const char* path
= (char*)cmd
+ ((struct rpath_command
*)cmd
)->path
.offset
;
1407 if ( strncmp(path
, "@loader_path/", 13) == 0 ) {
1408 if ( issetugid() && (context
.mainExecutable
== this) ) {
1409 dyld::warn("LC_RPATH %s in %s being ignored in setuid program because of @loader_path\n", path
, this->getPath());
1412 char resolvedPath
[PATH_MAX
];
1413 if ( realpath(this->getPath(), resolvedPath
) != NULL
) {
1414 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1415 strcpy(newRealPath
, resolvedPath
);
1416 char* addPoint
= strrchr(newRealPath
,'/');
1417 if ( addPoint
!= NULL
)
1418 strcpy(&addPoint
[1], &path
[13]);
1420 strcpy(newRealPath
, &path
[13]);
1421 path
= strdup(newRealPath
);
1424 else if ( strncmp(path
, "@executable_path/", 17) == 0 ) {
1425 if ( issetugid() ) {
1426 dyld::warn("LC_RPATH %s in %s being ignored in setuid program because of @executable_path\n", path
, this->getPath());
1429 char resolvedPath
[PATH_MAX
];
1430 if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL
) {
1431 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1432 strcpy(newRealPath
, resolvedPath
);
1433 char* addPoint
= strrchr(newRealPath
,'/');
1434 if ( addPoint
!= NULL
)
1435 strcpy(&addPoint
[1], &path
[17]);
1437 strcpy(newRealPath
, &path
[17]);
1438 path
= strdup(newRealPath
);
1441 else if ( (path
[0] != '/') && issetugid() ) {
1442 dyld::warn("LC_RPATH %s in %s being ignored in setuid program because it is a relative path\n", path
, this->getPath());
1446 // make copy so that all elements of 'paths' can be freed
1447 path
= strdup(path
);
1449 paths
.push_back(path
);
1452 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1456 uintptr_t ImageLoaderMachO::getFirstWritableSegmentAddress()
1458 // in split segment libraries r_address is offset from first writable segment
1459 for(ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
1461 if ( seg
->writeable() )
1462 return seg
->getActualLoadAddress(this);
1464 throw "no writable segment";
1467 uintptr_t ImageLoaderMachO::getRelocBase()
1469 // r_address is either an offset from the first segment address
1470 // or from the first writable segment address
1471 #if __ppc__ || __i386__
1473 return getFirstWritableSegmentAddress();
1475 return fSegmentsArray
[0].getActualLoadAddress(this);
1478 return getFirstWritableSegmentAddress();
1480 return fSegmentsArray
[0].getActualLoadAddress(this);
1482 return getFirstWritableSegmentAddress();
1488 static inline void otherRelocsPPC(uintptr_t* locationToFix
, uint8_t relocationType
, uint16_t otherHalf
, uintptr_t slide
)
1490 // low 16 bits of 32-bit ppc instructions need fixing
1491 struct ppcInstruction
{ uint16_t opcode
; int16_t immediateValue
; };
1492 ppcInstruction
* instruction
= (ppcInstruction
*)locationToFix
;
1493 //uint32_t before = *((uint32_t*)locationToFix);
1494 switch ( relocationType
)
1496 case PPC_RELOC_LO16
:
1497 instruction
->immediateValue
= ((otherHalf
<< 16) | instruction
->immediateValue
) + slide
;
1499 case PPC_RELOC_HI16
:
1500 instruction
->immediateValue
= ((((instruction
->immediateValue
<< 16) | otherHalf
) + slide
) >> 16);
1502 case PPC_RELOC_HA16
:
1503 int16_t signedOtherHalf
= (int16_t)(otherHalf
& 0xffff);
1504 uint32_t temp
= (instruction
->immediateValue
<< 16) + signedOtherHalf
+ slide
;
1505 if ( (temp
& 0x00008000) != 0 )
1507 instruction
->immediateValue
= temp
>> 16;
1509 //uint32_t after = *((uint32_t*)locationToFix);
1510 //dyld::log("dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
1514 #if __ppc__ || __i386__
1515 void ImageLoaderMachO::resetPreboundLazyPointers(const LinkContext
& context
, uintptr_t relocBase
)
1517 // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
1518 register const uintptr_t slide
= this->fSlide
;
1519 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]);
1520 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nlocrel
];
1521 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1522 if ( (reloc
->r_address
& R_SCATTERED
) != 0 ) {
1523 const struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
1524 if (sreloc
->r_length
== RELOC_SIZE
) {
1525 uintptr_t* locationToFix
= (uintptr_t*)(sreloc
->r_address
+ relocBase
);
1526 switch(sreloc
->r_type
) {
1528 case PPC_RELOC_PB_LA_PTR
:
1529 *locationToFix
= sreloc
->r_value
+ slide
;
1533 case GENERIC_RELOC_PB_LA_PTR
:
1534 *locationToFix
= sreloc
->r_value
+ slide
;
1544 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1546 // if prebound and loaded at prebound address, then no need to rebase
1547 if ( this->usablePrebinding(context
) ) {
1548 // skip rebasing because prebinding is valid
1549 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1553 // print why prebinding was not used
1554 if ( context
.verbosePrebinding
) {
1555 if ( !this->isPrebindable() ) {
1556 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1558 else if ( fSlide
!= 0 ) {
1559 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1561 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1562 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1564 else if ( !this->usesTwoLevelNameSpace() ){
1565 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1568 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1572 // cache values that are used in the following loop
1573 const uintptr_t relocBase
= this->getRelocBase();
1574 register const uintptr_t slide
= this->fSlide
;
1576 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1578 #if __ppc__ || __i386__
1579 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1580 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1581 if ( this->isPrebindable() && !fInSharedCache
)
1582 this->resetPreboundLazyPointers(context
, relocBase
);
1585 // if in shared cache and got here, then we depend on something not in the shared cache
1586 if ( fInSharedCache
)
1587 context
.notifySharedCacheInvalid();
1589 // if loaded at preferred address, no rebasing necessary
1593 #if TEXT_RELOC_SUPPORT
1594 // if there are __TEXT fixups, temporarily make __TEXT writable
1595 if ( fTextSegmentWithFixups
!= NULL
)
1596 fTextSegmentWithFixups
->tempWritable(context
, this);
1598 // loop through all local (internal) relocation records
1599 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]);
1600 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nlocrel
];
1601 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1602 #if LINKEDIT_USAGE_DEBUG
1603 noteAccessedLinkEditAddress(reloc
);
1606 // only one kind of local relocation supported for x86_64
1607 if ( reloc
->r_length
!= 3 )
1608 throw "bad local relocation length";
1609 if ( reloc
->r_type
!= X86_64_RELOC_UNSIGNED
)
1610 throw "unknown local relocation type";
1611 if ( reloc
->r_pcrel
!= 0 )
1612 throw "bad local relocation pc_rel";
1613 if ( reloc
->r_extern
!= 0 )
1614 throw "extern relocation found with local relocations";
1615 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1617 if ( (reloc
->r_address
& R_SCATTERED
) == 0 ) {
1618 if ( reloc
->r_symbolnum
== R_ABS
) {
1619 // ignore absolute relocations
1621 else if (reloc
->r_length
== RELOC_SIZE
) {
1622 switch(reloc
->r_type
) {
1623 case GENERIC_RELOC_VANILLA
:
1624 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1627 case PPC_RELOC_HI16
:
1628 case PPC_RELOC_LO16
:
1629 case PPC_RELOC_HA16
:
1630 // some tools leave object file relocations in linked images
1631 otherRelocsPPC((uintptr_t*)(reloc
->r_address
+ relocBase
), reloc
->r_type
, reloc
[1].r_address
, slide
);
1632 ++reloc
; // these relocations come in pairs, skip next
1636 throw "unknown local relocation type";
1640 throw "bad local relocation length";
1644 const struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
1645 if (sreloc
->r_length
== RELOC_SIZE
) {
1646 uintptr_t* locationToFix
= (uintptr_t*)(sreloc
->r_address
+ relocBase
);
1647 switch(sreloc
->r_type
) {
1648 case GENERIC_RELOC_VANILLA
:
1649 *locationToFix
+= slide
;
1652 case PPC_RELOC_HI16
:
1653 case PPC_RELOC_LO16
:
1654 case PPC_RELOC_HA16
:
1655 // Metrowerks compiler sometimes leaves object file relocations in linked images???
1656 ++reloc
; // these relocations come in pairs, get next one
1657 otherRelocsPPC(locationToFix
, sreloc
->r_type
, reloc
->r_address
, slide
);
1659 case PPC_RELOC_PB_LA_PTR
:
1663 case PPC_RELOC_PB_LA_PTR
:
1664 // needed for compatibility with ppc64 binaries built with the first ld64
1665 // which used PPC_RELOC_PB_LA_PTR relocs instead of GENERIC_RELOC_VANILLA for lazy pointers
1666 *locationToFix
+= slide
;
1669 case GENERIC_RELOC_PB_LA_PTR
:
1674 throw "unknown local scattered relocation type";
1678 throw "bad local scattered relocation length";
1684 #if TEXT_RELOC_SUPPORT
1685 // if there were __TEXT fixups, restore write protection
1686 if ( fTextSegmentWithFixups
!= NULL
) {
1687 fTextSegmentWithFixups
->setPermissions(context
,this);
1688 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(this), fTextSegmentWithFixups
->getSize());
1692 fgTotalRebaseFixups
+= fDynamicInfo
->nlocrel
;
1696 const struct macho_nlist
* ImageLoaderMachO::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],
1697 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
) const
1699 int32_t high
= symbolCount
-1;
1700 int32_t mid
= hintIndex
;
1702 // handle out of range hint
1703 if ( mid
>= (int32_t)symbolCount
) {
1704 mid
= symbolCount
/2;
1705 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1708 ++ImageLoaderMachO::fgHintedBinaryTreeSearchs
;
1710 ++fgTotalBindImageSearches
;
1712 //dyld::log("dyld: binarySearchWithToc for %s in %s\n", key, this->getShortName());
1714 for (int32_t low
= 0; low
<= high
; mid
= (low
+high
)/2) {
1715 const uint32_t index
= toc
[mid
].symbol_index
;
1716 const struct macho_nlist
* pivot
= &symbols
[index
];
1717 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1718 #if LINKEDIT_USAGE_DEBUG
1719 noteAccessedLinkEditAddress(&toc
[mid
]);
1720 noteAccessedLinkEditAddress(pivot
);
1721 noteAccessedLinkEditAddress(pivotStr
);
1723 int cmp
= astrcmp(key
, pivotStr
);
1738 const struct macho_nlist
* ImageLoaderMachO::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
) const
1741 ++fgTotalBindImageSearches
;
1742 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1744 //dyld::log("dyld: binarySearch for %s in %s, stringpool=%p, symbols=%p, symbolCount=%u\n",
1745 // key, this->getShortName(), stringPool, symbols, symbolCount);
1747 const struct macho_nlist
* base
= symbols
;
1748 for (uint32_t n
= symbolCount
; n
> 0; n
/= 2) {
1749 const struct macho_nlist
* pivot
= &base
[n
/2];
1750 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1751 #if LINKEDIT_USAGE_DEBUG
1752 noteAccessedLinkEditAddress(pivot
);
1753 noteAccessedLinkEditAddress(pivotStr
);
1755 int cmp
= astrcmp(key
, pivotStr
);
1760 // move base to symbol after pivot
1772 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, const void* hint
, bool searchReExports
, const ImageLoader
** foundIn
) const
1774 const struct macho_nlist
* sym
= NULL
;
1775 const struct twolevel_hint
* theHint
= (struct twolevel_hint
*)hint
;
1776 if ( fDynamicInfo
->tocoff
== 0 )
1777 sym
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
);
1779 uint32_t start
= fDynamicInfo
->nextdefsym
;
1780 if ( theHint
!= NULL
)
1781 start
= theHint
->itoc
;
1782 if ( (theHint
== NULL
) || (theHint
->isub_image
== 0) ) {
1783 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1784 fDynamicInfo
->ntoc
, start
);
1787 if ( sym
!= NULL
) {
1788 if ( foundIn
!= NULL
)
1789 *foundIn
= (ImageLoader
*)this;
1791 return (const Symbol
*)sym
;
1794 if ( searchReExports
) {
1795 // hint might tell us to try a particular subimage
1796 if ( (theHint
!= NULL
) && (theHint
->isub_image
> 0) && (theHint
->isub_image
<= fLibrariesCount
) ) {
1797 // isub_image is an index into a list that is sorted non-rexported images first
1799 ImageLoader
* target
= NULL
;
1800 // pass one, only look at sub-frameworks
1801 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1802 DependentLibrary
& libInfo
= fLibraries
[i
];
1803 if ( libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
)) {
1804 if ( ++index
== theHint
->isub_image
) {
1805 target
= libInfo
.image
;
1810 if (target
!= NULL
) {
1811 // pass two, only look at non-sub-framework-reexports
1812 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1813 DependentLibrary
& libInfo
= fLibraries
[i
];
1814 if ( libInfo
.isReExported
&& !libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
) ) {
1815 if ( ++index
== theHint
->isub_image
) {
1816 target
= libInfo
.image
;
1822 if (target
!= NULL
) {
1823 const Symbol
* result
= target
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1824 if ( result
!= NULL
)
1829 // hint failed, try all sub images
1830 // pass one, only look at sub-frameworks
1831 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1832 DependentLibrary
& libInfo
= fLibraries
[i
];
1833 if ( (libInfo
.image
!= NULL
) && libInfo
.isSubFramework
) {
1834 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1835 if ( result
!= NULL
)
1839 // pass two, only look at non-sub-framework-reexports
1840 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1841 DependentLibrary
& libInfo
= fLibraries
[i
];
1842 if ( (libInfo
.image
!= NULL
) && libInfo
.isReExported
&& !libInfo
.isSubFramework
) {
1843 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1844 if ( result
!= NULL
)
1850 // last change: the hint is wrong (non-zero but actually in this image)
1851 if ( (theHint
!= NULL
) && (theHint
->isub_image
!= 0) ) {
1852 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1853 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
);
1854 if ( sym
!= NULL
) {
1855 if ( foundIn
!= NULL
)
1856 *foundIn
= (ImageLoader
*)this;
1857 return (const Symbol
*)sym
;
1868 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
, const ImageLoader
* requestor
) const
1870 return this->getSymbolAddress((const struct macho_nlist
*)sym
, requestor
, context
);
1873 uintptr_t ImageLoaderMachO::getSymbolAddress(const struct macho_nlist
* sym
, const ImageLoader
* requestor
, const LinkContext
& context
) const
1875 uintptr_t result
= sym
->n_value
+ fSlide
;
1879 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1881 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1882 if ( (nlistSym
->n_desc
& N_WEAK_DEF
) != 0 )
1883 return kWeakDefinition
;
1884 return kNoDefinitionOptions
;
1887 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1889 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1890 return &fStrings
[nlistSym
->n_un
.n_strx
];
1893 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1895 return fDynamicInfo
->nextdefsym
;
1899 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1901 if ( index
< fDynamicInfo
->nextdefsym
) {
1902 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iextdefsym
+ index
];
1903 return (const ImageLoader::Symbol
*)sym
;
1909 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1911 return fDynamicInfo
->nundefsym
;
1915 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1917 if ( index
< fDynamicInfo
->nundefsym
) {
1918 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iundefsym
+ index
];
1919 return (const ImageLoader::Symbol
*)sym
;
1925 ImageLoader::ReferenceFlags
ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1927 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1928 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1929 if ( ((nlistSym
->n_type
& N_TYPE
) == N_UNDF
) && (nlistSym
->n_value
!= 0) )
1930 flags
|= ImageLoader::kTentativeDefinition
;
1931 if ( (nlistSym
->n_desc
& N_WEAK_REF
) != 0 )
1932 flags
|= ImageLoader::kWeakReference
;
1937 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1939 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1940 return &fStrings
[nlistSym
->n_un
.n_strx
];
1944 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1946 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1947 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1948 const struct load_command
* cmd
= cmds
;
1949 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1951 case LC_SEGMENT_COMMAND
:
1953 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1954 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1955 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1956 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1957 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1958 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1959 *length
= sect
->size
;
1966 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1972 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1974 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1975 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1976 const struct load_command
* cmd
= cmds
;
1977 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1978 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1980 case LC_SEGMENT_COMMAND
:
1982 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1983 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1984 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1985 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1986 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1987 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1988 if ( segmentName
!= NULL
)
1989 *segmentName
= sect
->segname
;
1990 if ( sectionName
!= NULL
)
1991 *sectionName
= sect
->sectname
;
1992 if ( sectionOffset
!= NULL
)
1993 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
2001 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2007 bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist
* symbol
)
2009 // if a define and weak ==> coalesced
2010 if ( ((symbol
->n_type
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc
& N_WEAK_DEF
) != 0) )
2012 // if an undefine and not referencing a weak symbol ==> coalesced
2013 if ( ((symbol
->n_type
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc
& N_REF_TO_WEAK
) != 0) )
2021 static void __attribute__((noreturn
)) throwSymbolNotFound(const char* symbol
, const char* referencedFrom
, const char* expectedIn
)
2023 dyld::throwf("Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n", symbol
, referencedFrom
, expectedIn
);
2026 uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
, bool twoLevel
, const ImageLoader
** foundIn
)
2028 ++fgTotalBindSymbolsResolved
;
2029 const char* symbolName
= &fStrings
[undefinedSymbol
->n_un
.n_strx
];
2031 #if LINKEDIT_USAGE_DEBUG
2032 noteAccessedLinkEditAddress(undefinedSymbol
);
2033 noteAccessedLinkEditAddress(symbolName
);
2035 if ( context
.bindFlat
|| !twoLevel
) {
2037 if ( ((undefinedSymbol
->n_type
& N_PEXT
) != 0) && ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) ) {
2038 // is a multi-module private_extern internal reference that the linker did not optimize away
2039 uintptr_t addr
= this->getSymbolAddress(undefinedSymbol
, this, context
);
2044 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) ) {
2045 if ( (*foundIn
!= this) && !(*foundIn
)->neverUnload() )
2046 this->addDynamicReference(*foundIn
);
2047 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
2049 // if a bundle is loaded privately the above will not find its exports
2050 if ( this->isBundle() && this->hasHiddenExports() ) {
2051 // look in self for needed symbol
2052 sym
= this->findExportedSymbol(symbolName
, NULL
, false, foundIn
);
2054 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
2056 if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
2057 // definition can't be found anywhere
2058 // if reference is weak_import, then it is ok, just return 0
2061 throwSymbolNotFound(symbolName
, this->getPath(), "flat namespace");
2064 // symbol requires searching images with coalesced symbols (not done during prebinding)
2065 if ( !context
.prebinding
&& this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol
) ) {
2067 if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) ) {
2068 if ( (*foundIn
!= this) && !(*foundIn
)->neverUnload() )
2069 this->addDynamicReference(*foundIn
);
2070 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
2072 //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace");
2073 //dyld::log("dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
2076 // if this is a real definition (not an undefined symbol) there is no ordinal
2077 if ( (undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) {
2078 // static linker should never generate this case, but if it does, do something sane
2079 uintptr_t addr
= this->getSymbolAddress(undefinedSymbol
, this, context
);
2086 ImageLoader
* target
= NULL
;
2087 uint8_t ord
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
);
2088 if ( ord
== EXECUTABLE_ORDINAL
) {
2089 target
= context
.mainExecutable
;
2091 else if ( ord
== SELF_LIBRARY_ORDINAL
) {
2094 else if ( ord
== DYNAMIC_LOOKUP_ORDINAL
) {
2095 // rnielsen: HACKHACK
2098 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
2099 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
2100 // no image has exports this symbol
2101 // either report error or hope ZeroLink can just-in-time load an image
2102 context
.undefinedHandler(symbolName
);
2103 // try looking again
2104 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
2105 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
2107 throwSymbolNotFound(symbolName
, this->getPath(), "dynamic lookup");
2109 else if ( ord
<= fLibrariesCount
) {
2110 DependentLibrary
& libInfo
= fLibraries
[ord
-1];
2111 target
= libInfo
.image
;
2112 if ( (target
== NULL
) && (((undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0) || !libInfo
.required
) ) {
2113 // if target library not loaded and reference is weak or library is weak return 0
2118 dyld::throwf("bad mach-o binary, library ordinal (%u) too big (max %u) for symbol %s in %s",
2119 ord
, fLibrariesCount
, symbolName
, this->getPath());
2122 if ( target
== NULL
) {
2123 //dyld::log("resolveUndefined(%s) in %s\n", symbolName, this->getPath());
2124 throw "symbol not found";
2128 if ( fTwoLevelHints
!= NULL
) {
2129 uint32_t symIndex
= undefinedSymbol
- fSymbolTable
;
2130 int32_t undefinedIndex
= symIndex
- fDynamicInfo
->iundefsym
;
2131 if ( (undefinedIndex
>= 0) && ((uint32_t)undefinedIndex
< fDynamicInfo
->nundefsym
) ) {
2132 const struct twolevel_hint
* hints
= (struct twolevel_hint
*)(&fLinkEditBase
[fTwoLevelHints
->offset
]);
2133 const struct twolevel_hint
* theHint
= &hints
[undefinedIndex
];
2134 hint
= (void*)theHint
;
2138 const Symbol
* sym
= target
->findExportedSymbol(symbolName
, hint
, true, foundIn
);
2140 return (*foundIn
)->getExportedSymbolAddress(sym
, context
, this);
2142 else if ( (undefinedSymbol
->n_type
& N_PEXT
) != 0 ) {
2143 // don't know why the static linker did not eliminate the internal reference to a private extern definition
2145 return this->getSymbolAddress(undefinedSymbol
, this, context
);
2147 else if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
2148 // if definition not found and reference is weak return 0
2152 // nowhere to be found
2153 throwSymbolNotFound(symbolName
, this->getPath(), target
->getPath());
2157 // returns if 'addr' is within the address range of section 'sectionIndex'
2158 // fSlide is not used. 'addr' is assumed to be a prebound address in this image
2159 bool ImageLoaderMachO::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
)
2161 uint8_t currentSectionIndex
= 1;
2162 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2163 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2164 const struct load_command
* cmd
= cmds
;
2165 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
2166 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2167 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2168 if ( (currentSectionIndex
<= sectionIndex
) && (sectionIndex
< currentSectionIndex
+seg
->nsects
) ) {
2169 // 'sectionIndex' is in this segment, get section info
2170 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2171 const struct macho_section
* const section
= §ionsStart
[sectionIndex
-currentSectionIndex
];
2172 return ( (section
->addr
<= addr
) && (addr
< section
->addr
+section
->size
) );
2175 // 'sectionIndex' not in this segment, skip to next segment
2176 currentSectionIndex
+= seg
->nsects
;
2179 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2185 void ImageLoaderMachO::doBindExternalRelocations(const LinkContext
& context
, bool onlyCoalescedSymbols
)
2187 const uintptr_t relocBase
= this->getRelocBase();
2188 const bool twoLevel
= this->usesTwoLevelNameSpace();
2189 const bool prebound
= this->isPrebindable();
2191 #if TEXT_RELOC_SUPPORT
2192 // if there are __TEXT fixups, temporarily make __TEXT writable
2193 if ( fTextSegmentWithFixups
!= NULL
)
2194 fTextSegmentWithFixups
->tempWritable(context
, this);
2196 // cache last lookup
2197 const struct macho_nlist
* lastUndefinedSymbol
= NULL
;
2198 uintptr_t symbolAddr
= 0;
2199 const ImageLoader
* image
= NULL
;
2201 // loop through all external relocation records and bind each
2202 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]);
2203 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nextrel
];
2204 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2205 if (reloc
->r_length
== RELOC_SIZE
) {
2206 switch(reloc
->r_type
) {
2209 const struct macho_nlist
* undefinedSymbol
= &fSymbolTable
[reloc
->r_symbolnum
];
2210 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
2211 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(undefinedSymbol
) )
2213 uintptr_t* location
= ((uintptr_t*)(reloc
->r_address
+ relocBase
));
2214 uintptr_t value
= *location
;
2215 bool symbolAddrCached
= true;
2217 if ( reloc
->r_pcrel
) {
2218 value
+= (uintptr_t)location
+ 4 - fSlide
;
2222 // we are doing relocations, so prebinding was not usable
2223 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
2224 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
2225 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
2226 if ( ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc
& N_WEAK_DEF
) != 0) ) {
2227 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
2228 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
2229 // that we can subtract off the weak symbol address to get the addend.
2230 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
2231 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
2232 if ( (value
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) )
2233 value
-= undefinedSymbol
->n_value
;
2238 // is undefined or non-weak symbol, so do subtraction to get addend
2239 value
-= undefinedSymbol
->n_value
;
2242 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
2243 if ( undefinedSymbol
!= lastUndefinedSymbol
) {
2244 symbolAddr
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, &image
);
2245 lastUndefinedSymbol
= undefinedSymbol
;
2246 symbolAddrCached
= false;
2248 if ( context
.verboseBind
) {
2249 const char *path
= NULL
;
2250 if ( image
!= NULL
) {
2251 path
= image
->getShortName();
2253 const char* cachedString
= "(cached)";
2254 if ( !symbolAddrCached
)
2257 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s\n",
2258 this->getShortName(), (uintptr_t)location
,
2259 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, cachedString
);
2262 dyld::log("dyld: bind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX%s + %ld\n",
2263 this->getShortName(), (uintptr_t)location
,
2264 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, cachedString
, value
);
2267 value
+= symbolAddr
;
2269 if ( reloc
->r_pcrel
) {
2270 *location
= value
- ((uintptr_t)location
+ 4);
2273 // don't dirty page if prebound value was correct
2274 if ( !prebound
|| (*location
!= value
) )
2278 // don't dirty page if prebound value was correct
2279 if ( !prebound
|| (*location
!= value
) )
2283 ++fgTotalBindFixups
;
2287 throw "unknown external relocation type";
2291 throw "bad external relocation length";
2295 #if TEXT_RELOC_SUPPORT
2296 // if there were __TEXT fixups, restore write protection
2297 if ( fTextSegmentWithFixups
!= NULL
) {
2298 fTextSegmentWithFixups
->setPermissions(context
, this);
2299 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(this), fTextSegmentWithFixups
->getSize());
2304 const mach_header
* ImageLoaderMachO::machHeader() const
2306 return (mach_header
*)fMachOData
;
2309 uintptr_t ImageLoaderMachO::getSlide() const
2314 // hmm. maybe this should be up in ImageLoader??
2315 const void* ImageLoaderMachO::getEnd() const
2317 uintptr_t lastAddress
= 0;
2318 for (ImageLoader::SegmentIterator it
= this->beginSegments(); it
!= this->endSegments(); ++it
) {
2320 uintptr_t segEnd
= seg
->getActualLoadAddress(this) + seg
->getSize();
2321 if ( segEnd
> lastAddress
)
2322 lastAddress
= segEnd
;
2324 return (const void*)lastAddress
;
2327 uintptr_t ImageLoaderMachO::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, const ImageLoader
* targetImage
, const LinkContext
& context
)
2329 if ( context
.verboseBind
) {
2330 const char* path
= NULL
;
2331 if ( targetImage
!= NULL
)
2332 path
= targetImage
->getShortName();
2333 dyld::log("dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
2334 this->getShortName(), symbolName
, (((sect
->flags
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"),
2335 path
, symbolName
, (uintptr_t)ptrToBind
, targetAddr
);
2337 if ( context
.bindingHandler
!= NULL
) {
2338 const char* path
= NULL
;
2339 if ( targetImage
!= NULL
)
2340 path
= targetImage
->getShortName();
2341 targetAddr
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
);
2344 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
2345 if ( ((sect
->flags
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2
== 5) ) {
2346 uint32_t rel32
= targetAddr
- (((uint32_t)ptrToBind
)+5);
2347 // re-write instruction in a thread-safe manner
2348 // use 8-byte compare-and-swap to alter 5-byte jump table entries
2349 // loop is required in case the extra three bytes that cover the next entry are altered by another thread
2352 volatile int64_t* jumpPtr
= (int64_t*)ptrToBind
;
2354 // By default the three extra bytes swapped follow the 5-byte JMP.
2355 // But, if the 5-byte jump is up against the end of the __IMPORT segment
2356 // We don't want to access bytes off the end of the segment, so we shift
2357 // the extra bytes to precede the 5-byte JMP.
2358 if ( (((uint32_t)ptrToBind
+ 8) & 0x00000FFC) == 0x00000000 ) {
2359 jumpPtr
= (int64_t*)((uint32_t)ptrToBind
- 3);
2362 int64_t oldEntry
= *jumpPtr
;
2367 newEntry
.int64
= oldEntry
;
2368 newEntry
.bytes
[pad
+0] = 0xE9; // JMP rel32
2369 newEntry
.bytes
[pad
+1] = rel32
& 0xFF;
2370 newEntry
.bytes
[pad
+2] = (rel32
>> 8) & 0xFF;
2371 newEntry
.bytes
[pad
+3] = (rel32
>> 16) & 0xFF;
2372 newEntry
.bytes
[pad
+4] = (rel32
>> 24) & 0xFF;
2373 done
= OSAtomicCompareAndSwap64Barrier(oldEntry
, newEntry
.int64
, (int64_t*)jumpPtr
);
2378 *ptrToBind
= targetAddr
;
2383 uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
)
2385 // scan for all non-lazy-pointer sections
2386 const bool twoLevel
= this->usesTwoLevelNameSpace();
2387 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2388 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2389 const struct load_command
* cmd
= cmds
;
2390 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2391 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2393 case LC_SEGMENT_COMMAND
:
2395 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2396 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2397 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2398 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2399 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2400 uint32_t symbolIndex
= INDIRECT_SYMBOL_LOCAL
;
2401 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2402 const uint32_t pointerCount
= sect
->size
/ sizeof(uintptr_t);
2403 uintptr_t* const symbolPointers
= (uintptr_t*)(sect
->addr
+ fSlide
);
2404 if ( (lazyPointer
>= symbolPointers
) && (lazyPointer
< &symbolPointers
[pointerCount
]) ) {
2405 const uint32_t indirectTableOffset
= sect
->reserved1
;
2406 const uint32_t lazyIndex
= lazyPointer
- symbolPointers
;
2407 symbolIndex
= indirectTable
[indirectTableOffset
+ lazyIndex
];
2411 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2412 // 5 bytes stubs on i386 are new "fast stubs"
2413 uint8_t* const jmpTableBase
= (uint8_t*)(sect
->addr
+ fSlide
);
2414 uint8_t* const jmpTableEnd
= jmpTableBase
+ sect
->size
;
2415 // initial CALL instruction in jump table leaves pointer to next entry, so back up
2416 uint8_t* const jmpTableEntryToPatch
= ((uint8_t*)lazyPointer
) - 5;
2417 lazyPointer
= (uintptr_t*)jmpTableEntryToPatch
;
2418 if ( (jmpTableEntryToPatch
>= jmpTableBase
) && (jmpTableEntryToPatch
< jmpTableEnd
) ) {
2419 const uint32_t indirectTableOffset
= sect
->reserved1
;
2420 const uint32_t entryIndex
= (jmpTableEntryToPatch
- jmpTableBase
)/5;
2421 symbolIndex
= indirectTable
[indirectTableOffset
+ entryIndex
];
2425 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
&& symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2426 const char* symbolName
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
];
2427 const ImageLoader
* image
= NULL
;
2428 uintptr_t symbolAddr
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], twoLevel
, &image
);
2430 this->makeImportSegmentWritable(context
);
2432 symbolAddr
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
, context
);
2433 ++fgTotalLazyBindFixups
;
2435 this->makeImportSegmentReadOnly(context
);
2443 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2445 dyld::throwf("lazy pointer not found at address %p in image %s", lazyPointer
, this->getPath());
2451 // For security the __IMPORT segments in the shared cache are normally not writable.
2452 // Any image can also be linked with -read_only_stubs to make their __IMPORT segments normally not writable.
2453 // For these images, dyld must change the page protection before updating them.
2454 // The spin lock is required because lazy symbol binding is done without taking the global dyld lock.
2455 // It keeps only one __IMPORT segment writable at a time.
2456 // Pre-main(), the shared cache __IMPORT segments are always writable, so we don't need to change the protection.
2458 void ImageLoaderMachO::makeImportSegmentWritable(const LinkContext
& context
)
2460 if ( fReadOnlyImportSegment
!= NULL
) {
2461 if ( fInSharedCache
) {
2462 if ( context
.startedInitializingMainExecutable
) {
2463 _spin_lock(&fgReadOnlyImportSpinLock
);
2464 context
.makeSharedCacheImportSegmentsWritable(true);
2468 _spin_lock(&fgReadOnlyImportSpinLock
);
2469 fReadOnlyImportSegment
->tempWritable(context
, this);
2474 void ImageLoaderMachO::makeImportSegmentReadOnly(const LinkContext
& context
)
2476 if ( fReadOnlyImportSegment
!= NULL
) {
2477 if ( fInSharedCache
) {
2478 if ( context
.startedInitializingMainExecutable
) {
2479 context
.makeSharedCacheImportSegmentsWritable(false);
2480 _spin_unlock(&fgReadOnlyImportSpinLock
);
2484 fReadOnlyImportSegment
->setPermissions(context
, this);
2485 _spin_unlock(&fgReadOnlyImportSpinLock
);
2491 void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext
& context
, bool bindNonLazys
, bool bindLazys
, bool onlyCoalescedSymbols
)
2494 this->makeImportSegmentWritable(context
);
2496 // scan for all non-lazy-pointer sections
2497 const bool twoLevel
= this->usesTwoLevelNameSpace();
2498 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2499 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2500 const struct load_command
* cmd
= cmds
;
2501 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2502 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2504 case LC_SEGMENT_COMMAND
:
2506 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2507 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2508 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2509 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2510 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2511 uint32_t elementSize
= sizeof(uintptr_t);
2512 uint32_t elementCount
= sect
->size
/ elementSize
;
2513 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2514 if ( ! bindNonLazys
)
2517 else if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2518 // process each symbol pointer in this section
2519 fgTotalPossibleLazyBindFixups
+= elementCount
;
2524 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2525 // process each jmp entry in this section
2526 elementCount
= sect
->size
/ 5;
2528 fgTotalPossibleLazyBindFixups
+= elementCount
;
2536 const uint32_t indirectTableOffset
= sect
->reserved1
;
2537 uint8_t* ptrToBind
= (uint8_t*)(sect
->addr
+ fSlide
);
2538 for (uint32_t j
=0; j
< elementCount
; ++j
, ptrToBind
+= elementSize
) {
2539 #if LINKEDIT_USAGE_DEBUG
2540 noteAccessedLinkEditAddress(&indirectTable
[indirectTableOffset
+ j
]);
2542 uint32_t symbolIndex
= indirectTable
[indirectTableOffset
+ j
];
2543 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2544 *((uintptr_t*)ptrToBind
) += this->fSlide
;
2546 else if ( symbolIndex
== INDIRECT_SYMBOL_ABS
) {
2547 // do nothing since already has absolute address
2550 const struct macho_nlist
* sym
= &fSymbolTable
[symbolIndex
];
2551 if ( symbolIndex
== 0 ) {
2552 // This could be rdar://problem/3534709
2553 if ( ((const macho_header
*)fMachOData
)->filetype
== MH_EXECUTE
) {
2554 static bool alreadyWarned
= false;
2555 if ( (sym
->n_type
& N_TYPE
) != N_UNDF
) {
2556 // The indirect table parallels the (non)lazy pointer sections. For
2557 // instance, to find info about the fifth lazy pointer you look at the
2558 // fifth entry in the indirect table. (try otool -Iv on a file).
2559 // The entry in the indirect table contains an index into the symbol table.
2561 // The bug in ld caused the entry in the indirect table to be zero
2562 // (instead of a magic value that means a local symbol). So, if the
2563 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
2564 // symbol table index. The check I put in place is to see if the zero'th
2565 // symbol table entry is an import entry (usually it is a local symbol
2567 if ( context
.verboseWarnings
&& !alreadyWarned
) {
2568 dyld::log("dyld: malformed executable '%s', skipping indirect symbol to %s\n",
2569 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]);
2570 alreadyWarned
= true;
2576 const ImageLoader
* image
= NULL
;
2577 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
2578 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(sym
) )
2580 uintptr_t symbolAddr
;
2581 symbolAddr
= resolveUndefined(context
, sym
, twoLevel
, &image
);
2584 symbolAddr
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
, context
);
2586 ++fgTotalBindFixups
;
2593 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2596 this->makeImportSegmentReadOnly(context
);
2600 #if SUPPORT_OLD_CRT_INITIALIZATION
2601 // first 16 bytes of "start" in crt1.o
2603 static uint32_t sStandardEntryPointInstructions
[4] = { 0x7c3a0b78, 0x3821fffc, 0x54210034, 0x38000000 };
2605 static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
2610 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
2611 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2612 // the following only exist in main executables built for 10.5 or later
2616 // These are defined in dyldStartup.s
2617 extern "C" void stub_binding_helper();
2618 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
);
2619 extern "C" void fast_stub_binding_helper_interface();
2622 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
2624 const macho_header
* mh
= (macho_header
*)fMachOData
;
2625 const uint32_t cmd_count
= mh
->ncmds
;
2626 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2627 const struct load_command
* cmd
;
2628 // set up __dyld section
2630 // 1) do nothing if image is in dyld shared cache and dyld loaded at same address as when cache built
2631 // 2) first read __dyld value, if already correct don't write, this prevents dirtying a page
2632 if ( !fInSharedCache
|| !context
.dyldLoadedAtSameAddressNeededBySharedCache
) {
2634 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2635 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2636 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2637 if ( strcmp(seg
->segname
, "__DATA") == 0 ) {
2638 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2639 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2640 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2641 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) {
2642 struct DATAdyld
* dd
= (struct DATAdyld
*)(sect
->addr
+ fSlide
);
2643 if ( sect
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
2644 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
2645 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
2647 if ( sect
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
2648 if ( dd
->dyldFuncLookup
!= (void*)&dyld_func_lookup
)
2649 dd
->dyldFuncLookup
= (void*)&dyld_func_lookup
;
2651 if ( mh
->filetype
== MH_EXECUTE
) {
2652 // there are two ways to get the program variables
2653 if ( (sect
->size
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh
== mh
) ) {
2654 // some really old binaries have space for vars, but it is zero filled
2655 // main executable has 10.5 style __dyld section that has program variable pointers
2656 context
.setNewProgramVars(dd
->vars
);
2659 // main executable is pre-10.5 and requires the symbols names to be looked up
2660 this->lookupProgramVars(context
);
2661 #if SUPPORT_OLD_CRT_INITIALIZATION
2662 // If the first 16 bytes of the entry point's instructions do not
2663 // match what crt1.o supplies, then the program has a custom entry point.
2664 // This means it might be doing something that needs to be executed before
2665 // initializers are run.
2666 if ( memcmp(this->getMain(), sStandardEntryPointInstructions
, 16) != 0 ) {
2667 if ( context
.verboseInit
)
2668 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
2669 context
.setRunInitialzersOldWay();
2678 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2682 if ( ! this->usablePrebinding(context
) ) {
2683 // reset all "fast" stubs
2684 this->makeImportSegmentWritable(context
);
2686 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2688 case LC_SEGMENT_COMMAND
:
2690 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2691 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2692 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2693 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2694 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2695 if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2696 // reset each jmp entry in this section
2697 const uint32_t indirectTableOffset
= sect
->reserved1
;
2698 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2699 uint8_t* start
= (uint8_t*)(sect
->addr
+ this->fSlide
);
2700 uint8_t* end
= start
+ sect
->size
;
2701 uintptr_t dyldHandler
= (uintptr_t)&fast_stub_binding_helper_interface
;
2702 uint32_t entryIndex
= 0;
2703 for (uint8_t* entry
= start
; entry
< end
; entry
+= 5, ++entryIndex
) {
2704 bool installLazyHandler
= true;
2705 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
2706 // if the instruction is updated by one thread while being executed by another
2707 if ( ((uint32_t)entry
& 0xFFFFFFC0) != ((uint32_t)entry
+4 & 0xFFFFFFC0) ) {
2708 // need to bind this now to avoid a potential problem if bound lazily
2709 uint32_t symbolIndex
= indirectTable
[indirectTableOffset
+ entryIndex
];
2710 // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
2711 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2712 const char* symbolName
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
];
2713 const ImageLoader
* image
= NULL
;
2715 uintptr_t symbolAddr
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], this->usesTwoLevelNameSpace(), &image
);
2716 symbolAddr
= this->bindIndirectSymbol((uintptr_t*)entry
, sect
, symbolName
, symbolAddr
, image
, context
);
2717 ++fgTotalBindFixups
;
2718 uint32_t rel32
= symbolAddr
- (((uint32_t)entry
)+5);
2719 entry
[0] = 0xE9; // JMP rel32
2720 entry
[1] = rel32
& 0xFF;
2721 entry
[2] = (rel32
>> 8) & 0xFF;
2722 entry
[3] = (rel32
>> 16) & 0xFF;
2723 entry
[4] = (rel32
>> 24) & 0xFF;
2724 installLazyHandler
= false;
2726 catch (const char* msg
) {
2727 // ignore errors when binding symbols early
2728 // maybe the function is never called, and therefore erroring out now would be a regression
2732 if ( installLazyHandler
) {
2733 uint32_t rel32
= dyldHandler
- (((uint32_t)entry
)+5);
2734 entry
[0] = 0xE8; // CALL rel32
2735 entry
[1] = rel32
& 0xFF;
2736 entry
[2] = (rel32
>> 8) & 0xFF;
2737 entry
[3] = (rel32
>> 16) & 0xFF;
2738 entry
[4] = (rel32
>> 24) & 0xFF;
2745 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2747 this->makeImportSegmentReadOnly(context
);
2753 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const
2755 ProgramVars vars
= context
.programVars
;
2756 const ImageLoader::Symbol
* sym
;
2758 // get mach header directly
2759 vars
.mh
= (macho_header
*)fMachOData
;
2762 sym
= this->findExportedSymbol("_NXArgc", NULL
, false, NULL
);
2764 vars
.NXArgcPtr
= (int*)this->getExportedSymbolAddress(sym
, context
, this);
2767 sym
= this->findExportedSymbol("_NXArgv", NULL
, false, NULL
);
2769 vars
.NXArgvPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this);
2772 sym
= this->findExportedSymbol("_environ", NULL
, false, NULL
);
2774 vars
.environPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this);
2776 // lookup __progname
2777 sym
= this->findExportedSymbol("___progname", NULL
, false, NULL
);
2779 vars
.__prognamePtr
= (const char**)this->getExportedSymbolAddress(sym
, context
, this);
2781 context
.setNewProgramVars(vars
);
2785 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
2787 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2788 if ( (this->isPrebindable() || fInSharedCache
)
2789 && (this->getSlide() == 0)
2790 && this->usesTwoLevelNameSpace()
2791 && this->allDependentLibrariesAsWhenPreBound() ) {
2792 // allow environment variables to disable prebinding
2793 if ( context
.bindFlat
)
2795 switch ( context
.prebindUsage
) {
2796 case kUseAllPrebinding
:
2798 case kUseSplitSegPrebinding
:
2799 return this->fIsSplitSeg
;
2800 case kUseAllButAppPredbinding
:
2801 return (this != context
.mainExecutable
);
2802 case kUseNoPrebinding
:
2809 void ImageLoaderMachO::doBindJustLazies(const LinkContext
& context
)
2811 // some API called requested that all lazy pointers in this image be force bound
2812 this->doBindIndirectSymbolPointers(context
, false, true, false);
2815 void ImageLoaderMachO::doBind(const LinkContext
& context
, bool forceLazysBound
)
2817 // set dyld entry points in image
2818 this->setupLazyPointerHandler(context
);
2820 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2821 // note: flat-namespace binaries need to have imports rebound (even if correctly prebound)
2822 if ( this->usablePrebinding(context
) ) {
2823 // if image has coalesced symbols, then these need to be rebound, unless this is the only image with weak symbols
2824 if ( this->needsCoalescing() && (fgCountOfImagesWithWeakExports
> 1) ) {
2825 this->doBindExternalRelocations(context
, true);
2826 this->doBindIndirectSymbolPointers(context
, true, true, true);
2829 ++fgImagesRequiringNoFixups
;
2832 // skip binding because prebound and prebinding not disabled
2836 // values bound by name are stored two different ways in mach-o:
2838 // 1) external relocations are used for data initialized to external symbols
2839 this->doBindExternalRelocations(context
, false);
2841 // 2) "indirect symbols" are used for code references to external symbols
2842 // if this image is in the shared cache, there is noway to reset the lazy pointers, so bind them now
2843 this->doBindIndirectSymbolPointers(context
, true, forceLazysBound
|| fInSharedCache
, false);
2846 void ImageLoaderMachO::doUpdateMappingPermissions(const LinkContext
& context
)
2849 if ( (fReadOnlyImportSegment
!= NULL
) && !fInSharedCache
)
2850 fReadOnlyImportSegment
->setPermissions(context
, this);
2854 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
2856 if ( fHasDashInit
) {
2857 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2858 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2859 const struct load_command
* cmd
= cmds
;
2860 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
2862 case LC_ROUTINES_COMMAND
:
2863 Initializer func
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address
+ fSlide
);
2864 if ( context
.verboseInit
)
2865 dyld::log("dyld: calling -init function 0x%p in %s\n", func
, this->getPath());
2866 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
2869 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2874 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
2876 if ( fHasInitializers
) {
2877 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2878 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2879 const struct load_command
* cmd
= cmds
;
2880 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
2881 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2882 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2883 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2884 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2885 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2886 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2887 if ( type
== S_MOD_INIT_FUNC_POINTERS
) {
2888 Initializer
* inits
= (Initializer
*)(sect
->addr
+ fSlide
);
2889 const uint32_t count
= sect
->size
/ sizeof(uintptr_t);
2890 for (uint32_t i
=0; i
< count
; ++i
) {
2891 Initializer func
= inits
[i
];
2892 if ( context
.verboseInit
)
2893 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath());
2894 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
2898 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2907 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
)
2909 if ( fHasDOFSections
) {
2910 // walk load commands (mapped in at start of __TEXT segment)
2911 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2912 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2913 const struct load_command
* cmd
= cmds
;
2914 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2916 case LC_SEGMENT_COMMAND
:
2918 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2919 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2920 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2921 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2922 if ( (sect
->flags
& SECTION_TYPE
) == S_DTRACE_DOF
) {
2923 ImageLoader::DOFInfo info
;
2924 info
.dof
= (void*)(sect
->addr
+ fSlide
);
2925 info
.imageHeader
= this->machHeader();
2926 info
.imageShortName
= this->getShortName();
2927 dofs
.push_back(info
);
2933 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2939 void ImageLoaderMachO::doInitialization(const LinkContext
& context
)
2941 // mach-o has -init and static initializers
2942 doImageInit(context
);
2943 doModInitFunctions(context
);
2946 bool ImageLoaderMachO::needsInitialization()
2948 return ( fHasDashInit
|| fHasInitializers
);
2952 bool ImageLoaderMachO::needsTermination()
2954 return fHasTerminators
;
2957 #if IMAGE_NOTIFY_SUPPORT
2958 bool ImageLoaderMachO::hasImageNotification()
2960 return fHasImageNotifySection
;
2964 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
2966 if ( fHasTerminators
) {
2967 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2968 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2969 const struct load_command
* cmd
= cmds
;
2970 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
2971 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2972 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2973 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2974 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2975 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2976 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2977 if ( type
== S_MOD_TERM_FUNC_POINTERS
) {
2978 Terminator
* terms
= (Terminator
*)(sect
->addr
+ fSlide
);
2979 const uint32_t count
= sect
->size
/ sizeof(uintptr_t);
2980 for (uint32_t i
=count
; i
> 0; --i
) {
2981 Terminator func
= terms
[i
-1];
2982 if ( context
.verboseInit
)
2983 dyld::log("dyld: calling terminaton function %p in %s\n", func
, this->getPath());
2989 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2994 #if IMAGE_NOTIFY_SUPPORT
2995 void ImageLoaderMachO::doNotification(enum dyld_image_mode mode
, uint32_t infoCount
, const struct dyld_image_info info
[])
2997 if ( fHasImageNotifySection
) {
2998 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2999 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
3000 const struct load_command
* cmd
= cmds
;
3001 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
3002 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
3003 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
3004 if ( strcmp(seg
->segname
, "__DATA") == 0 ) {
3005 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
3006 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
3007 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
3008 if ( strcmp(sect
->sectname
, "__image_notify") == 0 ) {
3009 dyld_image_notifier
* notes
= (dyld_image_notifier
*)(sect
->addr
+ fSlide
);
3010 const uint32_t count
= sect
->size
/ sizeof(uintptr_t);
3011 for (uint32_t i
=count
; i
> 0; --i
) {
3012 dyld_image_notifier func
= notes
[i
-1];
3013 func(mode
, infoCount
, info
);
3019 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
3025 void ImageLoaderMachO::printStatistics(unsigned int imageCount
)
3027 ImageLoader::printStatistics(imageCount
);
3028 //dyld::log("total hinted binary tree searches: %d\n", fgHintedBinaryTreeSearchs);
3029 //dyld::log("total unhinted binary tree searches: %d\n", fgUnhintedBinaryTreeSearchs);
3030 dyld::log("total images with weak exports: %d\n", fgCountOfImagesWithWeakExports
);
3032 #if LINKEDIT_USAGE_DEBUG
3033 dyld::log("linkedit pages accessed (%lu):\n", sLinkEditPageBuckets
.size());
3038 ImageLoader::SegmentIterator
ImageLoaderMachO::beginSegments() const
3040 return SegmentIterator(fSegmentsArray
);
3043 ImageLoader::SegmentIterator
ImageLoaderMachO::endSegments() const
3045 return SegmentIterator(&fSegmentsArray
[fSegmentsArrayCount
]);
3048 SegmentMachO::SegmentMachO(const struct macho_segment_command
* cmd
)
3049 : fSegmentLoadCommand(cmd
)
3053 SegmentMachO::~SegmentMachO()
3057 void SegmentMachO::adjust(const struct macho_segment_command
* cmd
)
3059 fSegmentLoadCommand
= cmd
;
3062 void SegmentMachO::unmap(const ImageLoader
* image
)
3065 --ImageLoader::fgTotalSegmentsMapped
;
3066 ImageLoader::fgTotalBytesMapped
-= fSegmentLoadCommand
->vmsize
;
3067 munmap((void*)(this->getActualLoadAddress(image
)), fSegmentLoadCommand
->vmsize
);
3071 const char* SegmentMachO::getName()
3073 return fSegmentLoadCommand
->segname
;
3076 uintptr_t SegmentMachO::getSize()
3078 return fSegmentLoadCommand
->vmsize
;
3081 uintptr_t SegmentMachO::getFileSize()
3083 return fSegmentLoadCommand
->filesize
;
3086 uintptr_t SegmentMachO::getFileOffset()
3088 return fSegmentLoadCommand
->fileoff
;
3091 bool SegmentMachO::readable()
3093 return ( (fSegmentLoadCommand
->initprot
& VM_PROT_READ
) != 0);
3096 bool SegmentMachO::writeable()
3098 return ((fSegmentLoadCommand
->initprot
& VM_PROT_WRITE
) != 0);
3101 bool SegmentMachO::executable()
3103 return ((fSegmentLoadCommand
->initprot
& VM_PROT_EXECUTE
) != 0);
3106 bool SegmentMachO::unaccessible()
3108 return (fSegmentLoadCommand
->initprot
== 0);
3111 #if TEXT_RELOC_SUPPORT
3112 bool SegmentMachO::hasFixUps()
3114 // scan sections for fix-up bit
3115 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)fSegmentLoadCommand
+ sizeof(struct macho_segment_command
));
3116 const struct macho_section
* const sectionsEnd
= §ionsStart
[fSegmentLoadCommand
->nsects
];
3117 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
3118 if ( (sect
->flags
& (S_ATTR_EXT_RELOC
| S_ATTR_LOC_RELOC
)) != 0 )
3126 bool SegmentMachO::readOnlyImportStubs()
3128 return ( (fSegmentLoadCommand
->initprot
& VM_PROT_EXECUTE
)
3129 && ((fSegmentLoadCommand
->initprot
& VM_PROT_WRITE
) == 0)
3130 && (strcmp(fSegmentLoadCommand
->segname
, "__IMPORT") == 0) );
3134 uintptr_t SegmentMachO::getActualLoadAddress(const ImageLoader
* inImage
)
3136 return fSegmentLoadCommand
->vmaddr
+ inImage
->getSlide();
3139 uintptr_t SegmentMachO::getPreferredLoadAddress()
3141 return fSegmentLoadCommand
->vmaddr
;
3144 bool SegmentMachO::hasPreferredLoadAddress()
3146 return (fSegmentLoadCommand
->vmaddr
!= 0);
3150 Segment
* SegmentMachO::next(Segment
* location
)
3152 return &((SegmentMachO
*)location
)[1];