1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2005 Apple Computer, 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@
27 #include <sys/types.h>
30 #include <mach/shared_memory_server.h>
31 #include <mach/mach.h>
32 #include <mach/thread_status.h>
33 #include <mach-o/loader.h>
34 #include <mach-o/reloc.h>
35 #include <mach-o/nlist.h>
36 #include <sys/sysctl.h>
37 #if __ppc__ || __ppc64__
38 #include <mach-o/ppc/reloc.h>
41 #ifndef S_ATTR_SELF_MODIFYING_CODE
42 #define S_ATTR_SELF_MODIFYING_CODE 0x04000000
45 #include "ImageLoaderMachO.h"
46 #include "mach-o/dyld_gdb.h"
48 // no header for this yet, rdar://problem/3850825
49 extern "C" void sys_icache_invalidate(void *, size_t);
51 // optimize strcmp for ppc
53 #include <ppc_intrinsics.h>
55 #define astrcmp(a,b) strcmp(a,b)
58 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
61 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
62 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
63 struct macho_header
: public mach_header_64
{};
64 struct macho_segment_command
: public segment_command_64
{};
65 struct macho_section
: public section_64
{};
66 struct macho_nlist
: public nlist_64
{};
67 struct macho_routines_command
: public routines_command_64
{};
70 #define LC_SEGMENT_COMMAND LC_SEGMENT
71 #define LC_ROUTINES_COMMAND LC_ROUTINES
72 struct macho_header
: public mach_header
{};
73 struct macho_segment_command
: public segment_command
{};
74 struct macho_section
: public section
{};
75 struct macho_nlist
: public nlist
{};
76 struct macho_routines_command
: public routines_command
{};
80 uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs
= 0;
81 uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
= 0;
82 uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports
= 0;
85 //#define LINKEDIT_USAGE_DEBUG 1
87 #if LINKEDIT_USAGE_DEBUG
89 static std::set
<uintptr_t> sLinkEditPageBuckets
;
92 extern ImageLoader
* findImageContainingAddress(const void* addr
);
95 static void noteAccessedLinkEditAddress(const void* addr
)
97 uintptr_t page
= ((uintptr_t)addr
) & (-4096);
98 sLinkEditPageBuckets
.insert(page
);
99 fprintf(stderr
, "dyld: accessing page 0x%08lX in __LINKEDIT of %s\n", page
, dyld::findImageContainingAddress(addr
)->getPath());
103 // only way to share initialization in C++
104 void ImageLoaderMachO::init()
107 fLinkEditBase
= NULL
;
113 fHasSubLibraries
= false;
114 fHasSubUmbrella
= false;
116 fModInitSection
= NULL
;
117 fModTermSection
= NULL
;
119 fImageNotifySection
= NULL
;
120 fTwoLevelHints
= NULL
;
122 fReExportThruFramework
= NULL
;
123 fTextSegmentWithFixups
= NULL
;
126 // create image by copying an in-memory mach-o file
127 ImageLoaderMachO::ImageLoaderMachO(const char* moduleName
, const struct mach_header
* mh
, uint64_t len
, const LinkContext
& context
)
128 : ImageLoader(moduleName
)
133 // temporary use this buffer until TEXT is mapped in
134 fMachOData
= (const uint8_t*)mh
;
137 this->instantiateSegments((const uint8_t*)mh
);
140 if ( mh
->filetype
!= MH_EXECUTE
)
141 ImageLoader::mapSegments((const void*)mh
, len
, context
);
143 // get pointers to interesting things
144 this->parseLoadCmds();
148 // create image by mapping in a mach-o file
149 ImageLoaderMachO::ImageLoaderMachO(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,
150 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
151 : ImageLoader(path
, offsetInFat
, info
)
156 // read load commands
157 const unsigned int dataSize
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
;
158 uint8_t buffer
[dataSize
];
159 const uint8_t* fileData
= firstPage
;
160 if ( dataSize
> 4096 ) {
161 // only read more if cmds take up more space than first page
163 memcpy(buffer
, firstPage
, 4096);
164 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096);
167 // temporary use this buffer until TEXT is mapped in
168 fMachOData
= fileData
;
170 // the meaning of many fields changes in split seg mach-o files
171 fIsSplitSeg
= ((((macho_header
*)fileData
)->flags
& MH_SPLIT_SEGS
) != 0) && (((macho_header
*)fileData
)->filetype
== MH_DYLIB
);
174 this->instantiateSegments(fileData
);
176 // map segments, except for main executable which is already mapped in by kernel
177 if ( ((macho_header
*)fileData
)->filetype
!= MH_EXECUTE
)
178 this->mapSegments(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
);
180 // get pointers to interesting things
181 this->parseLoadCmds();
184 ImageLoaderMachO::~ImageLoaderMachO()
186 // keep count of images with weak exports
187 if ( this->hasCoalescedExports() )
188 --fgCountOfImagesWithWeakExports
;
193 void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData
)
195 const uint32_t cmd_count
= ((macho_header
*)fileData
)->ncmds
;
196 const struct load_command
* const cmds
= (struct load_command
*)&fileData
[sizeof(macho_header
)];
198 // construct Segment object for each LC_SEGMENT cmd and add to list
199 const struct load_command
* cmd
= cmds
;
200 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
201 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
202 if ( (((struct macho_segment_command
*)cmd
)->vmsize
!= 0) || !fIsSplitSeg
)
203 fSegments
.push_back(new SegmentMachO((struct macho_segment_command
*)cmd
, this, fileData
));
205 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
211 bool ImageLoaderMachO::segmentsMustSlideTogether() const
216 bool ImageLoaderMachO::segmentsCanSlide() const
218 const macho_header
* mh
= (macho_header
*)fMachOData
;
219 return ( (mh
->filetype
== MH_DYLIB
) || (mh
->filetype
== MH_BUNDLE
) );
222 bool ImageLoaderMachO::isBundle() const
224 const macho_header
* mh
= (macho_header
*)fMachOData
;
225 return ( mh
->filetype
== MH_BUNDLE
);
228 bool ImageLoaderMachO::isDylib() const
230 const macho_header
* mh
= (macho_header
*)fMachOData
;
231 return ( mh
->filetype
== MH_DYLIB
);
234 bool ImageLoaderMachO::forceFlat() const
236 const macho_header
* mh
= (macho_header
*)fMachOData
;
237 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
240 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
242 const macho_header
* mh
= (macho_header
*)fMachOData
;
243 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
246 bool ImageLoaderMachO::isPrebindable() const
248 const macho_header
* mh
= (macho_header
*)fMachOData
;
249 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
252 bool ImageLoaderMachO::hasCoalescedExports() const
254 const macho_header
* mh
= (macho_header
*)fMachOData
;
255 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
258 bool ImageLoaderMachO::needsCoalescing() const
260 const macho_header
* mh
= (macho_header
*)fMachOData
;
261 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
264 #if !__LP64__ // split segs not supported for 64-bits
266 #if 1 // hack until kernel headers and glue are in system
267 struct _shared_region_mapping_np
{
268 mach_vm_address_t address
;
270 mach_vm_offset_t file_offset
;
271 vm_prot_t max_prot
; /* read/write/execute/COW/ZF */
272 vm_prot_t init_prot
; /* read/write/execute/COW/ZF */
274 struct _shared_region_range_np
{
275 mach_vm_address_t address
;
280 // Requests the kernel to map a number of regions from the fd into the
281 // shared sections address range (0x90000000-0xAFFFFFFF).
282 // If shared_region_make_private_np() has not been called by this process,
283 // the file mapped in is seen in the address space of all processes that
284 // participate in using the shared region.
285 // If shared_region_make_private_np() _has_ been called by this process,
286 // the file mapped in is only seen by this process.
287 // If the slide parameter is not NULL and then regions cannot be mapped
288 // as requested, the kernel will try to map the file in at a different
289 // address in the shared region and return the distance slid.
290 // If the mapping requesting cannot be fulfilled, returns non-zero.
292 _shared_region_map_file_np(
293 int fd
, // file descriptor to map into shared region
294 unsigned int regionCount
, // number of entres in array of regions
295 const _shared_region_mapping_np regions
[], // the array of regions to map
296 uint64_t* slide
) // the amount all regions were slid, NULL means don't attempt to slide
298 //fprintf(stderr, "%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide);
299 //for ( unsigned int i=0; i < regionCount; ++i) {
300 // fprintf(stderr, "\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size);
302 int r
= syscall(299, fd
, regionCount
, regions
, slide
);
304 // fprintf(stderr, "%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno));
307 // Called by dyld if shared_region_map_file() fails.
308 // Requests the kernel to take this process out of using the shared region.
309 // The specified ranges are created as private copies from the shared region for this process.
311 _shared_region_make_private_np(
312 unsigned int rangeCount
, // number of entres in array of msrp_range
313 const _shared_region_range_np ranges
[]) // the array of shared regions to make private
315 //fprintf(stderr, "%s(%u, %8p)\n", __func__, rangeCount, ranges);
316 int r
= syscall(300, rangeCount
, ranges
);
318 // fprintf(stderr, "%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno));
321 #define KERN_SHREG_PRIVATIZABLE 54
322 #endif // hack until kernel headers and glue are in system
324 static uintptr_t sNextAltLoadAddress
332 _shared_region_map_file_with_mmap(
333 int fd
, // file descriptor to map into shared region
334 unsigned int regionCount
, // number of entres in array of regions
335 const _shared_region_mapping_np regions
[]) // the array of regions to map
337 // map in each region
338 for(unsigned int i
=0; i
< regionCount
; ++i
) {
339 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
);
340 size_t size
= regions
[i
].size
;
341 if ( (regions
[i
].init_prot
& VM_PROT_ZF
) != 0 ) {
342 // do nothing already vm_allocate() which zero fills
346 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
347 protection
|= PROT_EXEC
;
348 if ( regions
[i
].init_prot
& VM_PROT_READ
)
349 protection
|= PROT_READ
;
350 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
351 protection
|= PROT_WRITE
;
352 off_t offset
= regions
[i
].file_offset
;
353 //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
354 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FILE
| MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
355 if ( mmapAddress
== ((void*)(-1)) )
366 hasSharedRegionMapFile(void)
368 int mib
[CTL_MAXNAME
];
373 mib
[1] = KERN_SHREG_PRIVATIZABLE
;
375 if (sysctl(mib
, 2, &value
, &size
, NULL
, 0) != 0) {
383 ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd
,
384 uint64_t offsetInFat
,
387 const LinkContext
& context
)
389 const unsigned int segmentCount
= fSegments
.size();
390 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
391 const unsigned int regionCount
= segmentCount
+extraZeroFillEntries
;
392 _shared_region_mapping_np regions
[regionCount
];
393 initMappingTable(offsetInFat
, regions
);
395 // find space somewhere to allocate split seg
396 bool foundRoom
= false;
397 vm_size_t biggestDiff
= 0;
398 while ( ! foundRoom
) {
400 for(unsigned int i
=0; i
< regionCount
; ++i
) {
401 vm_address_t addr
= sNextAltLoadAddress
+ regions
[i
].address
- regions
[0].address
;
402 vm_size_t size
= regions
[i
].size
;
403 r
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/);
405 // no room here, deallocate what has succeeded so far
406 for(unsigned int j
=0; j
< i
; ++j
) {
407 vm_address_t addr
= sNextAltLoadAddress
+ regions
[j
].address
- regions
[0].address
;
408 vm_size_t size
= regions
[j
].size
;
409 (void)vm_deallocate(mach_task_self(), addr
, size
);
411 sNextAltLoadAddress
+= 0x00100000; // skip ahead 1MB and try again
412 if ( (sNextAltLoadAddress
& 0xF0000000) == 0x90000000 )
413 throw "can't map split seg anywhere";
417 vm_size_t high
= (regions
[i
].address
+ size
- regions
[0].address
) & 0x0FFFFFFF;
418 if ( high
> biggestDiff
)
423 // map in each region
424 uintptr_t slide
= sNextAltLoadAddress
- regions
[0].address
;
425 this->setSlide(slide
);
426 for(unsigned int i
=0; i
< regionCount
; ++i
) {
427 if ( (regions
[i
].init_prot
& VM_PROT_ZF
) != 0 ) {
428 // do nothing vm_allocate() zero-fills by default
431 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
+ slide
);
432 size_t size
= regions
[i
].size
;
434 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
435 protection
|= PROT_EXEC
;
436 if ( regions
[i
].init_prot
& VM_PROT_READ
)
437 protection
|= PROT_READ
;
438 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
439 protection
|= PROT_WRITE
;
440 off_t offset
= regions
[i
].file_offset
;
441 //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
442 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FILE
| MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
443 if ( mmapAddress
== ((void*)(-1)) )
447 // set so next maps right after this one
448 sNextAltLoadAddress
+= biggestDiff
;
449 sNextAltLoadAddress
= (sNextAltLoadAddress
+ 4095) & (-4096);
452 if ( context
.verboseMapping
) {
453 fprintf(stderr
, "dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide
, this->getPath());
454 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
455 Segment
* seg
= fSegments
[segIndex
];
456 const _shared_region_mapping_np
* entry
= ®ions
[entryIndex
];
457 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
458 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
459 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
460 if ( entryIndex
< (regionCount
-1) ) {
461 const _shared_region_mapping_np
* nextEntry
= ®ions
[entryIndex
+1];
462 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
463 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
464 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
465 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
476 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
478 enum SharedRegionState
480 kSharedRegionStartState
= 0,
481 kSharedRegionLoadFileState
,
482 kSharedRegionMapFileState
,
483 kSharedRegionMapFilePrivateState
,
484 kSharedRegionMapFilePrivateMMapState
,
485 kSharedRegionMapFilePrivateOutsideState
,
487 static SharedRegionState sSharedRegionState
= kSharedRegionStartState
;
489 // non-split segment libraries handled by super class
491 return ImageLoader::mapSegments(fd
, offsetInFat
, lenInFat
, fileLen
, context
);
493 if ( kSharedRegionStartState
== sSharedRegionState
) {
494 if ( hasSharedRegionMapFile() ) {
495 if ( context
.slideAndPackDylibs
) {
496 sharedRegionMakePrivate(context
);
497 // remove underlying submap and block out 0x90000000 to 0xAFFFFFFF
498 vm_address_t addr
= (vm_address_t
)0x90000000;
499 vm_deallocate(mach_task_self(), addr
, 0x20000000);
500 vm_allocate(mach_task_self(), &addr
, 0x20000000, false);
501 sSharedRegionState
= kSharedRegionMapFilePrivateMMapState
;
503 else if ( context
.sharedRegionMode
== kUsePrivateSharedRegion
) {
504 sharedRegionMakePrivate(context
);
505 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
507 else if ( context
.sharedRegionMode
== kDontUseSharedRegion
) {
508 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
511 sSharedRegionState
= kSharedRegionMapFileState
;
515 sSharedRegionState
= kSharedRegionLoadFileState
;
519 if ( kSharedRegionLoadFileState
== sSharedRegionState
) {
520 if ( 0 != sharedRegionLoadFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
521 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
525 if ( kSharedRegionMapFileState
== sSharedRegionState
) {
526 if ( 0 != sharedRegionMapFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
527 sharedRegionMakePrivate(context
);
528 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
532 if ( (kSharedRegionMapFilePrivateState
== sSharedRegionState
) || (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
) ) {
533 if ( 0 != sharedRegionMapFilePrivate(fd
, offsetInFat
, lenInFat
, fileLen
, context
, (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
)) ) {
534 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
538 if ( kSharedRegionMapFilePrivateOutsideState
== sSharedRegionState
) {
539 if ( 0 != sharedRegionMapFilePrivateOutside(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
540 throw "mapping error";
546 ImageLoaderMachO::getExtraZeroFillEntriesCount()
548 // calculate mapping entries
549 const unsigned int segmentCount
= fSegments
.size();
550 unsigned int extraZeroFillEntries
= 0;
551 for(unsigned int i
=0; i
< segmentCount
; ++i
){
552 Segment
* seg
= fSegments
[i
];
553 if ( seg
->hasTrailingZeroFill() )
554 ++extraZeroFillEntries
;
557 return extraZeroFillEntries
;
561 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
562 _shared_region_mapping_np
*mappingTable
)
564 unsigned int segmentCount
= fSegments
.size();
565 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
566 Segment
* seg
= fSegments
[segIndex
];
567 _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
568 entry
->address
= seg
->getActualLoadAddress();
569 entry
->size
= seg
->getFileSize();
570 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
571 entry
->init_prot
= VM_PROT_NONE
;
572 if ( !seg
->unaccessible() ) {
573 if ( seg
->executable() )
574 entry
->init_prot
|= VM_PROT_EXECUTE
;
575 if ( seg
->readable() )
576 entry
->init_prot
|= VM_PROT_READ
;
577 if ( seg
->writeable() )
578 entry
->init_prot
|= VM_PROT_WRITE
| VM_PROT_COW
;
580 entry
->max_prot
= entry
->init_prot
;
581 if ( seg
->hasTrailingZeroFill() ) {
582 _shared_region_mapping_np
* zfentry
= &mappingTable
[++entryIndex
];
583 zfentry
->address
= entry
->address
+ seg
->getFileSize();
584 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
585 zfentry
->file_offset
= 0;
586 zfentry
->init_prot
= entry
->init_prot
| VM_PROT_COW
| VM_PROT_ZF
;
587 zfentry
->max_prot
= zfentry
->init_prot
;
593 ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext
& context
)
595 if ( context
.verboseMapping
)
596 fprintf(stderr
, "dyld: making shared regions private\n");
598 // shared mapping failed, so make private copy of shared region and try mapping private
599 RegionsVector allRegions
;
600 context
.getAllMappedRegions(allRegions
);
601 std::vector
<_shared_region_range_np
> splitSegRegions
;
602 const unsigned int allRegiontCount
= allRegions
.size();
603 for(unsigned int i
=0; i
< allRegiontCount
; ++i
){
604 MappedRegion region
= allRegions
[i
];
605 uint8_t highByte
= region
.address
>> 28;
606 if ( (highByte
== 9) || (highByte
== 0xA) ) {
607 _shared_region_range_np splitRegion
;
608 splitRegion
.address
= region
.address
;
609 splitRegion
.size
= region
.size
;
610 splitSegRegions
.push_back(splitRegion
);
613 int result
= _shared_region_make_private_np(splitSegRegions
.size(), &splitSegRegions
[0]);
614 // notify gdb or other lurkers that this process is no longer using the shared region
615 dyld_all_image_infos
.processDetachedFromSharedRegion
= true;
620 ImageLoaderMachO::sharedRegionMapFile(int fd
,
621 uint64_t offsetInFat
,
624 const LinkContext
& context
)
626 // build table of segments to map
627 const unsigned int segmentCount
= fSegments
.size();
628 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
629 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
630 _shared_region_mapping_np mappingTable
[mappingTableCount
];
631 initMappingTable(offsetInFat
, mappingTable
);
633 uint64_t *slidep
= NULL
;
635 // try to map it in shared
636 int r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, slidep
);
638 if(NULL
!= slidep
&& 0 != *slidep
) {
639 // update with actual load addresses
641 if ( context
.verboseMapping
) {
642 fprintf(stderr
, "dyld: Mapping split-seg shared %s\n", this->getPath());
643 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
644 Segment
* seg
= fSegments
[segIndex
];
645 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
646 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
647 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
648 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
649 if ( entryIndex
< (mappingTableCount
-1) ) {
650 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
651 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
652 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
653 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
654 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
666 ImageLoaderMachO::sharedRegionMapFilePrivate(int fd
,
667 uint64_t offsetInFat
,
670 const LinkContext
& context
,
673 const unsigned int segmentCount
= fSegments
.size();
675 // adjust base address of segments to pack next to last dylib
676 if ( context
.slideAndPackDylibs
) {
677 uintptr_t lowestReadOnly
= (uintptr_t)(-1);
678 uintptr_t lowestWritable
= (uintptr_t)(-1);
679 for(unsigned int segIndex
=0; segIndex
< segmentCount
; ++segIndex
){
680 Segment
* seg
= fSegments
[segIndex
];
681 uintptr_t segEnd
= seg
->getActualLoadAddress();
682 if ( seg
->writeable() ) {
683 if ( segEnd
< lowestWritable
)
684 lowestWritable
= segEnd
;
687 if ( segEnd
< lowestReadOnly
)
688 lowestReadOnly
= segEnd
;
691 uintptr_t baseAddress
;
692 if ( lowestWritable
- 256*1024*1024 < lowestReadOnly
)
693 baseAddress
= lowestWritable
- 256*1024*1024;
695 baseAddress
= lowestReadOnly
;
696 // record that we want dylb slid to fgNextSplitSegAddress
697 this->setSlide(fgNextSplitSegAddress
- baseAddress
);
700 // build table of segments to map
701 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
702 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
703 _shared_region_mapping_np mappingTable
[mappingTableCount
];
704 initMappingTable(offsetInFat
, mappingTable
);
707 // try map it in privately (don't allow sliding if we pre-calculated the load address to pack dylibs)
710 r
= _shared_region_map_file_with_mmap(fd
, mappingTableCount
, mappingTable
);
712 r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, context
.slideAndPackDylibs
? NULL
: &slide
);
715 slide
= (slide
) & (-4096); // round down to page boundary
716 this->setSlide(slide
);
718 if ( context
.verboseMapping
) {
720 fprintf(stderr
, "dyld: Mapping split-seg un-shared %s\n", this->getPath());
722 fprintf(stderr
, "dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide
, this->getPath());
723 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
724 Segment
* seg
= fSegments
[segIndex
];
725 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
726 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
727 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
728 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
729 if ( entryIndex
< (mappingTableCount
-1) ) {
730 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
731 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
732 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
733 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
734 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
740 if ( context
.slideAndPackDylibs
) {
741 // calculate where next split-seg dylib can load
742 uintptr_t largestReadOnly
= 0;
743 uintptr_t largestWritable
= 0;
744 for (unsigned int segIndex
=0; segIndex
< segmentCount
; ++segIndex
) {
745 Segment
* seg
= fSegments
[segIndex
];
746 uintptr_t segEnd
= seg
->getActualLoadAddress()+seg
->getSize();
747 segEnd
= (segEnd
+4095) & (-4096); // page align
748 if ( seg
->writeable() ) {
749 if ( segEnd
> largestWritable
)
750 largestWritable
= segEnd
;
753 if ( segEnd
> largestReadOnly
)
754 largestReadOnly
= segEnd
;
757 if ( largestWritable
- 256*1024*1024 > largestReadOnly
)
758 fgNextSplitSegAddress
= largestWritable
- 256*1024*1024;
760 fgNextSplitSegAddress
= largestReadOnly
;
763 if ( context
.slideAndPackDylibs
&& (r
!= 0) )
764 throwf("can't rebase split-seg dylib %s because shared_region_map_file_np() returned %d", this->getPath(), r
);
771 ImageLoaderMachO::sharedRegionLoadFile(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
774 // map in split segment file at random address, then tell kernel to share it
775 void* loadAddress
= 0;
776 loadAddress
= mmap(NULL
, fileLen
, PROT_READ
, MAP_FILE
, fd
, 0);
777 if ( loadAddress
== ((void*)(-1)) )
780 // calculate mapping entries
781 const unsigned int segmentCount
= fSegments
.size();
782 unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
784 // build table of segments to map
785 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
786 const uintptr_t baseAddress
= fSegments
[0]->getPreferredLoadAddress();
787 sf_mapping mappingTable
[mappingTableCount
];
788 initMappingTable(offsetInFat
, mappingTable
, baseAddress
);
791 // use load_shared_file() to map all segments at once
792 int flags
= 0; // might need to set NEW_LOCAL_SHARED_REGIONS on first use
793 static bool firstTime
= true;
795 // when NEW_LOCAL_SHARED_REGIONS bit is set, this process will get is own shared region
796 // this is used by Xcode to prevent development libraries from polluting the global shared segment
797 if ( context
.sharedRegionMode
== kUsePrivateSharedRegion
)
798 flags
|= NEW_LOCAL_SHARED_REGIONS
;
802 caddr_t base_address
= (caddr_t
)baseAddress
;
804 r
= load_shared_file( (char*)fPath
, // path of file to map shared
805 (char*)loadAddress
, // beginning of local copy of sharable pages in file
806 fileLen
, // end of shareable pages in file
807 &base_address
, // beginning of address range to map
808 mappingTableCount
, // number of entres in array of sf_mapping
809 mappingTable
, // the array of sf_mapping
810 &flags
); // in/out flags
812 // try again but tell kernel it is ok to slide
813 flags
|= ALTERNATE_LOAD_SITE
;
814 r
= load_shared_file((char*)fPath
,(char*)loadAddress
, fileLen
, &base_address
,
815 mappingTableCount
, mappingTable
, &flags
);
818 // unmap file from random address now that they are (hopefully) mapped into the shared region
819 munmap(loadAddress
, fileLen
);
822 if ( base_address
!= (caddr_t
)baseAddress
)
823 this->setSlide((uintptr_t)base_address
- baseAddress
);
824 if ( context
.verboseMapping
) {
825 if ( base_address
!= (caddr_t
)baseAddress
)
826 fprintf(stderr
, "dyld: Mapping split-seg load_shared_alt_region %s\n", this->getPath());
828 fprintf(stderr
, "dyld: Mapping split-seg load_shared %s\n", this->getPath());
829 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
830 Segment
* seg
= fSegments
[segIndex
];
831 const sf_mapping
* entry
= &mappingTable
[entryIndex
];
832 if ( (entry
->protection
& VM_PROT_ZF
) == 0 )
833 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
834 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
835 if ( entryIndex
< (mappingTableCount
-1) ) {
836 const sf_mapping
* nextEntry
= &mappingTable
[entryIndex
+1];
837 if ( (nextEntry
->protection
& VM_PROT_ZF
) != 0 ) {
838 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
839 seg
->getName(), (uintptr_t)(nextEntry
->mapping_offset
+ base_address
), (uintptr_t)(nextEntry
->mapping_offset
+ base_address
+ nextEntry
->size
- 1));
849 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
850 sf_mapping
*mappingTable
,
851 uintptr_t baseAddress
)
853 unsigned int segmentCount
= fSegments
.size();
854 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
855 Segment
* seg
= fSegments
[segIndex
];
856 sf_mapping
* entry
= &mappingTable
[entryIndex
];
857 entry
->mapping_offset
= seg
->getPreferredLoadAddress() - baseAddress
;
858 entry
->size
= seg
->getFileSize();
859 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
860 entry
->protection
= VM_PROT_NONE
;
861 if ( !seg
->unaccessible() ) {
862 if ( seg
->executable() )
863 entry
->protection
|= VM_PROT_EXECUTE
;
864 if ( seg
->readable() )
865 entry
->protection
|= VM_PROT_READ
;
866 if ( seg
->writeable() )
867 entry
->protection
|= VM_PROT_WRITE
| VM_PROT_COW
;
871 if ( seg
->hasTrailingZeroFill() ) {
872 sf_mapping
* zfentry
= &mappingTable
[++entryIndex
];
873 zfentry
->mapping_offset
= entry
->mapping_offset
+ seg
->getFileSize();
874 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
875 zfentry
->file_offset
= 0;
876 zfentry
->protection
= entry
->protection
| VM_PROT_COW
| VM_PROT_ZF
;
882 #endif // !__LP64__ split segs not supported for 64-bits
885 void ImageLoaderMachO::setSlide(intptr_t slide
)
890 void ImageLoaderMachO::parseLoadCmds()
892 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
893 const unsigned int segmentCount
= fSegments
.size();
894 for(unsigned int i
=0; i
< segmentCount
; ++i
){
895 Segment
* seg
= fSegments
[i
];
896 // set up pointer to __LINKEDIT segment
897 if ( strcmp(seg
->getName(),"__LINKEDIT") == 0 )
898 fLinkEditBase
= (uint8_t*)(seg
->getActualLoadAddress() - seg
->getFileOffset());
899 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
900 if ( strcmp(seg
->getName(),"__TEXT") == 0 ) {
901 if ( seg
->hasFixUps() )
902 fTextSegmentWithFixups
= (SegmentMachO
*)seg
;
904 // some segment always starts at beginning of file and contains mach_header and load commands
905 if ( (seg
->getFileOffset() == 0) && (seg
->getFileSize() != 0) ) {
906 fMachOData
= (uint8_t*)(seg
->getActualLoadAddress());
910 // keep count of prebound images with weak exports
911 if ( this->hasCoalescedExports() )
912 ++fgCountOfImagesWithWeakExports
;
914 // walk load commands (mapped in at start of __TEXT segment)
915 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
916 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
917 const struct load_command
* cmd
= cmds
;
918 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
922 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
923 fStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
924 fSymbolTable
= (struct macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
928 fDynamicInfo
= (struct dysymtab_command
*)cmd
;
930 case LC_SUB_UMBRELLA
:
931 fHasSubUmbrella
= true;
933 case LC_SUB_FRAMEWORK
:
935 const struct sub_framework_command
* subf
= (struct sub_framework_command
*)cmd
;
936 fReExportThruFramework
= (char*)cmd
+ subf
->umbrella
.offset
;
940 fHasSubLibraries
= true;
942 case LC_ROUTINES_COMMAND
:
943 fDashInit
= (struct macho_routines_command
*)cmd
;
945 case LC_SEGMENT_COMMAND
:
947 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
948 const bool isDataSeg
= (strcmp(seg
->segname
, "__DATA") == 0);
949 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
950 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
951 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
952 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
953 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
954 fModInitSection
= sect
;
955 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
956 fModTermSection
= sect
;
957 else if ( isDataSeg
&& (strcmp(sect
->sectname
, "__dyld") == 0) ) {
960 else if ( isDataSeg
&& (strcmp(sect
->sectname
, "__image_notify") == 0) )
961 fImageNotifySection
= sect
;
965 case LC_TWOLEVEL_HINTS
:
966 fTwoLevelHints
= (struct twolevel_hints_command
*)cmd
;
970 fDylibID
= (struct dylib_command
*)cmd
;
973 case LC_LOAD_WEAK_DYLIB
:
974 // do nothing, just prevent LC_REQ_DYLD exception from occuring
977 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 )
978 throwf("unknown required load command 0x%08X", cmd
->cmd
);
980 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
987 const char* ImageLoaderMachO::getInstallPath() const
989 if ( fDylibID
!= NULL
) {
990 return (char*)fDylibID
+ fDylibID
->dylib
.name
.offset
;
995 // test if this image is re-exported through parent (the image that loaded this one)
996 bool ImageLoaderMachO::isSubframeworkOf(const LinkContext
& context
, const ImageLoader
* parent
) const
998 if ( fReExportThruFramework
!= NULL
) {
999 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
1000 const char* parentInstallPath
= parent
->getInstallPath();
1001 if ( parentInstallPath
!= NULL
) {
1002 const char* lastSlash
= strrchr(parentInstallPath
, '/');
1003 if ( lastSlash
!= NULL
) {
1004 if ( strcmp(&lastSlash
[1], fReExportThruFramework
) == 0 )
1006 if ( context
.imageSuffix
!= NULL
) {
1007 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1008 char reexportAndSuffix
[strlen(context
.imageSuffix
)+strlen(fReExportThruFramework
)+1];
1009 strcpy(reexportAndSuffix
, fReExportThruFramework
);
1010 strcat(reexportAndSuffix
, context
.imageSuffix
);
1011 if ( strcmp(&lastSlash
[1], reexportAndSuffix
) == 0 )
1020 // test if child is re-exported
1021 bool ImageLoaderMachO::hasSubLibrary(const LinkContext
& context
, const ImageLoader
* child
) const
1023 if ( fHasSubLibraries
) {
1024 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
1025 const char* childInstallPath
= child
->getInstallPath();
1026 if ( childInstallPath
!= NULL
) {
1027 const char* lastSlash
= strrchr(childInstallPath
, '/');
1028 if ( lastSlash
!= NULL
) {
1029 const char* firstDot
= strchr(lastSlash
, '.');
1031 if ( firstDot
== NULL
)
1032 len
= strlen(lastSlash
);
1034 len
= firstDot
-lastSlash
-1;
1035 char childLeafName
[len
+1];
1036 strncpy(childLeafName
, &lastSlash
[1], len
);
1037 childLeafName
[len
] = '\0';
1038 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1039 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1040 const struct load_command
* cmd
= cmds
;
1041 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1043 case LC_SUB_LIBRARY
:
1045 const struct sub_library_command
* lib
= (struct sub_library_command
*)cmd
;
1046 const char* aSubLibName
= (char*)cmd
+ lib
->sub_library
.offset
;
1047 if ( strcmp(aSubLibName
, childLeafName
) == 0 )
1049 if ( context
.imageSuffix
!= NULL
) {
1050 // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
1051 char aSubLibNameAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubLibName
)+1];
1052 strcpy(aSubLibNameAndSuffix
, aSubLibName
);
1053 strcat(aSubLibNameAndSuffix
, context
.imageSuffix
);
1054 if ( strcmp(aSubLibNameAndSuffix
, childLeafName
) == 0 )
1060 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1065 if ( fHasSubUmbrella
) {
1066 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
1067 const char* childInstallPath
= child
->getInstallPath();
1068 if ( childInstallPath
!= NULL
) {
1069 const char* lastSlash
= strrchr(childInstallPath
, '/');
1070 if ( lastSlash
!= NULL
) {
1071 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1072 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1073 const struct load_command
* cmd
= cmds
;
1074 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1076 case LC_SUB_UMBRELLA
:
1078 const struct sub_umbrella_command
* um
= (struct sub_umbrella_command
*)cmd
;
1079 const char* aSubUmbrellaName
= (char*)cmd
+ um
->sub_umbrella
.offset
;
1080 if ( strcmp(aSubUmbrellaName
, &lastSlash
[1]) == 0 )
1082 if ( context
.imageSuffix
!= NULL
) {
1083 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1084 char umbrellaAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubUmbrellaName
)+1];
1085 strcpy(umbrellaAndSuffix
, aSubUmbrellaName
);
1086 strcat(umbrellaAndSuffix
, context
.imageSuffix
);
1087 if ( strcmp(umbrellaAndSuffix
, &lastSlash
[1]) == 0 )
1093 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1102 void* ImageLoaderMachO::getMain() const
1104 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1105 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1106 const struct load_command
* cmd
= cmds
;
1107 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1112 const ppc_thread_state_t
* registers
= (ppc_thread_state_t
*)(((char*)cmd
) + 16);
1113 return (void*)registers
->srr0
;
1115 const ppc_thread_state64_t
* registers
= (ppc_thread_state64_t
*)(((char*)cmd
) + 16);
1116 return (void*)registers
->srr0
;
1118 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
1119 return (void*)registers
->eip
;
1121 #warning need processor specific code
1126 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1132 uint32_t ImageLoaderMachO::doGetDependentLibraryCount()
1134 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1135 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1137 const struct load_command
* cmd
= cmds
;
1138 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1141 case LC_LOAD_WEAK_DYLIB
:
1145 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1150 void ImageLoaderMachO::doGetDependentLibraries(DependentLibrary libs
[])
1153 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1154 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1155 const struct load_command
* cmd
= cmds
;
1156 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1159 case LC_LOAD_WEAK_DYLIB
:
1161 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
1162 DependentLibrary
* lib
= &libs
[index
++];
1163 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
1164 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1166 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
1167 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
1168 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
1169 lib
->required
= (cmd
->cmd
== LC_LOAD_DYLIB
);
1170 lib
->checksumMatches
= false;
1171 lib
->isReExported
= false;
1175 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1179 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo()
1182 if ( fDylibID
!= NULL
) {
1183 info
.minVersion
= fDylibID
->dylib
.compatibility_version
;
1184 info
.maxVersion
= fDylibID
->dylib
.current_version
;
1185 info
.checksum
= fDylibID
->dylib
.timestamp
;
1188 info
.minVersion
= 0;
1189 info
.maxVersion
= 0;
1196 uintptr_t ImageLoaderMachO::getRelocBase()
1198 if ( fIsSplitSeg
) {
1199 // in split segment libraries r_address is offset from first writable segment
1200 const unsigned int segmentCount
= fSegments
.size();
1201 for(unsigned int i
=0; i
< segmentCount
; ++i
){
1202 Segment
* seg
= fSegments
[i
];
1203 if ( seg
->writeable() ) {
1204 return seg
->getActualLoadAddress();
1209 // in non-split segment libraries r_address is offset from first segment
1210 return fSegments
[0]->getActualLoadAddress();
1214 static inline void otherRelocsPPC(uintptr_t* locationToFix
, uint8_t relocationType
, uint16_t otherHalf
, uintptr_t slide
)
1216 // low 16 bits of 32-bit ppc instructions need fixing
1217 struct ppcInstruction
{ uint16_t opcode
; int16_t immediateValue
; };
1218 ppcInstruction
* instruction
= (ppcInstruction
*)locationToFix
;
1219 //uint32_t before = *((uint32_t*)locationToFix);
1220 switch ( relocationType
)
1222 case PPC_RELOC_LO16
:
1223 instruction
->immediateValue
= ((otherHalf
<< 16) | instruction
->immediateValue
) + slide
;
1225 case PPC_RELOC_HI16
:
1226 instruction
->immediateValue
= ((((instruction
->immediateValue
<< 16) | otherHalf
) + slide
) >> 16);
1228 case PPC_RELOC_HA16
:
1229 int16_t signedOtherHalf
= (int16_t)(otherHalf
& 0xffff);
1230 uint32_t temp
= (instruction
->immediateValue
<< 16) + signedOtherHalf
+ slide
;
1231 if ( (temp
& 0x00008000) != 0 )
1233 instruction
->immediateValue
= temp
>> 16;
1235 //uint32_t after = *((uint32_t*)locationToFix);
1236 //fprintf(stderr, "dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
1240 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1242 // if prebound and loaded at prebound address, then no need to rebase
1243 // Note: you might think that the check for allDependentLibrariesAsWhenPreBound() is not needed
1244 // but it is. If a dependent library changed, this image's lazy pointers into that library
1245 // need to be updated (reset back to lazy binding handler). That work is done most easily
1246 // here because there is a PPC_RELOC_PB_LA_PTR reloc record for each lazy pointer.
1247 if ( this->usablePrebinding(context
) && this->usesTwoLevelNameSpace() ) {
1248 // skip rebasing cause prebound and prebinding not disabled
1249 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1253 // print why prebinding was not used
1254 if ( context
.verbosePrebinding
) {
1255 if ( !this->isPrebindable() ) {
1256 fprintf(stderr
, "dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1258 else if ( fSlide
!= 0 ) {
1259 fprintf(stderr
, "dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1261 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1262 fprintf(stderr
, "dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1264 else if ( !this->usesTwoLevelNameSpace() ){
1265 fprintf(stderr
, "dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1268 fprintf(stderr
, "dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1272 // if there are __TEXT fixups, temporarily make __TEXT writable
1273 if ( fTextSegmentWithFixups
!= NULL
)
1274 fTextSegmentWithFixups
->tempWritable();
1276 // cache this value that is used in the following loop
1277 register const uintptr_t slide
= this->fSlide
;
1279 // loop through all local (internal) relocation records
1280 const uintptr_t relocBase
= this->getRelocBase();
1281 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]);
1282 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nlocrel
];
1283 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1284 if ( (reloc
->r_address
& R_SCATTERED
) == 0 ) {
1285 if ( reloc
->r_symbolnum
== R_ABS
) {
1286 // ignore absolute relocations
1288 else if (reloc
->r_length
== RELOC_SIZE
) {
1289 switch(reloc
->r_type
) {
1290 case GENERIC_RELOC_VANILLA
:
1291 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1294 case PPC_RELOC_HI16
:
1295 case PPC_RELOC_LO16
:
1296 case PPC_RELOC_HA16
:
1297 // some tools leave object file relocations in linked images
1298 otherRelocsPPC((uintptr_t*)(reloc
->r_address
+ relocBase
), reloc
->r_type
, reloc
[1].r_address
, slide
);
1299 ++reloc
; // these relocations come in pairs, skip next
1303 throw "unknown local relocation type";
1307 throw "bad local relocation length";
1311 const struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
1312 if (sreloc
->r_length
== RELOC_SIZE
) {
1313 uintptr_t* locationToFix
= (uintptr_t*)(sreloc
->r_address
+ relocBase
);
1314 switch(sreloc
->r_type
) {
1315 case GENERIC_RELOC_VANILLA
:
1316 *locationToFix
+= slide
;
1318 #if __ppc__ || __ppc64__
1319 case PPC_RELOC_PB_LA_PTR
:
1320 // should only see these in prebound images, and we got here so prebinding is being ignored
1321 *locationToFix
= sreloc
->r_value
+ slide
;
1325 case PPC_RELOC_HI16
:
1326 case PPC_RELOC_LO16
:
1327 case PPC_RELOC_HA16
:
1328 // Metrowerks compiler sometimes leaves object file relocations in linked images???
1329 ++reloc
; // these relocations come in pairs, get next one
1330 otherRelocsPPC(locationToFix
, sreloc
->r_type
, reloc
->r_address
, slide
);
1334 case GENERIC_RELOC_PB_LA_PTR
:
1335 // should only see these in prebound images, and we got here so prebinding is being ignored
1336 *locationToFix
= sreloc
->r_value
+ slide
;
1340 throw "unknown local scattered relocation type";
1344 throw "bad local scattered relocation length";
1349 // if there were __TEXT fixups, restore write protection
1350 if ( fTextSegmentWithFixups
!= NULL
) {
1351 fTextSegmentWithFixups
->setPermissions();
1352 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
1356 fgTotalRebaseFixups
+= fDynamicInfo
->nlocrel
;
1360 const struct macho_nlist
* ImageLoaderMachO::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],
1361 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
)
1363 int32_t high
= symbolCount
-1;
1364 int32_t mid
= hintIndex
;
1366 // handle out of range hint
1367 if ( mid
>= (int32_t)symbolCount
) {
1368 mid
= symbolCount
/2;
1369 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1372 ++ImageLoaderMachO::fgHintedBinaryTreeSearchs
;
1375 for (int32_t low
= 0; low
<= high
; mid
= (low
+high
)/2) {
1376 const uint32_t index
= toc
[mid
].symbol_index
;
1377 const struct macho_nlist
* pivot
= &symbols
[index
];
1378 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1379 #if LINKEDIT_USAGE_DEBUG
1380 noteAccessedLinkEditAddress(&toc
[mid
]);
1381 noteAccessedLinkEditAddress(pivot
);
1382 noteAccessedLinkEditAddress(pivotStr
);
1384 int cmp
= astrcmp(key
, pivotStr
);
1399 const struct macho_nlist
* ImageLoaderMachO::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
)
1401 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1402 const struct macho_nlist
* base
= symbols
;
1403 for (uint32_t n
= symbolCount
; n
> 0; n
/= 2) {
1404 const struct macho_nlist
* pivot
= &base
[n
/2];
1405 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1406 #if LINKEDIT_USAGE_DEBUG
1407 noteAccessedLinkEditAddress(pivot
);
1408 noteAccessedLinkEditAddress(pivotStr
);
1410 int cmp
= astrcmp(key
, pivotStr
);
1415 // move base to symbol after pivot
1427 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, const void* hint
, bool searchReExports
, ImageLoader
** foundIn
) const
1429 const struct macho_nlist
* sym
= NULL
;
1430 const struct twolevel_hint
* theHint
= (struct twolevel_hint
*)hint
;
1431 if ( fDynamicInfo
->tocoff
== 0 )
1432 sym
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
);
1434 uint32_t start
= fDynamicInfo
->nextdefsym
;
1435 if ( theHint
!= NULL
)
1436 start
= theHint
->itoc
;
1437 if ( (theHint
== NULL
) || (theHint
->isub_image
== 0) ) {
1438 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1439 fDynamicInfo
->ntoc
, start
);
1442 if ( sym
!= NULL
) {
1443 if ( foundIn
!= NULL
)
1444 *foundIn
= (ImageLoader
*)this;
1446 return (const Symbol
*)sym
;
1449 if ( searchReExports
) {
1450 // hint might tell us to try a particular subimage
1451 if ( (theHint
!= NULL
) && (theHint
->isub_image
> 0) && (theHint
->isub_image
<= fLibrariesCount
) ) {
1452 // isub_image is an index into a list that is sorted non-rexported images first
1454 ImageLoader
* target
= NULL
;
1455 // pass one, only look at sub-frameworks
1456 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1457 DependentLibrary
& libInfo
= fLibraries
[i
];
1458 if ( libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
)) {
1459 if ( ++index
== theHint
->isub_image
) {
1460 target
= libInfo
.image
;
1465 if (target
!= NULL
) {
1466 // pass two, only look at non-sub-framework-reexports
1467 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1468 DependentLibrary
& libInfo
= fLibraries
[i
];
1469 if ( libInfo
.isReExported
&& !libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
) ) {
1470 if ( ++index
== theHint
->isub_image
) {
1471 target
= libInfo
.image
;
1477 if (target
!= NULL
) {
1478 const Symbol
* result
= target
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1479 if ( result
!= NULL
)
1484 // hint failed, try all sub images
1485 // pass one, only look at sub-frameworks
1486 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1487 DependentLibrary
& libInfo
= fLibraries
[i
];
1488 if ( (libInfo
.image
!= NULL
) && libInfo
.isSubFramework
) {
1489 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1490 if ( result
!= NULL
)
1494 // pass two, only look at non-sub-framework-reexports
1495 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1496 DependentLibrary
& libInfo
= fLibraries
[i
];
1497 if ( (libInfo
.image
!= NULL
) && libInfo
.isReExported
&& !libInfo
.isSubFramework
) {
1498 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1499 if ( result
!= NULL
)
1505 // last change: the hint is wrong (non-zero but actually in this image)
1506 if ( (theHint
!= NULL
) && (theHint
->isub_image
!= 0) ) {
1507 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1508 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
);
1509 if ( sym
!= NULL
) {
1510 if ( foundIn
!= NULL
)
1511 *foundIn
= (ImageLoader
*)this;
1512 return (const Symbol
*)sym
;
1520 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
) const
1522 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1523 return nlistSym
->n_value
+ fSlide
;
1526 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1528 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1529 if ( (nlistSym
->n_desc
& N_WEAK_DEF
) != 0 )
1530 return kWeakDefinition
;
1531 return kNoDefinitionOptions
;
1534 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1536 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1537 return &fStrings
[nlistSym
->n_un
.n_strx
];
1540 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1542 return fDynamicInfo
->nextdefsym
;
1546 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1548 if ( index
< fDynamicInfo
->nextdefsym
) {
1549 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iextdefsym
+ index
];
1550 return (const ImageLoader::Symbol
*)sym
;
1556 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1558 return fDynamicInfo
->nundefsym
;
1562 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1564 if ( index
< fDynamicInfo
->nundefsym
) {
1565 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iundefsym
+ index
];
1566 return (const ImageLoader::Symbol
*)sym
;
1572 ImageLoader::ReferenceFlags
ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1574 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1575 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1576 if ( ((nlistSym
->n_type
& N_TYPE
) == N_UNDF
) && (nlistSym
->n_value
!= 0) )
1577 flags
|= ImageLoader::kTentativeDefinition
;
1578 if ( (nlistSym
->n_desc
& N_WEAK_REF
) != 0 )
1579 flags
|= ImageLoader::kWeakReference
;
1584 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1586 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1587 return &fStrings
[nlistSym
->n_un
.n_strx
];
1591 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1593 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1594 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1595 const struct load_command
* cmd
= cmds
;
1596 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1598 case LC_SEGMENT_COMMAND
:
1600 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1601 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1602 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1603 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1604 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1605 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1606 *length
= sect
->size
;
1613 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1619 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1621 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1622 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1623 const struct load_command
* cmd
= cmds
;
1624 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1625 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1627 case LC_SEGMENT_COMMAND
:
1629 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1630 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1631 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1632 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1633 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1634 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1635 if ( segmentName
!= NULL
)
1636 *segmentName
= sect
->segname
;
1637 if ( sectionName
!= NULL
)
1638 *sectionName
= sect
->sectname
;
1639 if ( sectionOffset
!= NULL
)
1640 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1648 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1654 bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist
* symbol
)
1656 // if a define and weak ==> coalesced
1657 if ( ((symbol
->n_type
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc
& N_WEAK_DEF
) != 0) )
1659 // if an undefine and not referencing a weak symbol ==> coalesced
1660 if ( ((symbol
->n_type
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc
& N_REF_TO_WEAK
) != 0) )
1668 static void __attribute__((noreturn
)) throwSymbolNotFound(const char* symbol
, const char* referencedFrom
, const char* expectedIn
)
1670 const char* formatString
= "Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n";
1671 char buf
[strlen(symbol
)+strlen(referencedFrom
)+strlen(expectedIn
)+strlen(formatString
)];
1672 sprintf(buf
, formatString
, symbol
, referencedFrom
, expectedIn
);
1673 throw strdup(buf
); // this is a leak if exception doesn't halt program
1676 uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
, bool twoLevel
, ImageLoader
** foundIn
)
1678 const char* symbolName
= &fStrings
[undefinedSymbol
->n_un
.n_strx
];
1680 if ( context
.bindFlat
|| !twoLevel
) {
1683 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1684 return (*foundIn
)->getExportedSymbolAddress(sym
);
1685 // if a bundle is loaded privately the above will not find its exports
1686 if ( this->isBundle() && this->hasHiddenExports() ) {
1687 // look in self for needed symbol
1688 sym
= this->findExportedSymbol(symbolName
, NULL
, false, foundIn
);
1690 return (*foundIn
)->getExportedSymbolAddress(sym
);
1692 if ( ((undefinedSymbol
->n_type
& N_PEXT
) != 0) || ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) ) {
1693 // could be a multi-module private_extern internal reference
1694 // the static linker squirrels away the target address in n_value
1695 uintptr_t addr
= undefinedSymbol
->n_value
+ this->fSlide
;
1699 if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1700 // definition can't be found anywhere
1701 // if reference is weak_import, then it is ok, just return 0
1704 throwSymbolNotFound(symbolName
, this->getPath(), "flat namespace");
1707 // symbol requires searching images with coalesced symbols
1708 if ( this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol
) ) {
1710 if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) )
1711 return (*foundIn
)->getExportedSymbolAddress(sym
);
1712 //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace");
1713 //fprintf(stderr, "dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
1718 ImageLoader
* target
= NULL
;
1719 uint8_t ord
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
);
1720 if ( ord
== EXECUTABLE_ORDINAL
) {
1721 target
= context
.mainExecutable
;
1723 else if ( ord
== SELF_LIBRARY_ORDINAL
) {
1726 else if ( ord
== DYNAMIC_LOOKUP_ORDINAL
) {
1727 // rnielsen: HACKHACK
1730 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1731 return (*foundIn
)->getExportedSymbolAddress(sym
);
1732 // no image has exports this symbol
1733 // either report error or hope ZeroLink can just-in-time load an image
1734 context
.undefinedHandler(symbolName
);
1735 // try looking again
1736 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1737 return (*foundIn
)->getExportedSymbolAddress(sym
);
1739 throwSymbolNotFound(symbolName
, this->getPath(), "dynamic lookup");
1741 else if ( ord
<= fLibrariesCount
) {
1742 DependentLibrary
& libInfo
= fLibraries
[ord
-1];
1743 target
= libInfo
.image
;
1744 if ( (target
== NULL
) && (((undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0) || !libInfo
.required
) ) {
1745 // if target library not loaded and reference is weak or library is weak return 0
1750 throw "corrupt binary, library ordinal too big";
1753 if ( target
== NULL
) {
1754 fprintf(stderr
, "resolveUndefined(%s) in %s\n", symbolName
, this->getPath());
1755 throw "symbol not found";
1759 if ( fTwoLevelHints
!= NULL
) {
1760 uint32_t symIndex
= undefinedSymbol
- fSymbolTable
;
1761 int32_t undefinedIndex
= symIndex
- fDynamicInfo
->iundefsym
;
1762 if ( (undefinedIndex
>= 0) && ((uint32_t)undefinedIndex
< fDynamicInfo
->nundefsym
) ) {
1763 const struct twolevel_hint
* hints
= (struct twolevel_hint
*)(&fLinkEditBase
[fTwoLevelHints
->offset
]);
1764 const struct twolevel_hint
* theHint
= &hints
[undefinedIndex
];
1765 hint
= (void*)theHint
;
1769 const Symbol
* sym
= target
->findExportedSymbol(symbolName
, hint
, true, foundIn
);
1771 return (*foundIn
)->getExportedSymbolAddress(sym
);
1773 else if ( (undefinedSymbol
->n_type
& N_PEXT
) != 0 ) {
1774 // don't know why the static linker did not eliminate the internal reference to a private extern definition
1776 return undefinedSymbol
->n_value
+ fSlide
;
1778 else if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1779 // if definition not found and reference is weak return 0
1783 // nowhere to be found
1784 throwSymbolNotFound(symbolName
, this->getPath(), target
->getPath());
1788 // returns if 'addr' is within the address range of section 'sectionIndex'
1789 // fSlide is not used. 'addr' is assumed to be a prebound address in this image
1790 bool ImageLoaderMachO::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
)
1792 uint8_t currentSectionIndex
= 1;
1793 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1794 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1795 const struct load_command
* cmd
= cmds
;
1796 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1797 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1798 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1799 if ( (currentSectionIndex
<= sectionIndex
) && (sectionIndex
< currentSectionIndex
+seg
->nsects
) ) {
1800 // 'sectionIndex' is in this segment, get section info
1801 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1802 const struct macho_section
* const section
= §ionsStart
[sectionIndex
-currentSectionIndex
];
1803 return ( (section
->addr
<= addr
) && (addr
< section
->addr
+section
->size
) );
1806 // 'sectionIndex' not in this segment, skip to next segment
1807 currentSectionIndex
+= seg
->nsects
;
1810 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1816 void ImageLoaderMachO::doBindExternalRelocations(const LinkContext
& context
, bool onlyCoalescedSymbols
)
1818 const uintptr_t relocBase
= this->getRelocBase();
1819 const bool twoLevel
= this->usesTwoLevelNameSpace();
1820 const bool prebound
= this->isPrebindable();
1822 // if there are __TEXT fixups, temporarily make __TEXT writable
1823 if ( fTextSegmentWithFixups
!= NULL
)
1824 fTextSegmentWithFixups
->tempWritable();
1826 // cache last lookup
1827 const struct macho_nlist
* lastUndefinedSymbol
= 0;
1828 uintptr_t symbolAddr
= 0;
1829 ImageLoader
* image
= NULL
;
1831 // loop through all external relocation records and bind each
1832 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]);
1833 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nextrel
];
1834 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1835 if (reloc
->r_length
== RELOC_SIZE
) {
1836 switch(reloc
->r_type
) {
1837 case GENERIC_RELOC_VANILLA
:
1839 const struct macho_nlist
* undefinedSymbol
= &fSymbolTable
[reloc
->r_symbolnum
];
1840 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
1841 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(undefinedSymbol
) )
1843 uintptr_t* location
= ((uintptr_t*)(reloc
->r_address
+ relocBase
));
1844 uintptr_t value
= *location
;
1846 if ( reloc
->r_pcrel
) {
1847 value
+= (uintptr_t)location
+ 4 - fSlide
;
1851 // we are doing relocations, so prebinding was not usable
1852 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1853 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1854 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1855 if ( ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc
& N_WEAK_DEF
) != 0) ) {
1856 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1857 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1858 // that we can subtract off the weak symbol address to get the addend.
1859 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1860 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1861 if ( (value
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) )
1862 value
-= undefinedSymbol
->n_value
;
1867 // is undefined or non-weak symbol, so do subtraction to get addend
1868 value
-= undefinedSymbol
->n_value
;
1871 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
1872 if ( undefinedSymbol
!= lastUndefinedSymbol
) {
1873 symbolAddr
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, &image
);
1874 lastUndefinedSymbol
= undefinedSymbol
;
1876 if ( context
.verboseBind
) {
1877 const char *path
= NULL
;
1879 path
= image
->getShortName();
1882 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx\n",
1883 this->getShortName(), (uintptr_t)location
,
1884 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
);
1887 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx + %ld\n",
1888 this->getShortName(), (uintptr_t)location
,
1889 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, value
);
1892 value
+= symbolAddr
;
1894 if ( reloc
->r_pcrel
) {
1895 *location
= value
- ((uintptr_t)location
+ 4);
1898 // don't dirty page if prebound value was correct
1899 if ( !prebound
|| (*location
!= value
) )
1903 // don't dirty page if prebound value was correct
1904 if ( !prebound
|| (*location
!= value
) )
1910 throw "unknown external relocation type";
1914 throw "bad external relocation length";
1918 // if there were __TEXT fixups, restore write protection
1919 if ( fTextSegmentWithFixups
!= NULL
) {
1920 fTextSegmentWithFixups
->setPermissions();
1921 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
1925 fgTotalBindFixups
+= fDynamicInfo
->nextrel
;
1928 const mach_header
* ImageLoaderMachO::machHeader() const
1930 return (mach_header
*)fMachOData
;
1933 uintptr_t ImageLoaderMachO::getSlide() const
1938 // hmm. maybe this should be up in ImageLoader??
1939 const void* ImageLoaderMachO::getBaseAddress() const
1941 Segment
* seg
= fSegments
[0];
1942 return (const void*)seg
->getActualLoadAddress();
1945 uintptr_t ImageLoaderMachO::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, ImageLoader
* targetImage
, const LinkContext
& context
)
1947 if ( context
.verboseBind
) {
1948 const char* path
= NULL
;
1949 if ( targetImage
!= NULL
)
1950 path
= targetImage
->getShortName();
1951 fprintf(stderr
, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
1952 this->getShortName(), symbolName
, (((sect
->flags
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"),
1953 path
, symbolName
, (uintptr_t)ptrToBind
, targetAddr
);
1955 if ( context
.bindingHandler
!= NULL
) {
1956 const char* path
= NULL
;
1957 if ( targetImage
!= NULL
)
1958 path
= targetImage
->getShortName();
1959 targetAddr
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
);
1962 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
1963 if ( ((sect
->flags
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2
== 5) ) {
1964 uint8_t* const jmpTableEntryToPatch
= (uint8_t*)ptrToBind
;
1965 uint32_t rel32
= targetAddr
- (((uint32_t)ptrToBind
)+5);
1966 //fprintf(stderr, "rewriting stub at %p\n", jmpTableEntryToPatch);
1967 jmpTableEntryToPatch
[0] = 0xE9; // JMP rel32
1968 jmpTableEntryToPatch
[1] = rel32
& 0xFF;
1969 jmpTableEntryToPatch
[2] = (rel32
>> 8) & 0xFF;
1970 jmpTableEntryToPatch
[3] = (rel32
>> 16) & 0xFF;
1971 jmpTableEntryToPatch
[4] = (rel32
>> 24) & 0xFF;
1975 *ptrToBind
= targetAddr
;
1980 uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
)
1982 // scan for all non-lazy-pointer sections
1983 const bool twoLevel
= this->usesTwoLevelNameSpace();
1984 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1985 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1986 const struct load_command
* cmd
= cmds
;
1987 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
1988 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1990 case LC_SEGMENT_COMMAND
:
1992 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1993 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1994 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1995 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1996 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1997 uint32_t symbolIndex
= INDIRECT_SYMBOL_LOCAL
;
1998 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
1999 const uint32_t pointerCount
= sect
->size
/ sizeof(uintptr_t);
2000 uintptr_t* const symbolPointers
= (uintptr_t*)(sect
->addr
+ fSlide
);
2001 if ( (lazyPointer
>= symbolPointers
) && (lazyPointer
< &symbolPointers
[pointerCount
]) ) {
2002 const uint32_t indirectTableOffset
= sect
->reserved1
;
2003 const uint32_t lazyIndex
= lazyPointer
- symbolPointers
;
2004 symbolIndex
= indirectTable
[indirectTableOffset
+ lazyIndex
];
2008 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2009 // 5 bytes stubs on i386 are new "fast stubs"
2010 uint8_t* const jmpTableBase
= (uint8_t*)(sect
->addr
+ fSlide
);
2011 uint8_t* const jmpTableEnd
= jmpTableBase
+ sect
->size
;
2012 // initial CALL instruction in jump table leaves pointer to next entry, so back up
2013 uint8_t* const jmpTableEntryToPatch
= ((uint8_t*)lazyPointer
) - 5;
2014 lazyPointer
= (uintptr_t*)jmpTableEntryToPatch
;
2015 if ( (jmpTableEntryToPatch
>= jmpTableBase
) && (jmpTableEntryToPatch
< jmpTableEnd
) ) {
2016 const uint32_t indirectTableOffset
= sect
->reserved1
;
2017 const uint32_t entryIndex
= (jmpTableEntryToPatch
- jmpTableBase
)/5;
2018 symbolIndex
= indirectTable
[indirectTableOffset
+ entryIndex
];
2022 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
&& symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2023 const char* symbolName
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
];
2024 ImageLoader
* image
= NULL
;
2025 uintptr_t symbolAddr
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], twoLevel
, &image
);
2026 symbolAddr
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
, context
);
2027 ++fgTotalLazyBindFixups
;
2034 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2036 throw "lazy pointer not found";
2042 void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext
& context
, BindingLaziness bindness
, bool onlyCoalescedSymbols
)
2044 // scan for all non-lazy-pointer sections
2045 const bool twoLevel
= this->usesTwoLevelNameSpace();
2046 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2047 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2048 const struct load_command
* cmd
= cmds
;
2049 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2050 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2052 case LC_SEGMENT_COMMAND
:
2054 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2055 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2056 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2057 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2058 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2059 uint32_t elementSize
= sizeof(uintptr_t);
2060 uint32_t elementCount
= sect
->size
/ elementSize
;
2061 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2062 if ( (bindness
== kLazyOnly
) || (bindness
== kLazyOnlyNoDependents
) )
2065 else if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2066 // process each symbol pointer in this section
2067 fgTotalPossibleLazyBindFixups
+= elementCount
;
2068 if ( bindness
== kNonLazyOnly
)
2072 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2073 // process each jmp entry in this section
2074 elementCount
= sect
->size
/ 5;
2076 fgTotalPossibleLazyBindFixups
+= elementCount
;
2077 if ( bindness
== kNonLazyOnly
)
2084 const uint32_t indirectTableOffset
= sect
->reserved1
;
2085 uint8_t* ptrToBind
= (uint8_t*)(sect
->addr
+ fSlide
);
2086 for (uint32_t j
=0; j
< elementCount
; ++j
, ptrToBind
+= elementSize
) {
2087 uint32_t symbolIndex
= indirectTable
[indirectTableOffset
+ j
];
2088 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2089 *((uintptr_t*)ptrToBind
) += this->fSlide
;
2091 else if ( symbolIndex
== INDIRECT_SYMBOL_ABS
) {
2092 // do nothing since already has absolute address
2095 const struct macho_nlist
* sym
= &fSymbolTable
[symbolIndex
];
2096 if ( symbolIndex
== 0 ) {
2097 // This could be rdar://problem/3534709
2098 if ( ((const macho_header
*)fMachOData
)->filetype
== MH_EXECUTE
) {
2099 static bool alreadyWarned
= false;
2100 if ( (sym
->n_type
& N_TYPE
) != N_UNDF
) {
2101 // The indirect table parallels the (non)lazy pointer sections. For
2102 // instance, to find info about the fifth lazy pointer you look at the
2103 // fifth entry in the indirect table. (try otool -Iv on a file).
2104 // The entry in the indirect table contains an index into the symbol table.
2106 // The bug in ld caused the entry in the indirect table to be zero
2107 // (instead of a magic value that means a local symbol). So, if the
2108 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
2109 // symbol table index. The check I put in place is to see if the zero'th
2110 // symbol table entry is an import entry (usually it is a local symbol
2112 if ( context
.verboseWarnings
&& !alreadyWarned
) {
2113 fprintf(stderr
, "dyld: malformed executable '%s', skipping indirect symbol to %s\n",
2114 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]);
2115 alreadyWarned
= true;
2121 ImageLoader
*image
= NULL
;
2122 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
2123 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(sym
) )
2125 uintptr_t symbolAddr
;
2126 symbolAddr
= resolveUndefined(context
, sym
, twoLevel
, &image
);
2129 symbolAddr
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
, context
);
2133 fgTotalBindFixups
+= elementCount
;
2138 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2143 * The address of these symbols are written in to the (__DATA,__dyld) section
2144 * at the following offsets:
2145 * at offset 0 stub_binding_helper_interface
2146 * at offset 4 _dyld_func_lookup
2147 * at offset 8 start_debug_thread
2148 * The 'C' types (if any) for these symbols are ignored here and all are
2149 * declared as longs so the assignment of their address in to the section will
2150 * not require a cast. stub_binding_helper_interface is really a label in the
2151 * assembly code interface for the stub binding. It does not have a meaningful
2152 * 'C' type. _dyld_func_lookup is the routine in dyld_libfuncs.c.
2153 * start_debug_thread is the routine in debug.c.
2155 * For ppc the image's stub_binding_binding_helper is read from:
2156 * at offset 20 the image's stub_binding_binding_helper address
2157 * and saved into to the image structure.
2160 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
2161 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2162 void* startDebugThread
; // debugger interface ???
2163 void* debugPort
; // debugger interface ???
2164 void* debugThread
; // debugger interface ???
2165 void* stubBindHelper
; // filled in at static link time to point to stub helper in image
2166 void* coreDebug
; // ???
2169 // These are defined in dyldStartup.s
2170 extern "C" void stub_binding_helper();
2171 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
);
2172 extern "C" void fast_stub_binding_helper_interface();
2175 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
2177 if ( fDATAdyld
!= NULL
) {
2178 struct DATAdyld
* dd
= (struct DATAdyld
*)(fDATAdyld
->addr
+ fSlide
);
2179 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
2180 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
2181 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
2183 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
2184 if ( dd
->dyldFuncLookup
!= (void*)&dyld_func_lookup
)
2185 dd
->dyldFuncLookup
= (void*)&dyld_func_lookup
;
2187 //if ( fDATAdyld->size > offsetof(DATAdyld, startDebugThread) )
2188 // dd->startDebugThread = &start_debug_thread;
2190 //if ( fDATAdyld->size > offsetof(DATAdyld, stubBindHelper) )
2191 // save = dd->stubBindHelper;
2195 if ( ! this->usablePrebinding(context
) || !this->usesTwoLevelNameSpace() ) {
2196 // reset all "fast" stubs
2197 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2198 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2199 const struct load_command
* cmd
= cmds
;
2200 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2202 case LC_SEGMENT_COMMAND
:
2204 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2205 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2206 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2207 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2208 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2209 if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2210 // reset each jmp entry in this section
2211 uint8_t* start
= (uint8_t*)(sect
->addr
+ this->fSlide
);
2212 uint8_t* end
= start
+ sect
->size
;
2213 uintptr_t dyldHandler
= (uintptr_t)&fast_stub_binding_helper_interface
;
2214 for (uint8_t* entry
= start
; entry
< end
; entry
+= 5) {
2215 uint32_t rel32
= dyldHandler
- (((uint32_t)entry
)+5);
2216 entry
[0] = 0xE8; // CALL rel32
2217 entry
[1] = rel32
& 0xFF;
2218 entry
[2] = (rel32
>> 8) & 0xFF;
2219 entry
[3] = (rel32
>> 16) & 0xFF;
2220 entry
[4] = (rel32
>> 24) & 0xFF;
2226 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2232 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
2234 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2235 if ( this->isPrebindable() && this->allDependentLibrariesAsWhenPreBound() && (this->getSlide() == 0) ) {
2236 // allow environment variables to disable prebinding
2237 if ( context
.bindFlat
)
2239 switch ( context
.prebindUsage
) {
2240 case kUseAllPrebinding
:
2242 case kUseSplitSegPrebinding
:
2243 return this->fIsSplitSeg
;
2244 case kUseAllButAppPredbinding
:
2245 return (this != context
.mainExecutable
);
2246 case kUseNoPrebinding
:
2253 void ImageLoaderMachO::doBind(const LinkContext
& context
, BindingLaziness bindness
)
2255 // set dyld entry points in image
2256 this->setupLazyPointerHandler(context
);
2258 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2259 // note: flat-namespace binaries need to be imports rebound (even if correctly prebound)
2260 if ( this->usablePrebinding(context
) && this->usesTwoLevelNameSpace() ) {
2261 // if image has coalesced symbols, then these need to be rebound, unless this is the only image with weak symbols
2262 if ( this->needsCoalescing() && (fgCountOfImagesWithWeakExports
> 1) ) {
2263 this->doBindExternalRelocations(context
, true);
2264 this->doBindIndirectSymbolPointers(context
, kLazyAndNonLazy
, true);
2266 // skip binding because prebound and prebinding not disabled
2270 // values bound by name are stored two different ways in mach-o
2273 case kLazyAndNonLazy
:
2274 // external relocations are used for data initialized to external symbols
2275 this->doBindExternalRelocations(context
, false);
2278 case kLazyOnlyNoDependents
:
2281 // "indirect symbols" are used for code references to external symbols
2282 this->doBindIndirectSymbolPointers(context
, bindness
, false);
2287 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
2289 if ( fDashInit
!= NULL
) {
2290 Initializer func
= (Initializer
)(fDashInit
->init_address
+ fSlide
);
2291 if ( context
.verboseInit
)
2292 fprintf(stderr
, "dyld: calling -init function 0x%p in %s\n", func
, this->getPath());
2293 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2297 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
2299 if ( fModInitSection
!= NULL
) {
2300 Initializer
* inits
= (Initializer
*)(fModInitSection
->addr
+ fSlide
);
2301 const uint32_t count
= fModInitSection
->size
/ sizeof(uintptr_t);
2302 for (uint32_t i
=0; i
< count
; ++i
) {
2303 Initializer func
= inits
[i
];
2304 if ( context
.verboseInit
)
2305 fprintf(stderr
, "dyld: calling initializer function %p in %s\n", func
, this->getPath());
2306 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2312 void ImageLoaderMachO::doInitialization(const LinkContext
& context
)
2314 // mach-o has -init and static initializers
2315 doImageInit(context
);
2316 doModInitFunctions(context
);
2319 bool ImageLoaderMachO::needsInitialization()
2321 return ( (fDashInit
!= NULL
) || (fModInitSection
!= NULL
) );
2325 bool ImageLoaderMachO::needsTermination()
2327 return ( fModTermSection
!= NULL
);
2330 bool ImageLoaderMachO::hasImageNotification()
2332 return ( fImageNotifySection
!= NULL
);
2336 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
2338 if ( fModTermSection
!= NULL
) {
2339 Terminator
* terms
= (Terminator
*)(fModTermSection
->addr
+ fSlide
);
2340 const uint32_t count
= fModTermSection
->size
/ sizeof(uintptr_t);
2341 for (uint32_t i
=count
; i
> 0; --i
) {
2342 Terminator func
= terms
[i
-1];
2343 if ( context
.verboseInit
)
2344 fprintf(stderr
, "dyld: calling terminaton function %p in %s\n", func
, this->getPath());
2350 void ImageLoaderMachO::doNotification(enum dyld_image_mode mode
, uint32_t infoCount
, const struct dyld_image_info info
[])
2352 if ( fImageNotifySection
!= NULL
) {
2353 dyld_image_notifier
* notes
= (dyld_image_notifier
*)(fImageNotifySection
->addr
+ fSlide
);
2354 const uint32_t count
= fImageNotifySection
->size
/ sizeof(uintptr_t);
2355 for (uint32_t i
=count
; i
> 0; --i
) {
2356 dyld_image_notifier func
= notes
[i
-1];
2357 func(mode
, infoCount
, info
);
2362 void ImageLoaderMachO::printStatistics(unsigned int imageCount
)
2364 ImageLoader::printStatistics(imageCount
);
2365 fprintf(stderr
, "total hinted binary tree searches: %d\n", fgHintedBinaryTreeSearchs
);
2366 fprintf(stderr
, "total unhinted binary tree searches: %d\n", fgUnhintedBinaryTreeSearchs
);
2367 fprintf(stderr
, "total images with weak exports: %d\n", fgCountOfImagesWithWeakExports
);
2369 #if LINKEDIT_USAGE_DEBUG
2370 fprintf(stderr
, "linkedit pages accessed (%lu):\n", sLinkEditPageBuckets
.size());
2374 void ImageLoaderMachO::doPrebinding(const LinkContext
& context
, time_t timestamp
, uint8_t* fileToPrebind
)
2376 // update __DATA segment
2377 this->applyPrebindingToDATA(fileToPrebind
);
2379 // update load commands
2380 this->applyPrebindingToLoadCommands(context
, fileToPrebind
, timestamp
);
2382 // update symbol table
2383 this->applyPrebindingToLinkEdit(context
, fileToPrebind
);
2386 void ImageLoaderMachO::applyPrebindingToDATA(uint8_t* fileToPrebind
)
2388 const unsigned int segmentCount
= fSegments
.size();
2389 for(unsigned int i
=0; i
< segmentCount
; ++i
) {
2390 SegmentMachO
* seg
= (SegmentMachO
*)fSegments
[i
];
2391 if ( seg
->writeable() ) {
2392 memcpy(&fileToPrebind
[seg
->fFileOffset
], (void*)seg
->getActualLoadAddress(), seg
->fFileSize
);
2397 void ImageLoaderMachO::applyPrebindingToLoadCommands(const LinkContext
& context
, uint8_t* fileToPrebind
, time_t timestamp
)
2399 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2400 const uint32_t cmd_count
= mh
->ncmds
;
2401 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2402 const struct load_command
* cmd
= cmds
;
2403 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2406 case LC_LOAD_WEAK_DYLIB
:
2408 // update each dylib load command with the timestamp of the target dylib
2409 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2410 const char* name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
2411 for (const DependentLibrary
* dl
=fLibraries
; dl
< &fLibraries
[fLibrariesCount
]; dl
++) {
2412 if (strcmp(dl
->name
, name
) == 0 ) {
2413 // found matching DependentLibrary for this load command
2414 ImageLoaderMachO
* targetImage
= (ImageLoaderMachO
*)(dl
->image
); // !!! assume only mach-o images are prebound
2415 if ( ! targetImage
->isPrebindable() )
2416 throw "dependent dylib is not prebound";
2417 // if the target is currently being re-prebound then its timestamp will be the same as this one
2418 if ( ! targetImage
->usablePrebinding(context
) ) {
2419 dylib
->dylib
.timestamp
= timestamp
;
2422 // otherwise dependent library is already correctly prebound, so use its checksum
2423 dylib
->dylib
.timestamp
= targetImage
->doGetLibraryInfo().checksum
;
2432 // update the ID of this library with the new timestamp
2433 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2434 dylib
->dylib
.timestamp
= timestamp
;
2437 case LC_SEGMENT_COMMAND
:
2438 // if dylib was rebased, update segment commands
2439 if ( fSlide
!= 0 ) {
2440 struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2441 seg
->vmaddr
+= fSlide
;
2442 struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2443 struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2444 for (struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2445 sect
->addr
+= fSlide
;
2449 case LC_ROUTINES_COMMAND
:
2450 // if dylib was rebased, update -init command
2451 if ( fSlide
!= 0 ) {
2452 struct macho_routines_command
* routines
= (struct macho_routines_command
*)cmd
;
2453 routines
->init_address
+= fSlide
;
2457 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2461 void ImageLoaderMachO::applyPrebindingToLinkEdit(const LinkContext
& context
, uint8_t* fileToPrebind
)
2463 // In prebound images, the n_value of the symbol table entry for is the prebound address
2464 // This is needed when prebinding can't be used, to back solve for any possible addend in non-lazy pointers
2465 const char* stringPool
= NULL
;
2466 struct macho_nlist
* symbolTable
= NULL
;
2467 const struct dysymtab_command
* dysymtab
= NULL
;
2469 // get symbol table info
2470 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2471 const uint32_t cmd_count
= mh
->ncmds
;
2472 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2473 const struct load_command
* cmd
= cmds
;
2474 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2478 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
2479 stringPool
= (const char*)&fileToPrebind
[symtab
->stroff
];
2480 symbolTable
= (struct macho_nlist
*)(&fileToPrebind
[symtab
->symoff
]);
2484 dysymtab
= (struct dysymtab_command
*)cmd
;
2487 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2490 // walk all imports and re-resolve their n_value (needed incase prebinding is invalid)
2491 struct macho_nlist
* lastImport
= &symbolTable
[dysymtab
->iundefsym
+dysymtab
->nundefsym
];
2492 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iundefsym
]; entry
< lastImport
; ++entry
) {
2494 entry
->n_value
= this->resolveUndefined(context
, entry
, this->usesTwoLevelNameSpace(), &dummy
);
2497 // walk all exports and slide their n_value
2498 struct macho_nlist
* lastExport
= &symbolTable
[dysymtab
->iextdefsym
+dysymtab
->nextdefsym
];
2499 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iextdefsym
]; entry
< lastExport
; ++entry
) {
2500 if ( (entry
->n_type
& N_TYPE
) == N_SECT
)
2501 entry
->n_value
+= fSlide
;
2504 // walk all local symbols and slide their n_value
2505 struct macho_nlist
* lastLocal
= &symbolTable
[dysymtab
->ilocalsym
+dysymtab
->nlocalsym
];
2506 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->ilocalsym
]; entry
< lastLocal
; ++entry
) {
2507 if ( entry
->n_sect
!= NO_SECT
)
2508 entry
->n_value
+= fSlide
;
2511 // walk all local relocations and reset every PPC_RELOC_PB_LA_PTR r_value
2512 relocation_info
* const relocsStart
= (struct relocation_info
*)(&fileToPrebind
[dysymtab
->locreloff
]);
2513 relocation_info
* const relocsEnd
= &relocsStart
[dysymtab
->nlocrel
];
2514 for (relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2515 if ( (reloc
->r_address
& R_SCATTERED
) != 0 ) {
2516 struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
2517 if (sreloc
->r_length
== RELOC_SIZE
) {
2518 switch(sreloc
->r_type
) {
2519 #if __ppc__ || __ppc64__
2520 case PPC_RELOC_PB_LA_PTR
:
2522 case GENERIC_RELOC_PB_LA_PTR
:
2524 #error unknown architecture
2526 sreloc
->r_value
+= fSlide
;
2533 // if multi-module, fix up objc_addr (10.4 and later runtime does not use this, but we want to keep file checksum consistent)
2534 if ( dysymtab
->nmodtab
!= 0 ) {
2535 dylib_module
* const modulesStart
= (struct dylib_module
*)(&fileToPrebind
[dysymtab
->modtaboff
]);
2536 dylib_module
* const modulesEnd
= &modulesStart
[dysymtab
->nmodtab
];
2537 for (dylib_module
* module=modulesStart
; module < modulesEnd
; ++module) {
2538 if ( module->objc_module_info_size
!= 0 ) {
2539 module->objc_module_info_addr
+= fSlide
;
2545 // file on disk has been reprebound, but we are still mapped to old file
2546 void ImageLoaderMachO::prebindUnmap(const LinkContext
& context
)
2548 // this removes all mappings to the old file, so the kernel will unlink (delete) it.
2549 // We need to leave the load commands and __LINKEDIT in place
2550 for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it
!= fSegments
.end(); ++it
) {
2551 void* segmentAddress
= (void*)((*it
)->getActualLoadAddress());
2552 uintptr_t segmentSize
= (*it
)->getSize();
2553 //fprintf(stderr, "unmapping segment %s at %p for %s\n", (*it)->getName(), segmentAddress, this->getPath());
2554 // save load commands at beginning of __TEXT segment
2555 if ( segmentAddress
== fMachOData
) {
2556 // typically load commands are one or two pages in size, so ok to alloc on stack
2557 uint32_t loadCmdSize
= sizeof(macho_header
) + ((macho_header
*)fMachOData
)->sizeofcmds
;
2558 uint32_t loadCmdPages
= (loadCmdSize
+4095) & (-4096);
2559 uint8_t loadcommands
[loadCmdPages
];
2560 memcpy(loadcommands
, fMachOData
, loadCmdPages
);
2561 // unmap whole __TEXT segment
2562 munmap((void*)(fMachOData
), segmentSize
);
2563 // allocate and copy back mach_header and load commands
2564 vm_address_t addr
= (vm_address_t
)fMachOData
;
2565 int r2
= vm_allocate(mach_task_self(), &addr
, loadCmdPages
, false /*at this address*/);
2567 fprintf(stderr
, "prebindUnmap() vm_allocate for __TEXT %d failed\n", loadCmdPages
);
2568 memcpy((void*)fMachOData
, loadcommands
, loadCmdPages
);
2569 //fprintf(stderr, "copying back load commands to %p size=%u for %s\n", segmentAddress, loadCmdPages, this->getPath());
2571 else if ( strcmp((*it
)->getName(), "__LINKEDIT") == 0 ) {
2572 uint32_t linkEditSize
= segmentSize
;
2573 uint32_t linkEditPages
= (linkEditSize
+4095) & (-4096);
2574 void* linkEditTmp
= malloc(linkEditPages
);
2575 memcpy(linkEditTmp
, segmentAddress
, linkEditPages
);
2576 // unmap whole __LINKEDIT segment
2577 munmap(segmentAddress
, segmentSize
);
2578 vm_address_t addr
= (vm_address_t
)segmentAddress
;
2579 int r2
= vm_allocate(mach_task_self(), &addr
, linkEditPages
, false /*at this address*/);
2581 fprintf(stderr
, "prebindUnmap() vm_allocate for __LINKEDIT %d failed\n", linkEditPages
);
2582 memcpy(segmentAddress
, linkEditTmp
, linkEditPages
);
2583 //fprintf(stderr, "copying back __LINKEDIT to %p size=%u for %s\n", segmentAddress, linkEditPages, this->getPath());
2587 // unmap any other segment
2588 munmap((void*)(segmentAddress
), (*it
)->getSize());
2595 SegmentMachO::SegmentMachO(const struct macho_segment_command
* cmd
, ImageLoaderMachO
* image
, const uint8_t* fileData
)
2596 : fImage(image
), fSize(cmd
->vmsize
), fFileSize(cmd
->filesize
), fFileOffset(cmd
->fileoff
), fPreferredLoadAddress(cmd
->vmaddr
),
2597 fVMProtection(cmd
->initprot
), fHasFixUps(false), fUnMapOnDestruction(false)
2599 strncpy(fName
, cmd
->segname
, 16);
2601 // scan sections for fix-up bit
2602 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)cmd
+ sizeof(struct macho_segment_command
));
2603 const struct macho_section
* const sectionsEnd
= §ionsStart
[cmd
->nsects
];
2604 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2605 if ( (sect
->flags
& (S_ATTR_EXT_RELOC
| S_ATTR_LOC_RELOC
)) != 0 )
2610 SegmentMachO::~SegmentMachO()
2612 if ( fUnMapOnDestruction
) {
2613 //fprintf(stderr, "unmapping segment %s at 0x%08lX\n", getName(), getActualLoadAddress());
2614 munmap((void*)(this->getActualLoadAddress()), this->getSize());
2618 const ImageLoader
* SegmentMachO::getImage()
2623 const char* SegmentMachO::getName()
2628 uintptr_t SegmentMachO::getSize()
2633 uintptr_t SegmentMachO::getFileSize()
2638 uintptr_t SegmentMachO::getFileOffset()
2643 bool SegmentMachO::readable()
2645 return ( (fVMProtection
& VM_PROT_READ
) != 0);
2648 bool SegmentMachO::writeable()
2650 return ((fVMProtection
& VM_PROT_WRITE
) != 0);
2653 bool SegmentMachO::executable()
2655 return ((fVMProtection
& VM_PROT_EXECUTE
) != 0);
2658 bool SegmentMachO::unaccessible()
2660 return (fVMProtection
== 0);
2663 bool SegmentMachO::hasFixUps()
2668 uintptr_t SegmentMachO::getActualLoadAddress()
2670 return fPreferredLoadAddress
+ fImage
->fSlide
;
2673 uintptr_t SegmentMachO::getPreferredLoadAddress()
2675 return fPreferredLoadAddress
;
2678 bool SegmentMachO::hasPreferredLoadAddress()
2680 return (fPreferredLoadAddress
!= 0);
2683 void SegmentMachO::setUnMapWhenDestructed(bool unmap
)
2685 fUnMapOnDestruction
= unmap
;
2688 static uint32_t *buildCRCTable(void)
2690 uint32_t *table
= new uint32_t[256];
2691 uint32_t p
= 0xedb88320UL
; // standard CRC-32 polynomial
2693 for (unsigned int i
= 0; i
< 256; i
++) {
2695 for (unsigned int j
= 0; j
< 8; j
++) {
2696 if ( c
& 1 ) c
= p
^ (c
>> 1);
2705 uint32_t SegmentMachO::crc32()
2707 if ( !readable() ) return 0;
2709 static uint32_t *crcTable
= NULL
;
2710 if ( !crcTable
) crcTable
= buildCRCTable();
2712 uint32_t crc
= ~(uint32_t)0;
2713 uint8_t *p
= (uint8_t *)getActualLoadAddress();
2714 uint8_t *end
= p
+ getSize();
2716 crc
= crcTable
[(crc
& 0xff) ^ (*p
++)] ^ (crc
>> 8);
2718 return crc
^ ~(uint32_t)0;