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
{};
79 #define POINTER_RELOC GENERIC_RELOC_VANILLA
81 uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs
= 0;
82 uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
= 0;
83 uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports
= 0;
86 //#define LINKEDIT_USAGE_DEBUG 1
88 #if LINKEDIT_USAGE_DEBUG
90 static std::set
<uintptr_t> sLinkEditPageBuckets
;
93 extern ImageLoader
* findImageContainingAddress(const void* addr
);
96 static void noteAccessedLinkEditAddress(const void* addr
)
98 uintptr_t page
= ((uintptr_t)addr
) & (-4096);
99 sLinkEditPageBuckets
.insert(page
);
100 fprintf(stderr
, "dyld: accessing page 0x%08lX in __LINKEDIT of %s\n", page
, dyld::findImageContainingAddress(addr
)->getPath());
104 // only way to share initialization in C++
105 void ImageLoaderMachO::init()
108 fLinkEditBase
= NULL
;
114 fHasSubLibraries
= false;
115 fHasSubUmbrella
= false;
117 fModInitSection
= NULL
;
118 fModTermSection
= NULL
;
120 fImageNotifySection
= NULL
;
121 fTwoLevelHints
= NULL
;
123 fReExportThruFramework
= NULL
;
124 fTextSegmentWithFixups
= NULL
;
127 // create image by copying an in-memory mach-o file
128 ImageLoaderMachO::ImageLoaderMachO(const char* moduleName
, const struct mach_header
* mh
, uint64_t len
, const LinkContext
& context
)
129 : ImageLoader(moduleName
)
134 // temporary use this buffer until TEXT is mapped in
135 fMachOData
= (const uint8_t*)mh
;
138 this->instantiateSegments((const uint8_t*)mh
);
141 if ( mh
->filetype
!= MH_EXECUTE
)
142 ImageLoader::mapSegments((const void*)mh
, len
, context
);
144 // get pointers to interesting things
145 this->parseLoadCmds();
149 // create image by mapping in a mach-o file
150 ImageLoaderMachO::ImageLoaderMachO(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,
151 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
152 : ImageLoader(path
, offsetInFat
, info
)
157 // read load commands
158 const unsigned int dataSize
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
;
159 uint8_t buffer
[dataSize
];
160 const uint8_t* fileData
= firstPage
;
161 if ( dataSize
> 4096 ) {
162 // only read more if cmds take up more space than first page
164 memcpy(buffer
, firstPage
, 4096);
165 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096);
168 // temporary use this buffer until TEXT is mapped in
169 fMachOData
= fileData
;
171 // the meaning of many fields changes in split seg mach-o files
172 fIsSplitSeg
= ((((macho_header
*)fileData
)->flags
& MH_SPLIT_SEGS
) != 0) && (((macho_header
*)fileData
)->filetype
== MH_DYLIB
);
175 this->instantiateSegments(fileData
);
177 // map segments, except for main executable which is already mapped in by kernel
178 if ( ((macho_header
*)fileData
)->filetype
!= MH_EXECUTE
)
179 this->mapSegments(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
);
181 // get pointers to interesting things
182 this->parseLoadCmds();
185 ImageLoaderMachO::~ImageLoaderMachO()
187 // keep count of images with weak exports
188 if ( this->hasCoalescedExports() )
189 --fgCountOfImagesWithWeakExports
;
194 void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData
)
196 const uint32_t cmd_count
= ((macho_header
*)fileData
)->ncmds
;
197 const struct load_command
* const cmds
= (struct load_command
*)&fileData
[sizeof(macho_header
)];
199 // construct Segment object for each LC_SEGMENT cmd and add to list
200 const struct load_command
* cmd
= cmds
;
201 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
202 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
203 if ( (((struct macho_segment_command
*)cmd
)->vmsize
!= 0) || !fIsSplitSeg
)
204 fSegments
.push_back(new SegmentMachO((struct macho_segment_command
*)cmd
, this, fileData
));
206 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
212 bool ImageLoaderMachO::segmentsMustSlideTogether() const
217 bool ImageLoaderMachO::segmentsCanSlide() const
219 const macho_header
* mh
= (macho_header
*)fMachOData
;
220 return ( (mh
->filetype
== MH_DYLIB
) || (mh
->filetype
== MH_BUNDLE
) );
223 bool ImageLoaderMachO::isBundle() const
225 const macho_header
* mh
= (macho_header
*)fMachOData
;
226 return ( mh
->filetype
== MH_BUNDLE
);
229 bool ImageLoaderMachO::isDylib() const
231 const macho_header
* mh
= (macho_header
*)fMachOData
;
232 return ( mh
->filetype
== MH_DYLIB
);
235 bool ImageLoaderMachO::forceFlat() const
237 const macho_header
* mh
= (macho_header
*)fMachOData
;
238 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
241 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
243 const macho_header
* mh
= (macho_header
*)fMachOData
;
244 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
247 bool ImageLoaderMachO::isPrebindable() const
249 const macho_header
* mh
= (macho_header
*)fMachOData
;
250 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
253 bool ImageLoaderMachO::hasCoalescedExports() const
255 const macho_header
* mh
= (macho_header
*)fMachOData
;
256 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
259 bool ImageLoaderMachO::needsCoalescing() const
261 const macho_header
* mh
= (macho_header
*)fMachOData
;
262 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
265 #if !__LP64__ // split segs not supported for 64-bits
267 #if 1 // hack until kernel headers and glue are in system
268 struct _shared_region_mapping_np
{
269 mach_vm_address_t address
;
271 mach_vm_offset_t file_offset
;
272 vm_prot_t max_prot
; /* read/write/execute/COW/ZF */
273 vm_prot_t init_prot
; /* read/write/execute/COW/ZF */
275 struct _shared_region_range_np
{
276 mach_vm_address_t address
;
281 // Requests the kernel to map a number of regions from the fd into the
282 // shared sections address range (0x90000000-0xAFFFFFFF).
283 // If shared_region_make_private_np() has not been called by this process,
284 // the file mapped in is seen in the address space of all processes that
285 // participate in using the shared region.
286 // If shared_region_make_private_np() _has_ been called by this process,
287 // the file mapped in is only seen by this process.
288 // If the slide parameter is not NULL and then regions cannot be mapped
289 // as requested, the kernel will try to map the file in at a different
290 // address in the shared region and return the distance slid.
291 // If the mapping requesting cannot be fulfilled, returns non-zero.
293 _shared_region_map_file_np(
294 int fd
, // file descriptor to map into shared region
295 unsigned int regionCount
, // number of entres in array of regions
296 const _shared_region_mapping_np regions
[], // the array of regions to map
297 uint64_t* slide
) // the amount all regions were slid, NULL means don't attempt to slide
299 //fprintf(stderr, "%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide);
300 //for ( unsigned int i=0; i < regionCount; ++i) {
301 // fprintf(stderr, "\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size);
303 int r
= syscall(299, fd
, regionCount
, regions
, slide
);
305 // fprintf(stderr, "%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno));
308 // Called by dyld if shared_region_map_file() fails.
309 // Requests the kernel to take this process out of using the shared region.
310 // The specified ranges are created as private copies from the shared region for this process.
312 _shared_region_make_private_np(
313 unsigned int rangeCount
, // number of entres in array of msrp_range
314 const _shared_region_range_np ranges
[]) // the array of shared regions to make private
316 //fprintf(stderr, "%s(%u, %8p)\n", __func__, rangeCount, ranges);
317 int r
= syscall(300, rangeCount
, ranges
);
319 // fprintf(stderr, "%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno));
322 #define KERN_SHREG_PRIVATIZABLE 54
323 #endif // hack until kernel headers and glue are in system
325 static uintptr_t sNextAltLoadAddress
333 _shared_region_map_file_with_mmap(
334 int fd
, // file descriptor to map into shared region
335 unsigned int regionCount
, // number of entres in array of regions
336 const _shared_region_mapping_np regions
[]) // the array of regions to map
338 // map in each region
339 for(unsigned int i
=0; i
< regionCount
; ++i
) {
340 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
);
341 size_t size
= regions
[i
].size
;
342 if ( (regions
[i
].init_prot
& VM_PROT_ZF
) != 0 ) {
343 // do nothing already vm_allocate() which zero fills
347 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
348 protection
|= PROT_EXEC
;
349 if ( regions
[i
].init_prot
& VM_PROT_READ
)
350 protection
|= PROT_READ
;
351 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
352 protection
|= PROT_WRITE
;
353 off_t offset
= regions
[i
].file_offset
;
354 //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
355 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FILE
| MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
356 if ( mmapAddress
== ((void*)(-1)) )
367 hasSharedRegionMapFile(void)
369 int mib
[CTL_MAXNAME
];
374 mib
[1] = KERN_SHREG_PRIVATIZABLE
;
376 if (sysctl(mib
, 2, &value
, &size
, NULL
, 0) != 0) {
384 ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd
,
385 uint64_t offsetInFat
,
388 const LinkContext
& context
)
390 const unsigned int segmentCount
= fSegments
.size();
391 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
392 const unsigned int regionCount
= segmentCount
+extraZeroFillEntries
;
393 _shared_region_mapping_np regions
[regionCount
];
394 initMappingTable(offsetInFat
, regions
);
396 // find space somewhere to allocate split seg
397 bool foundRoom
= false;
398 vm_size_t biggestDiff
= 0;
399 while ( ! foundRoom
) {
401 for(unsigned int i
=0; i
< regionCount
; ++i
) {
402 vm_address_t addr
= sNextAltLoadAddress
+ regions
[i
].address
- regions
[0].address
;
403 vm_size_t size
= regions
[i
].size
;
404 r
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/);
406 // no room here, deallocate what has succeeded so far
407 for(unsigned int j
=0; j
< i
; ++j
) {
408 vm_address_t addr
= sNextAltLoadAddress
+ regions
[j
].address
- regions
[0].address
;
409 vm_size_t size
= regions
[j
].size
;
410 (void)vm_deallocate(mach_task_self(), addr
, size
);
412 sNextAltLoadAddress
+= 0x00100000; // skip ahead 1MB and try again
413 if ( (sNextAltLoadAddress
& 0xF0000000) == 0x90000000 )
414 sNextAltLoadAddress
= 0xB0000000;
415 if ( (sNextAltLoadAddress
& 0xF0000000) == 0xF0000000 )
416 throw "can't map split seg anywhere";
420 vm_size_t high
= (regions
[i
].address
+ size
- regions
[0].address
) & 0x0FFFFFFF;
421 if ( high
> biggestDiff
)
426 // map in each region
427 uintptr_t slide
= sNextAltLoadAddress
- regions
[0].address
;
428 this->setSlide(slide
);
429 for(unsigned int i
=0; i
< regionCount
; ++i
) {
430 if ( (regions
[i
].init_prot
& VM_PROT_ZF
) != 0 ) {
431 // do nothing vm_allocate() zero-fills by default
434 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
+ slide
);
435 size_t size
= regions
[i
].size
;
437 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
438 protection
|= PROT_EXEC
;
439 if ( regions
[i
].init_prot
& VM_PROT_READ
)
440 protection
|= PROT_READ
;
441 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
442 protection
|= PROT_WRITE
;
443 off_t offset
= regions
[i
].file_offset
;
444 //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
445 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FILE
| MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
446 if ( mmapAddress
== ((void*)(-1)) )
450 // set so next maps right after this one
451 sNextAltLoadAddress
+= biggestDiff
;
452 sNextAltLoadAddress
= (sNextAltLoadAddress
+ 4095) & (-4096);
455 if ( context
.verboseMapping
) {
456 fprintf(stderr
, "dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide
, this->getPath());
457 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
458 Segment
* seg
= fSegments
[segIndex
];
459 const _shared_region_mapping_np
* entry
= ®ions
[entryIndex
];
460 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
461 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
462 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
463 if ( entryIndex
< (regionCount
-1) ) {
464 const _shared_region_mapping_np
* nextEntry
= ®ions
[entryIndex
+1];
465 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
466 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
467 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
468 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
479 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
481 enum SharedRegionState
483 kSharedRegionStartState
= 0,
484 kSharedRegionLoadFileState
,
485 kSharedRegionMapFileState
,
486 kSharedRegionMapFilePrivateState
,
487 kSharedRegionMapFilePrivateMMapState
,
488 kSharedRegionMapFilePrivateOutsideState
,
490 static SharedRegionState sSharedRegionState
= kSharedRegionStartState
;
492 // non-split segment libraries handled by super class
494 return ImageLoader::mapSegments(fd
, offsetInFat
, lenInFat
, fileLen
, context
);
496 if ( kSharedRegionStartState
== sSharedRegionState
) {
497 if ( hasSharedRegionMapFile() ) {
498 if ( context
.slideAndPackDylibs
) {
499 sharedRegionMakePrivate(context
);
500 // remove underlying submap and block out 0x90000000 to 0xAFFFFFFF
501 vm_address_t addr
= (vm_address_t
)0x90000000;
502 vm_deallocate(mach_task_self(), addr
, 0x20000000);
503 vm_allocate(mach_task_self(), &addr
, 0x20000000, false);
504 sSharedRegionState
= kSharedRegionMapFilePrivateMMapState
;
506 else if ( context
.sharedRegionMode
== kUsePrivateSharedRegion
) {
507 sharedRegionMakePrivate(context
);
508 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
510 else if ( context
.sharedRegionMode
== kDontUseSharedRegion
) {
511 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
514 sSharedRegionState
= kSharedRegionMapFileState
;
518 sSharedRegionState
= kSharedRegionLoadFileState
;
522 if ( kSharedRegionLoadFileState
== sSharedRegionState
) {
523 if ( 0 != sharedRegionLoadFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
524 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
528 if ( kSharedRegionMapFileState
== sSharedRegionState
) {
529 if ( 0 != sharedRegionMapFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
530 sharedRegionMakePrivate(context
);
531 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
535 if ( (kSharedRegionMapFilePrivateState
== sSharedRegionState
) || (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
) ) {
536 if ( 0 != sharedRegionMapFilePrivate(fd
, offsetInFat
, lenInFat
, fileLen
, context
, (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
)) ) {
537 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
541 if ( kSharedRegionMapFilePrivateOutsideState
== sSharedRegionState
) {
542 if ( 0 != sharedRegionMapFilePrivateOutside(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
543 throw "mapping error";
549 ImageLoaderMachO::getExtraZeroFillEntriesCount()
551 // calculate mapping entries
552 const unsigned int segmentCount
= fSegments
.size();
553 unsigned int extraZeroFillEntries
= 0;
554 for(unsigned int i
=0; i
< segmentCount
; ++i
){
555 Segment
* seg
= fSegments
[i
];
556 if ( seg
->hasTrailingZeroFill() )
557 ++extraZeroFillEntries
;
560 return extraZeroFillEntries
;
564 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
565 _shared_region_mapping_np
*mappingTable
)
567 unsigned int segmentCount
= fSegments
.size();
568 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
569 Segment
* seg
= fSegments
[segIndex
];
570 _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
571 entry
->address
= seg
->getActualLoadAddress();
572 entry
->size
= seg
->getFileSize();
573 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
574 entry
->init_prot
= VM_PROT_NONE
;
575 if ( !seg
->unaccessible() ) {
576 if ( seg
->executable() )
577 entry
->init_prot
|= VM_PROT_EXECUTE
;
578 if ( seg
->readable() )
579 entry
->init_prot
|= VM_PROT_READ
;
580 if ( seg
->writeable() )
581 entry
->init_prot
|= VM_PROT_WRITE
| VM_PROT_COW
;
583 entry
->max_prot
= entry
->init_prot
;
584 if ( seg
->hasTrailingZeroFill() ) {
585 _shared_region_mapping_np
* zfentry
= &mappingTable
[++entryIndex
];
586 zfentry
->address
= entry
->address
+ seg
->getFileSize();
587 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
588 zfentry
->file_offset
= 0;
589 zfentry
->init_prot
= entry
->init_prot
| VM_PROT_COW
| VM_PROT_ZF
;
590 zfentry
->max_prot
= zfentry
->init_prot
;
596 ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext
& context
)
598 if ( context
.verboseMapping
)
599 fprintf(stderr
, "dyld: making shared regions private\n");
601 // shared mapping failed, so make private copy of shared region and try mapping private
602 RegionsVector allRegions
;
603 context
.getAllMappedRegions(allRegions
);
604 std::vector
<_shared_region_range_np
> splitSegRegions
;
605 const unsigned int allRegiontCount
= allRegions
.size();
606 for(unsigned int i
=0; i
< allRegiontCount
; ++i
){
607 MappedRegion region
= allRegions
[i
];
608 uint8_t highByte
= region
.address
>> 28;
609 if ( (highByte
== 9) || (highByte
== 0xA) ) {
610 _shared_region_range_np splitRegion
;
611 splitRegion
.address
= region
.address
;
612 splitRegion
.size
= region
.size
;
613 splitSegRegions
.push_back(splitRegion
);
616 int result
= _shared_region_make_private_np(splitSegRegions
.size(), &splitSegRegions
[0]);
617 // notify gdb or other lurkers that this process is no longer using the shared region
618 dyld_all_image_infos
.processDetachedFromSharedRegion
= true;
623 ImageLoaderMachO::sharedRegionMapFile(int fd
,
624 uint64_t offsetInFat
,
627 const LinkContext
& context
)
629 // build table of segments to map
630 const unsigned int segmentCount
= fSegments
.size();
631 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
632 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
633 _shared_region_mapping_np mappingTable
[mappingTableCount
];
634 initMappingTable(offsetInFat
, mappingTable
);
636 uint64_t *slidep
= NULL
;
638 // try to map it in shared
639 int r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, slidep
);
641 if(NULL
!= slidep
&& 0 != *slidep
) {
642 // update with actual load addresses
644 if ( context
.verboseMapping
) {
645 fprintf(stderr
, "dyld: Mapping split-seg shared %s\n", this->getPath());
646 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
647 Segment
* seg
= fSegments
[segIndex
];
648 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
649 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
650 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
651 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
652 if ( entryIndex
< (mappingTableCount
-1) ) {
653 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
654 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
655 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
656 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
657 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
669 ImageLoaderMachO::sharedRegionMapFilePrivate(int fd
,
670 uint64_t offsetInFat
,
673 const LinkContext
& context
,
676 const unsigned int segmentCount
= fSegments
.size();
678 // adjust base address of segments to pack next to last dylib
679 if ( context
.slideAndPackDylibs
) {
680 uintptr_t lowestReadOnly
= (uintptr_t)(-1);
681 uintptr_t lowestWritable
= (uintptr_t)(-1);
682 for(unsigned int segIndex
=0; segIndex
< segmentCount
; ++segIndex
){
683 Segment
* seg
= fSegments
[segIndex
];
684 uintptr_t segEnd
= seg
->getActualLoadAddress();
685 if ( seg
->writeable() ) {
686 if ( segEnd
< lowestWritable
)
687 lowestWritable
= segEnd
;
690 if ( segEnd
< lowestReadOnly
)
691 lowestReadOnly
= segEnd
;
694 uintptr_t baseAddress
;
695 if ( lowestWritable
- 256*1024*1024 < lowestReadOnly
)
696 baseAddress
= lowestWritable
- 256*1024*1024;
698 baseAddress
= lowestReadOnly
;
699 // record that we want dylb slid to fgNextSplitSegAddress
700 this->setSlide(fgNextSplitSegAddress
- baseAddress
);
703 // build table of segments to map
704 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
705 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
706 _shared_region_mapping_np mappingTable
[mappingTableCount
];
707 initMappingTable(offsetInFat
, mappingTable
);
710 // try map it in privately (don't allow sliding if we pre-calculated the load address to pack dylibs)
713 r
= _shared_region_map_file_with_mmap(fd
, mappingTableCount
, mappingTable
);
715 r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, context
.slideAndPackDylibs
? NULL
: &slide
);
718 slide
= (slide
) & (-4096); // round down to page boundary
719 this->setSlide(slide
);
721 if ( context
.verboseMapping
) {
723 fprintf(stderr
, "dyld: Mapping split-seg un-shared %s\n", this->getPath());
725 fprintf(stderr
, "dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide
, this->getPath());
726 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
727 Segment
* seg
= fSegments
[segIndex
];
728 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
729 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
730 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
731 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
732 if ( entryIndex
< (mappingTableCount
-1) ) {
733 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
734 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
735 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
736 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
737 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
743 if ( context
.slideAndPackDylibs
) {
744 // calculate where next split-seg dylib can load
745 uintptr_t largestReadOnly
= 0;
746 uintptr_t largestWritable
= 0;
747 for (unsigned int segIndex
=0; segIndex
< segmentCount
; ++segIndex
) {
748 Segment
* seg
= fSegments
[segIndex
];
749 uintptr_t segEnd
= seg
->getActualLoadAddress()+seg
->getSize();
750 segEnd
= (segEnd
+4095) & (-4096); // page align
751 if ( seg
->writeable() ) {
752 if ( segEnd
> largestWritable
)
753 largestWritable
= segEnd
;
756 if ( segEnd
> largestReadOnly
)
757 largestReadOnly
= segEnd
;
760 if ( largestWritable
- 256*1024*1024 > largestReadOnly
)
761 fgNextSplitSegAddress
= largestWritable
- 256*1024*1024;
763 fgNextSplitSegAddress
= largestReadOnly
;
766 if ( context
.slideAndPackDylibs
&& (r
!= 0) )
767 throwf("can't rebase split-seg dylib %s because shared_region_map_file_np() returned %d", this->getPath(), r
);
774 ImageLoaderMachO::sharedRegionLoadFile(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
777 // map in split segment file at random address, then tell kernel to share it
778 void* loadAddress
= 0;
779 loadAddress
= mmap(NULL
, fileLen
, PROT_READ
, MAP_FILE
, fd
, 0);
780 if ( loadAddress
== ((void*)(-1)) )
783 // calculate mapping entries
784 const unsigned int segmentCount
= fSegments
.size();
785 unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
787 // build table of segments to map
788 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
789 const uintptr_t baseAddress
= fSegments
[0]->getPreferredLoadAddress();
790 sf_mapping mappingTable
[mappingTableCount
];
791 initMappingTable(offsetInFat
, mappingTable
, baseAddress
);
794 // use load_shared_file() to map all segments at once
795 int flags
= 0; // might need to set NEW_LOCAL_SHARED_REGIONS on first use
796 static bool firstTime
= true;
798 // when NEW_LOCAL_SHARED_REGIONS bit is set, this process will get is own shared region
799 // this is used by Xcode to prevent development libraries from polluting the global shared segment
800 if ( context
.sharedRegionMode
== kUsePrivateSharedRegion
)
801 flags
|= NEW_LOCAL_SHARED_REGIONS
;
805 caddr_t base_address
= (caddr_t
)baseAddress
;
807 r
= load_shared_file( (char*)fPath
, // path of file to map shared
808 (char*)loadAddress
, // beginning of local copy of sharable pages in file
809 fileLen
, // end of shareable pages in file
810 &base_address
, // beginning of address range to map
811 mappingTableCount
, // number of entres in array of sf_mapping
812 mappingTable
, // the array of sf_mapping
813 &flags
); // in/out flags
815 // try again but tell kernel it is ok to slide
816 flags
|= ALTERNATE_LOAD_SITE
;
817 r
= load_shared_file((char*)fPath
,(char*)loadAddress
, fileLen
, &base_address
,
818 mappingTableCount
, mappingTable
, &flags
);
821 // unmap file from random address now that they are (hopefully) mapped into the shared region
822 munmap(loadAddress
, fileLen
);
825 if ( base_address
!= (caddr_t
)baseAddress
)
826 this->setSlide((uintptr_t)base_address
- baseAddress
);
827 if ( context
.verboseMapping
) {
828 if ( base_address
!= (caddr_t
)baseAddress
)
829 fprintf(stderr
, "dyld: Mapping split-seg load_shared_alt_region %s\n", this->getPath());
831 fprintf(stderr
, "dyld: Mapping split-seg load_shared %s\n", this->getPath());
832 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
833 Segment
* seg
= fSegments
[segIndex
];
834 const sf_mapping
* entry
= &mappingTable
[entryIndex
];
835 if ( (entry
->protection
& VM_PROT_ZF
) == 0 )
836 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
837 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
838 if ( entryIndex
< (mappingTableCount
-1) ) {
839 const sf_mapping
* nextEntry
= &mappingTable
[entryIndex
+1];
840 if ( (nextEntry
->protection
& VM_PROT_ZF
) != 0 ) {
841 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
842 seg
->getName(), (uintptr_t)(nextEntry
->mapping_offset
+ base_address
), (uintptr_t)(nextEntry
->mapping_offset
+ base_address
+ nextEntry
->size
- 1));
852 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
853 sf_mapping
*mappingTable
,
854 uintptr_t baseAddress
)
856 unsigned int segmentCount
= fSegments
.size();
857 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
858 Segment
* seg
= fSegments
[segIndex
];
859 sf_mapping
* entry
= &mappingTable
[entryIndex
];
860 entry
->mapping_offset
= seg
->getPreferredLoadAddress() - baseAddress
;
861 entry
->size
= seg
->getFileSize();
862 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
863 entry
->protection
= VM_PROT_NONE
;
864 if ( !seg
->unaccessible() ) {
865 if ( seg
->executable() )
866 entry
->protection
|= VM_PROT_EXECUTE
;
867 if ( seg
->readable() )
868 entry
->protection
|= VM_PROT_READ
;
869 if ( seg
->writeable() )
870 entry
->protection
|= VM_PROT_WRITE
| VM_PROT_COW
;
874 if ( seg
->hasTrailingZeroFill() ) {
875 sf_mapping
* zfentry
= &mappingTable
[++entryIndex
];
876 zfentry
->mapping_offset
= entry
->mapping_offset
+ seg
->getFileSize();
877 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
878 zfentry
->file_offset
= 0;
879 zfentry
->protection
= entry
->protection
| VM_PROT_COW
| VM_PROT_ZF
;
885 #endif // !__LP64__ split segs not supported for 64-bits
888 void ImageLoaderMachO::setSlide(intptr_t slide
)
893 void ImageLoaderMachO::parseLoadCmds()
895 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
896 const unsigned int segmentCount
= fSegments
.size();
897 for(unsigned int i
=0; i
< segmentCount
; ++i
){
898 Segment
* seg
= fSegments
[i
];
899 // set up pointer to __LINKEDIT segment
900 if ( strcmp(seg
->getName(),"__LINKEDIT") == 0 )
901 fLinkEditBase
= (uint8_t*)(seg
->getActualLoadAddress() - seg
->getFileOffset());
902 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
903 if ( strcmp(seg
->getName(),"__TEXT") == 0 ) {
904 if ( seg
->hasFixUps() )
905 fTextSegmentWithFixups
= (SegmentMachO
*)seg
;
907 // some segment always starts at beginning of file and contains mach_header and load commands
908 if ( (seg
->getFileOffset() == 0) && (seg
->getFileSize() != 0) ) {
909 fMachOData
= (uint8_t*)(seg
->getActualLoadAddress());
913 // keep count of prebound images with weak exports
914 if ( this->hasCoalescedExports() )
915 ++fgCountOfImagesWithWeakExports
;
917 // walk load commands (mapped in at start of __TEXT segment)
918 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
919 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
920 const struct load_command
* cmd
= cmds
;
921 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
925 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
926 fStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
927 fSymbolTable
= (struct macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
931 fDynamicInfo
= (struct dysymtab_command
*)cmd
;
933 case LC_SUB_UMBRELLA
:
934 fHasSubUmbrella
= true;
936 case LC_SUB_FRAMEWORK
:
938 const struct sub_framework_command
* subf
= (struct sub_framework_command
*)cmd
;
939 fReExportThruFramework
= (char*)cmd
+ subf
->umbrella
.offset
;
943 fHasSubLibraries
= true;
945 case LC_ROUTINES_COMMAND
:
946 fDashInit
= (struct macho_routines_command
*)cmd
;
948 case LC_SEGMENT_COMMAND
:
950 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
951 const bool isDataSeg
= (strcmp(seg
->segname
, "__DATA") == 0);
952 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
953 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
954 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
955 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
956 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
957 fModInitSection
= sect
;
958 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
959 fModTermSection
= sect
;
960 else if ( isDataSeg
&& (strcmp(sect
->sectname
, "__dyld") == 0) ) {
963 else if ( isDataSeg
&& (strcmp(sect
->sectname
, "__image_notify") == 0) )
964 fImageNotifySection
= sect
;
968 case LC_TWOLEVEL_HINTS
:
969 fTwoLevelHints
= (struct twolevel_hints_command
*)cmd
;
973 fDylibID
= (struct dylib_command
*)cmd
;
976 case LC_LOAD_WEAK_DYLIB
:
977 // do nothing, just prevent LC_REQ_DYLD exception from occuring
980 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 )
981 throwf("unknown required load command 0x%08X", cmd
->cmd
);
983 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
990 const char* ImageLoaderMachO::getInstallPath() const
992 if ( fDylibID
!= NULL
) {
993 return (char*)fDylibID
+ fDylibID
->dylib
.name
.offset
;
998 // test if this image is re-exported through parent (the image that loaded this one)
999 bool ImageLoaderMachO::isSubframeworkOf(const LinkContext
& context
, const ImageLoader
* parent
) const
1001 if ( fReExportThruFramework
!= NULL
) {
1002 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
1003 const char* parentInstallPath
= parent
->getInstallPath();
1004 if ( parentInstallPath
!= NULL
) {
1005 const char* lastSlash
= strrchr(parentInstallPath
, '/');
1006 if ( lastSlash
!= NULL
) {
1007 if ( strcmp(&lastSlash
[1], fReExportThruFramework
) == 0 )
1009 if ( context
.imageSuffix
!= NULL
) {
1010 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1011 char reexportAndSuffix
[strlen(context
.imageSuffix
)+strlen(fReExportThruFramework
)+1];
1012 strcpy(reexportAndSuffix
, fReExportThruFramework
);
1013 strcat(reexportAndSuffix
, context
.imageSuffix
);
1014 if ( strcmp(&lastSlash
[1], reexportAndSuffix
) == 0 )
1023 // test if child is re-exported
1024 bool ImageLoaderMachO::hasSubLibrary(const LinkContext
& context
, const ImageLoader
* child
) const
1026 if ( fHasSubLibraries
) {
1027 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
1028 const char* childInstallPath
= child
->getInstallPath();
1029 if ( childInstallPath
!= NULL
) {
1030 const char* lastSlash
= strrchr(childInstallPath
, '/');
1031 if ( lastSlash
!= NULL
) {
1032 const char* firstDot
= strchr(lastSlash
, '.');
1034 if ( firstDot
== NULL
)
1035 len
= strlen(lastSlash
);
1037 len
= firstDot
-lastSlash
-1;
1038 char childLeafName
[len
+1];
1039 strncpy(childLeafName
, &lastSlash
[1], len
);
1040 childLeafName
[len
] = '\0';
1041 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1042 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1043 const struct load_command
* cmd
= cmds
;
1044 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1046 case LC_SUB_LIBRARY
:
1048 const struct sub_library_command
* lib
= (struct sub_library_command
*)cmd
;
1049 const char* aSubLibName
= (char*)cmd
+ lib
->sub_library
.offset
;
1050 if ( strcmp(aSubLibName
, childLeafName
) == 0 )
1052 if ( context
.imageSuffix
!= NULL
) {
1053 // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
1054 char aSubLibNameAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubLibName
)+1];
1055 strcpy(aSubLibNameAndSuffix
, aSubLibName
);
1056 strcat(aSubLibNameAndSuffix
, context
.imageSuffix
);
1057 if ( strcmp(aSubLibNameAndSuffix
, childLeafName
) == 0 )
1063 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1068 if ( fHasSubUmbrella
) {
1069 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
1070 const char* childInstallPath
= child
->getInstallPath();
1071 if ( childInstallPath
!= NULL
) {
1072 const char* lastSlash
= strrchr(childInstallPath
, '/');
1073 if ( lastSlash
!= NULL
) {
1074 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1075 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1076 const struct load_command
* cmd
= cmds
;
1077 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1079 case LC_SUB_UMBRELLA
:
1081 const struct sub_umbrella_command
* um
= (struct sub_umbrella_command
*)cmd
;
1082 const char* aSubUmbrellaName
= (char*)cmd
+ um
->sub_umbrella
.offset
;
1083 if ( strcmp(aSubUmbrellaName
, &lastSlash
[1]) == 0 )
1085 if ( context
.imageSuffix
!= NULL
) {
1086 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1087 char umbrellaAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubUmbrellaName
)+1];
1088 strcpy(umbrellaAndSuffix
, aSubUmbrellaName
);
1089 strcat(umbrellaAndSuffix
, context
.imageSuffix
);
1090 if ( strcmp(umbrellaAndSuffix
, &lastSlash
[1]) == 0 )
1096 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1105 void* ImageLoaderMachO::getMain() const
1107 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1108 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1109 const struct load_command
* cmd
= cmds
;
1110 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1115 const ppc_thread_state_t
* registers
= (ppc_thread_state_t
*)(((char*)cmd
) + 16);
1116 return (void*)registers
->srr0
;
1118 const ppc_thread_state64_t
* registers
= (ppc_thread_state64_t
*)(((char*)cmd
) + 16);
1119 return (void*)registers
->srr0
;
1121 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
1122 return (void*)registers
->eip
;
1124 #warning need processor specific code
1129 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1135 uint32_t ImageLoaderMachO::doGetDependentLibraryCount()
1137 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1138 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1140 const struct load_command
* cmd
= cmds
;
1141 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1144 case LC_LOAD_WEAK_DYLIB
:
1148 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1153 void ImageLoaderMachO::doGetDependentLibraries(DependentLibrary libs
[])
1156 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1157 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1158 const struct load_command
* cmd
= cmds
;
1159 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1162 case LC_LOAD_WEAK_DYLIB
:
1164 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
1165 DependentLibrary
* lib
= &libs
[index
++];
1166 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
1167 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1169 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
1170 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
1171 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
1172 lib
->required
= (cmd
->cmd
== LC_LOAD_DYLIB
);
1173 lib
->checksumMatches
= false;
1174 lib
->isReExported
= false;
1178 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1182 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo()
1185 if ( fDylibID
!= NULL
) {
1186 info
.minVersion
= fDylibID
->dylib
.compatibility_version
;
1187 info
.maxVersion
= fDylibID
->dylib
.current_version
;
1188 info
.checksum
= fDylibID
->dylib
.timestamp
;
1191 info
.minVersion
= 0;
1192 info
.maxVersion
= 0;
1198 uintptr_t ImageLoaderMachO::getFirstWritableSegmentAddress()
1200 // in split segment libraries r_address is offset from first writable segment
1201 for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it
!= fSegments
.end(); ++it
) {
1202 if ( (*it
)->writeable() ) {
1203 return (*it
)->getActualLoadAddress();
1206 throw "no writable segment";
1209 uintptr_t ImageLoaderMachO::getRelocBase()
1211 #if __ppc__ || __i386__
1212 if ( fIsSplitSeg
) {
1213 // in split segment libraries r_address is offset from first writable segment
1214 return getFirstWritableSegmentAddress();
1218 // in non-split segment libraries r_address is offset from first segment
1219 return fSegments
[0]->getActualLoadAddress();
1223 static inline void otherRelocsPPC(uintptr_t* locationToFix
, uint8_t relocationType
, uint16_t otherHalf
, uintptr_t slide
)
1225 // low 16 bits of 32-bit ppc instructions need fixing
1226 struct ppcInstruction
{ uint16_t opcode
; int16_t immediateValue
; };
1227 ppcInstruction
* instruction
= (ppcInstruction
*)locationToFix
;
1228 //uint32_t before = *((uint32_t*)locationToFix);
1229 switch ( relocationType
)
1231 case PPC_RELOC_LO16
:
1232 instruction
->immediateValue
= ((otherHalf
<< 16) | instruction
->immediateValue
) + slide
;
1234 case PPC_RELOC_HI16
:
1235 instruction
->immediateValue
= ((((instruction
->immediateValue
<< 16) | otherHalf
) + slide
) >> 16);
1237 case PPC_RELOC_HA16
:
1238 int16_t signedOtherHalf
= (int16_t)(otherHalf
& 0xffff);
1239 uint32_t temp
= (instruction
->immediateValue
<< 16) + signedOtherHalf
+ slide
;
1240 if ( (temp
& 0x00008000) != 0 )
1242 instruction
->immediateValue
= temp
>> 16;
1244 //uint32_t after = *((uint32_t*)locationToFix);
1245 //fprintf(stderr, "dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
1249 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1251 // if prebound and loaded at prebound address, then no need to rebase
1252 // Note: you might think that the check for allDependentLibrariesAsWhenPreBound() is not needed
1253 // but it is. If a dependent library changed, this image's lazy pointers into that library
1254 // need to be updated (reset back to lazy binding handler). That work is done most easily
1255 // here because there is a PPC_RELOC_PB_LA_PTR reloc record for each lazy pointer.
1256 if ( this->usablePrebinding(context
) && this->usesTwoLevelNameSpace() ) {
1257 // skip rebasing cause prebound and prebinding not disabled
1258 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1262 // print why prebinding was not used
1263 if ( context
.verbosePrebinding
) {
1264 if ( !this->isPrebindable() ) {
1265 fprintf(stderr
, "dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1267 else if ( fSlide
!= 0 ) {
1268 fprintf(stderr
, "dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1270 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1271 fprintf(stderr
, "dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1273 else if ( !this->usesTwoLevelNameSpace() ){
1274 fprintf(stderr
, "dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1277 fprintf(stderr
, "dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1281 // if there are __TEXT fixups, temporarily make __TEXT writable
1282 if ( fTextSegmentWithFixups
!= NULL
)
1283 fTextSegmentWithFixups
->tempWritable();
1285 // cache this value that is used in the following loop
1286 register const uintptr_t slide
= this->fSlide
;
1288 // loop through all local (internal) relocation records
1289 const uintptr_t relocBase
= this->getRelocBase();
1290 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]);
1291 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nlocrel
];
1292 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1293 #if __ppc__ || __ppc64__ || __i386__
1294 if ( (reloc
->r_address
& R_SCATTERED
) == 0 ) {
1295 if ( reloc
->r_symbolnum
== R_ABS
) {
1296 // ignore absolute relocations
1298 else if (reloc
->r_length
== RELOC_SIZE
) {
1299 switch(reloc
->r_type
) {
1300 case GENERIC_RELOC_VANILLA
:
1301 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1304 case PPC_RELOC_HI16
:
1305 case PPC_RELOC_LO16
:
1306 case PPC_RELOC_HA16
:
1307 // some tools leave object file relocations in linked images
1308 otherRelocsPPC((uintptr_t*)(reloc
->r_address
+ relocBase
), reloc
->r_type
, reloc
[1].r_address
, slide
);
1309 ++reloc
; // these relocations come in pairs, skip next
1313 throw "unknown local relocation type";
1317 throw "bad local relocation length";
1321 const struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
1322 if (sreloc
->r_length
== RELOC_SIZE
) {
1323 uintptr_t* locationToFix
= (uintptr_t*)(sreloc
->r_address
+ relocBase
);
1324 switch(sreloc
->r_type
) {
1325 case GENERIC_RELOC_VANILLA
:
1326 *locationToFix
+= slide
;
1328 #if __ppc__ || __ppc64__
1329 case PPC_RELOC_PB_LA_PTR
:
1330 // should only see these in prebound images, and we got here so prebinding is being ignored
1331 *locationToFix
= sreloc
->r_value
+ slide
;
1335 case PPC_RELOC_HI16
:
1336 case PPC_RELOC_LO16
:
1337 case PPC_RELOC_HA16
:
1338 // Metrowerks compiler sometimes leaves object file relocations in linked images???
1339 ++reloc
; // these relocations come in pairs, get next one
1340 otherRelocsPPC(locationToFix
, sreloc
->r_type
, reloc
->r_address
, slide
);
1344 case GENERIC_RELOC_PB_LA_PTR
:
1345 // should only see these in prebound images, and we got here so prebinding is being ignored
1346 *locationToFix
= sreloc
->r_value
+ slide
;
1350 throw "unknown local scattered relocation type";
1354 throw "bad local scattered relocation length";
1360 // if there were __TEXT fixups, restore write protection
1361 if ( fTextSegmentWithFixups
!= NULL
) {
1362 fTextSegmentWithFixups
->setPermissions();
1363 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
1367 fgTotalRebaseFixups
+= fDynamicInfo
->nlocrel
;
1371 const struct macho_nlist
* ImageLoaderMachO::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],
1372 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
)
1374 int32_t high
= symbolCount
-1;
1375 int32_t mid
= hintIndex
;
1377 // handle out of range hint
1378 if ( mid
>= (int32_t)symbolCount
) {
1379 mid
= symbolCount
/2;
1380 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1383 ++ImageLoaderMachO::fgHintedBinaryTreeSearchs
;
1386 for (int32_t low
= 0; low
<= high
; mid
= (low
+high
)/2) {
1387 const uint32_t index
= toc
[mid
].symbol_index
;
1388 const struct macho_nlist
* pivot
= &symbols
[index
];
1389 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1390 #if LINKEDIT_USAGE_DEBUG
1391 noteAccessedLinkEditAddress(&toc
[mid
]);
1392 noteAccessedLinkEditAddress(pivot
);
1393 noteAccessedLinkEditAddress(pivotStr
);
1395 int cmp
= astrcmp(key
, pivotStr
);
1410 const struct macho_nlist
* ImageLoaderMachO::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
)
1412 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1413 const struct macho_nlist
* base
= symbols
;
1414 for (uint32_t n
= symbolCount
; n
> 0; n
/= 2) {
1415 const struct macho_nlist
* pivot
= &base
[n
/2];
1416 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1417 #if LINKEDIT_USAGE_DEBUG
1418 noteAccessedLinkEditAddress(pivot
);
1419 noteAccessedLinkEditAddress(pivotStr
);
1421 int cmp
= astrcmp(key
, pivotStr
);
1426 // move base to symbol after pivot
1438 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, const void* hint
, bool searchReExports
, ImageLoader
** foundIn
) const
1440 const struct macho_nlist
* sym
= NULL
;
1441 const struct twolevel_hint
* theHint
= (struct twolevel_hint
*)hint
;
1442 if ( fDynamicInfo
->tocoff
== 0 )
1443 sym
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
);
1445 uint32_t start
= fDynamicInfo
->nextdefsym
;
1446 if ( theHint
!= NULL
)
1447 start
= theHint
->itoc
;
1448 if ( (theHint
== NULL
) || (theHint
->isub_image
== 0) ) {
1449 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1450 fDynamicInfo
->ntoc
, start
);
1453 if ( sym
!= NULL
) {
1454 if ( foundIn
!= NULL
)
1455 *foundIn
= (ImageLoader
*)this;
1457 return (const Symbol
*)sym
;
1460 if ( searchReExports
) {
1461 // hint might tell us to try a particular subimage
1462 if ( (theHint
!= NULL
) && (theHint
->isub_image
> 0) && (theHint
->isub_image
<= fLibrariesCount
) ) {
1463 // isub_image is an index into a list that is sorted non-rexported images first
1465 ImageLoader
* target
= NULL
;
1466 // pass one, only look at sub-frameworks
1467 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1468 DependentLibrary
& libInfo
= fLibraries
[i
];
1469 if ( libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
)) {
1470 if ( ++index
== theHint
->isub_image
) {
1471 target
= libInfo
.image
;
1476 if (target
!= NULL
) {
1477 // pass two, only look at non-sub-framework-reexports
1478 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1479 DependentLibrary
& libInfo
= fLibraries
[i
];
1480 if ( libInfo
.isReExported
&& !libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
) ) {
1481 if ( ++index
== theHint
->isub_image
) {
1482 target
= libInfo
.image
;
1488 if (target
!= NULL
) {
1489 const Symbol
* result
= target
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1490 if ( result
!= NULL
)
1495 // hint failed, try all sub images
1496 // pass one, only look at sub-frameworks
1497 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1498 DependentLibrary
& libInfo
= fLibraries
[i
];
1499 if ( (libInfo
.image
!= NULL
) && libInfo
.isSubFramework
) {
1500 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1501 if ( result
!= NULL
)
1505 // pass two, only look at non-sub-framework-reexports
1506 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1507 DependentLibrary
& libInfo
= fLibraries
[i
];
1508 if ( (libInfo
.image
!= NULL
) && libInfo
.isReExported
&& !libInfo
.isSubFramework
) {
1509 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1510 if ( result
!= NULL
)
1516 // last change: the hint is wrong (non-zero but actually in this image)
1517 if ( (theHint
!= NULL
) && (theHint
->isub_image
!= 0) ) {
1518 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1519 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
);
1520 if ( sym
!= NULL
) {
1521 if ( foundIn
!= NULL
)
1522 *foundIn
= (ImageLoader
*)this;
1523 return (const Symbol
*)sym
;
1532 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
) const
1534 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1535 return nlistSym
->n_value
+ fSlide
;
1538 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1540 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1541 if ( (nlistSym
->n_desc
& N_WEAK_DEF
) != 0 )
1542 return kWeakDefinition
;
1543 return kNoDefinitionOptions
;
1546 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1548 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1549 return &fStrings
[nlistSym
->n_un
.n_strx
];
1552 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1554 return fDynamicInfo
->nextdefsym
;
1558 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1560 if ( index
< fDynamicInfo
->nextdefsym
) {
1561 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iextdefsym
+ index
];
1562 return (const ImageLoader::Symbol
*)sym
;
1568 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1570 return fDynamicInfo
->nundefsym
;
1574 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1576 if ( index
< fDynamicInfo
->nundefsym
) {
1577 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iundefsym
+ index
];
1578 return (const ImageLoader::Symbol
*)sym
;
1584 ImageLoader::ReferenceFlags
ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1586 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1587 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1588 if ( ((nlistSym
->n_type
& N_TYPE
) == N_UNDF
) && (nlistSym
->n_value
!= 0) )
1589 flags
|= ImageLoader::kTentativeDefinition
;
1590 if ( (nlistSym
->n_desc
& N_WEAK_REF
) != 0 )
1591 flags
|= ImageLoader::kWeakReference
;
1596 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1598 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1599 return &fStrings
[nlistSym
->n_un
.n_strx
];
1603 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1605 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1606 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1607 const struct load_command
* cmd
= cmds
;
1608 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1610 case LC_SEGMENT_COMMAND
:
1612 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1613 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1614 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1615 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1616 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1617 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1618 *length
= sect
->size
;
1625 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1631 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1633 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1634 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1635 const struct load_command
* cmd
= cmds
;
1636 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1637 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1639 case LC_SEGMENT_COMMAND
:
1641 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1642 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1643 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1644 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1645 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1646 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1647 if ( segmentName
!= NULL
)
1648 *segmentName
= sect
->segname
;
1649 if ( sectionName
!= NULL
)
1650 *sectionName
= sect
->sectname
;
1651 if ( sectionOffset
!= NULL
)
1652 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1660 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1666 bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist
* symbol
)
1668 // if a define and weak ==> coalesced
1669 if ( ((symbol
->n_type
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc
& N_WEAK_DEF
) != 0) )
1671 // if an undefine and not referencing a weak symbol ==> coalesced
1672 if ( ((symbol
->n_type
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc
& N_REF_TO_WEAK
) != 0) )
1680 static void __attribute__((noreturn
)) throwSymbolNotFound(const char* symbol
, const char* referencedFrom
, const char* expectedIn
)
1682 const char* formatString
= "Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n";
1683 char buf
[strlen(symbol
)+strlen(referencedFrom
)+strlen(expectedIn
)+strlen(formatString
)];
1684 sprintf(buf
, formatString
, symbol
, referencedFrom
, expectedIn
);
1685 throw strdup(buf
); // this is a leak if exception doesn't halt program
1688 uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
, bool twoLevel
, ImageLoader
** foundIn
)
1690 const char* symbolName
= &fStrings
[undefinedSymbol
->n_un
.n_strx
];
1692 if ( context
.bindFlat
|| !twoLevel
) {
1695 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1696 return (*foundIn
)->getExportedSymbolAddress(sym
);
1697 // if a bundle is loaded privately the above will not find its exports
1698 if ( this->isBundle() && this->hasHiddenExports() ) {
1699 // look in self for needed symbol
1700 sym
= this->findExportedSymbol(symbolName
, NULL
, false, foundIn
);
1702 return (*foundIn
)->getExportedSymbolAddress(sym
);
1704 if ( ((undefinedSymbol
->n_type
& N_PEXT
) != 0) || ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) ) {
1705 // could be a multi-module private_extern internal reference
1706 // the static linker squirrels away the target address in n_value
1707 uintptr_t addr
= undefinedSymbol
->n_value
+ this->fSlide
;
1711 if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1712 // definition can't be found anywhere
1713 // if reference is weak_import, then it is ok, just return 0
1716 throwSymbolNotFound(symbolName
, this->getPath(), "flat namespace");
1719 // symbol requires searching images with coalesced symbols
1720 if ( this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol
) ) {
1722 if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) )
1723 return (*foundIn
)->getExportedSymbolAddress(sym
);
1724 //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace");
1725 //fprintf(stderr, "dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
1730 ImageLoader
* target
= NULL
;
1731 uint8_t ord
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
);
1732 if ( ord
== EXECUTABLE_ORDINAL
) {
1733 target
= context
.mainExecutable
;
1735 else if ( ord
== SELF_LIBRARY_ORDINAL
) {
1738 else if ( ord
== DYNAMIC_LOOKUP_ORDINAL
) {
1739 // rnielsen: HACKHACK
1742 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1743 return (*foundIn
)->getExportedSymbolAddress(sym
);
1744 // no image has exports this symbol
1745 // either report error or hope ZeroLink can just-in-time load an image
1746 context
.undefinedHandler(symbolName
);
1747 // try looking again
1748 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1749 return (*foundIn
)->getExportedSymbolAddress(sym
);
1751 throwSymbolNotFound(symbolName
, this->getPath(), "dynamic lookup");
1753 else if ( ord
<= fLibrariesCount
) {
1754 DependentLibrary
& libInfo
= fLibraries
[ord
-1];
1755 target
= libInfo
.image
;
1756 if ( (target
== NULL
) && (((undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0) || !libInfo
.required
) ) {
1757 // if target library not loaded and reference is weak or library is weak return 0
1762 throw "corrupt binary, library ordinal too big";
1765 if ( target
== NULL
) {
1766 fprintf(stderr
, "resolveUndefined(%s) in %s\n", symbolName
, this->getPath());
1767 throw "symbol not found";
1771 if ( fTwoLevelHints
!= NULL
) {
1772 uint32_t symIndex
= undefinedSymbol
- fSymbolTable
;
1773 int32_t undefinedIndex
= symIndex
- fDynamicInfo
->iundefsym
;
1774 if ( (undefinedIndex
>= 0) && ((uint32_t)undefinedIndex
< fDynamicInfo
->nundefsym
) ) {
1775 const struct twolevel_hint
* hints
= (struct twolevel_hint
*)(&fLinkEditBase
[fTwoLevelHints
->offset
]);
1776 const struct twolevel_hint
* theHint
= &hints
[undefinedIndex
];
1777 hint
= (void*)theHint
;
1781 const Symbol
* sym
= target
->findExportedSymbol(symbolName
, hint
, true, foundIn
);
1783 return (*foundIn
)->getExportedSymbolAddress(sym
);
1785 else if ( (undefinedSymbol
->n_type
& N_PEXT
) != 0 ) {
1786 // don't know why the static linker did not eliminate the internal reference to a private extern definition
1788 return undefinedSymbol
->n_value
+ fSlide
;
1790 else if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1791 // if definition not found and reference is weak return 0
1795 // nowhere to be found
1796 throwSymbolNotFound(symbolName
, this->getPath(), target
->getPath());
1800 // returns if 'addr' is within the address range of section 'sectionIndex'
1801 // fSlide is not used. 'addr' is assumed to be a prebound address in this image
1802 bool ImageLoaderMachO::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
)
1804 uint8_t currentSectionIndex
= 1;
1805 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1806 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1807 const struct load_command
* cmd
= cmds
;
1808 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1809 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1810 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1811 if ( (currentSectionIndex
<= sectionIndex
) && (sectionIndex
< currentSectionIndex
+seg
->nsects
) ) {
1812 // 'sectionIndex' is in this segment, get section info
1813 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1814 const struct macho_section
* const section
= §ionsStart
[sectionIndex
-currentSectionIndex
];
1815 return ( (section
->addr
<= addr
) && (addr
< section
->addr
+section
->size
) );
1818 // 'sectionIndex' not in this segment, skip to next segment
1819 currentSectionIndex
+= seg
->nsects
;
1822 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1828 void ImageLoaderMachO::doBindExternalRelocations(const LinkContext
& context
, bool onlyCoalescedSymbols
)
1830 const uintptr_t relocBase
= this->getRelocBase();
1831 const bool twoLevel
= this->usesTwoLevelNameSpace();
1832 const bool prebound
= this->isPrebindable();
1834 // if there are __TEXT fixups, temporarily make __TEXT writable
1835 if ( fTextSegmentWithFixups
!= NULL
)
1836 fTextSegmentWithFixups
->tempWritable();
1838 // cache last lookup
1839 const struct macho_nlist
* lastUndefinedSymbol
= 0;
1840 uintptr_t symbolAddr
= 0;
1841 ImageLoader
* image
= NULL
;
1843 // loop through all external relocation records and bind each
1844 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]);
1845 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nextrel
];
1846 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1847 if (reloc
->r_length
== RELOC_SIZE
) {
1848 switch(reloc
->r_type
) {
1851 const struct macho_nlist
* undefinedSymbol
= &fSymbolTable
[reloc
->r_symbolnum
];
1852 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
1853 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(undefinedSymbol
) )
1855 uintptr_t* location
= ((uintptr_t*)(reloc
->r_address
+ relocBase
));
1856 uintptr_t value
= *location
;
1858 if ( reloc
->r_pcrel
) {
1859 value
+= (uintptr_t)location
+ 4 - fSlide
;
1863 // we are doing relocations, so prebinding was not usable
1864 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1865 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1866 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1867 if ( ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc
& N_WEAK_DEF
) != 0) ) {
1868 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1869 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1870 // that we can subtract off the weak symbol address to get the addend.
1871 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1872 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1873 if ( (value
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) )
1874 value
-= undefinedSymbol
->n_value
;
1879 // is undefined or non-weak symbol, so do subtraction to get addend
1880 value
-= undefinedSymbol
->n_value
;
1883 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
1884 if ( undefinedSymbol
!= lastUndefinedSymbol
) {
1885 symbolAddr
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, &image
);
1886 lastUndefinedSymbol
= undefinedSymbol
;
1888 if ( context
.verboseBind
) {
1889 const char *path
= NULL
;
1891 path
= image
->getShortName();
1894 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx\n",
1895 this->getShortName(), (uintptr_t)location
,
1896 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
);
1899 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx + %ld\n",
1900 this->getShortName(), (uintptr_t)location
,
1901 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, value
);
1904 value
+= symbolAddr
;
1906 if ( reloc
->r_pcrel
) {
1907 *location
= value
- ((uintptr_t)location
+ 4);
1910 // don't dirty page if prebound value was correct
1911 if ( !prebound
|| (*location
!= value
) )
1915 // don't dirty page if prebound value was correct
1916 if ( !prebound
|| (*location
!= value
) )
1922 throw "unknown external relocation type";
1926 throw "bad external relocation length";
1930 // if there were __TEXT fixups, restore write protection
1931 if ( fTextSegmentWithFixups
!= NULL
) {
1932 fTextSegmentWithFixups
->setPermissions();
1933 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
1937 fgTotalBindFixups
+= fDynamicInfo
->nextrel
;
1940 const mach_header
* ImageLoaderMachO::machHeader() const
1942 return (mach_header
*)fMachOData
;
1945 uintptr_t ImageLoaderMachO::getSlide() const
1950 // hmm. maybe this should be up in ImageLoader??
1951 const void* ImageLoaderMachO::getBaseAddress() const
1953 Segment
* seg
= fSegments
[0];
1954 return (const void*)seg
->getActualLoadAddress();
1957 uintptr_t ImageLoaderMachO::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, ImageLoader
* targetImage
, const LinkContext
& context
)
1959 if ( context
.verboseBind
) {
1960 const char* path
= NULL
;
1961 if ( targetImage
!= NULL
)
1962 path
= targetImage
->getShortName();
1963 fprintf(stderr
, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
1964 this->getShortName(), symbolName
, (((sect
->flags
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"),
1965 path
, symbolName
, (uintptr_t)ptrToBind
, targetAddr
);
1967 if ( context
.bindingHandler
!= NULL
) {
1968 const char* path
= NULL
;
1969 if ( targetImage
!= NULL
)
1970 path
= targetImage
->getShortName();
1971 targetAddr
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
);
1974 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
1975 if ( ((sect
->flags
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2
== 5) ) {
1976 uint8_t* const jmpTableEntryToPatch
= (uint8_t*)ptrToBind
;
1977 uint32_t rel32
= targetAddr
- (((uint32_t)ptrToBind
)+5);
1978 //fprintf(stderr, "rewriting stub at %p\n", jmpTableEntryToPatch);
1979 jmpTableEntryToPatch
[0] = 0xE9; // JMP rel32
1980 jmpTableEntryToPatch
[1] = rel32
& 0xFF;
1981 jmpTableEntryToPatch
[2] = (rel32
>> 8) & 0xFF;
1982 jmpTableEntryToPatch
[3] = (rel32
>> 16) & 0xFF;
1983 jmpTableEntryToPatch
[4] = (rel32
>> 24) & 0xFF;
1987 *ptrToBind
= targetAddr
;
1992 uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
)
1994 // scan for all non-lazy-pointer sections
1995 const bool twoLevel
= this->usesTwoLevelNameSpace();
1996 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1997 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1998 const struct load_command
* cmd
= cmds
;
1999 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2000 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2002 case LC_SEGMENT_COMMAND
:
2004 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2005 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2006 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2007 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2008 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2009 uint32_t symbolIndex
= INDIRECT_SYMBOL_LOCAL
;
2010 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2011 const uint32_t pointerCount
= sect
->size
/ sizeof(uintptr_t);
2012 uintptr_t* const symbolPointers
= (uintptr_t*)(sect
->addr
+ fSlide
);
2013 if ( (lazyPointer
>= symbolPointers
) && (lazyPointer
< &symbolPointers
[pointerCount
]) ) {
2014 const uint32_t indirectTableOffset
= sect
->reserved1
;
2015 const uint32_t lazyIndex
= lazyPointer
- symbolPointers
;
2016 symbolIndex
= indirectTable
[indirectTableOffset
+ lazyIndex
];
2020 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2021 // 5 bytes stubs on i386 are new "fast stubs"
2022 uint8_t* const jmpTableBase
= (uint8_t*)(sect
->addr
+ fSlide
);
2023 uint8_t* const jmpTableEnd
= jmpTableBase
+ sect
->size
;
2024 // initial CALL instruction in jump table leaves pointer to next entry, so back up
2025 uint8_t* const jmpTableEntryToPatch
= ((uint8_t*)lazyPointer
) - 5;
2026 lazyPointer
= (uintptr_t*)jmpTableEntryToPatch
;
2027 if ( (jmpTableEntryToPatch
>= jmpTableBase
) && (jmpTableEntryToPatch
< jmpTableEnd
) ) {
2028 const uint32_t indirectTableOffset
= sect
->reserved1
;
2029 const uint32_t entryIndex
= (jmpTableEntryToPatch
- jmpTableBase
)/5;
2030 symbolIndex
= indirectTable
[indirectTableOffset
+ entryIndex
];
2034 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
&& symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2035 const char* symbolName
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
];
2036 ImageLoader
* image
= NULL
;
2037 uintptr_t symbolAddr
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], twoLevel
, &image
);
2038 symbolAddr
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
, context
);
2039 ++fgTotalLazyBindFixups
;
2046 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2048 throw "lazy pointer not found";
2054 void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext
& context
, BindingLaziness bindness
, bool onlyCoalescedSymbols
)
2056 // scan for all non-lazy-pointer sections
2057 const bool twoLevel
= this->usesTwoLevelNameSpace();
2058 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2059 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2060 const struct load_command
* cmd
= cmds
;
2061 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2062 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2064 case LC_SEGMENT_COMMAND
:
2066 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2067 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2068 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2069 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2070 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2071 uint32_t elementSize
= sizeof(uintptr_t);
2072 uint32_t elementCount
= sect
->size
/ elementSize
;
2073 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2074 if ( (bindness
== kLazyOnly
) || (bindness
== kLazyOnlyNoDependents
) )
2077 else if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2078 // process each symbol pointer in this section
2079 fgTotalPossibleLazyBindFixups
+= elementCount
;
2080 if ( bindness
== kNonLazyOnly
)
2084 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2085 // process each jmp entry in this section
2086 elementCount
= sect
->size
/ 5;
2088 fgTotalPossibleLazyBindFixups
+= elementCount
;
2089 if ( bindness
== kNonLazyOnly
)
2096 const uint32_t indirectTableOffset
= sect
->reserved1
;
2097 uint8_t* ptrToBind
= (uint8_t*)(sect
->addr
+ fSlide
);
2098 for (uint32_t j
=0; j
< elementCount
; ++j
, ptrToBind
+= elementSize
) {
2099 uint32_t symbolIndex
= indirectTable
[indirectTableOffset
+ j
];
2100 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2101 *((uintptr_t*)ptrToBind
) += this->fSlide
;
2103 else if ( symbolIndex
== INDIRECT_SYMBOL_ABS
) {
2104 // do nothing since already has absolute address
2107 const struct macho_nlist
* sym
= &fSymbolTable
[symbolIndex
];
2108 if ( symbolIndex
== 0 ) {
2109 // This could be rdar://problem/3534709
2110 if ( ((const macho_header
*)fMachOData
)->filetype
== MH_EXECUTE
) {
2111 static bool alreadyWarned
= false;
2112 if ( (sym
->n_type
& N_TYPE
) != N_UNDF
) {
2113 // The indirect table parallels the (non)lazy pointer sections. For
2114 // instance, to find info about the fifth lazy pointer you look at the
2115 // fifth entry in the indirect table. (try otool -Iv on a file).
2116 // The entry in the indirect table contains an index into the symbol table.
2118 // The bug in ld caused the entry in the indirect table to be zero
2119 // (instead of a magic value that means a local symbol). So, if the
2120 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
2121 // symbol table index. The check I put in place is to see if the zero'th
2122 // symbol table entry is an import entry (usually it is a local symbol
2124 if ( context
.verboseWarnings
&& !alreadyWarned
) {
2125 fprintf(stderr
, "dyld: malformed executable '%s', skipping indirect symbol to %s\n",
2126 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]);
2127 alreadyWarned
= true;
2133 ImageLoader
*image
= NULL
;
2134 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
2135 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(sym
) )
2137 uintptr_t symbolAddr
;
2138 symbolAddr
= resolveUndefined(context
, sym
, twoLevel
, &image
);
2141 symbolAddr
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
, context
);
2145 fgTotalBindFixups
+= elementCount
;
2150 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2155 * The address of these symbols are written in to the (__DATA,__dyld) section
2156 * at the following offsets:
2157 * at offset 0 stub_binding_helper_interface
2158 * at offset 4 _dyld_func_lookup
2159 * at offset 8 start_debug_thread
2160 * The 'C' types (if any) for these symbols are ignored here and all are
2161 * declared as longs so the assignment of their address in to the section will
2162 * not require a cast. stub_binding_helper_interface is really a label in the
2163 * assembly code interface for the stub binding. It does not have a meaningful
2164 * 'C' type. _dyld_func_lookup is the routine in dyld_libfuncs.c.
2165 * start_debug_thread is the routine in debug.c.
2167 * For ppc the image's stub_binding_binding_helper is read from:
2168 * at offset 20 the image's stub_binding_binding_helper address
2169 * and saved into to the image structure.
2172 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
2173 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2174 void* startDebugThread
; // debugger interface ???
2175 void* debugPort
; // debugger interface ???
2176 void* debugThread
; // debugger interface ???
2177 void* stubBindHelper
; // filled in at static link time to point to stub helper in image
2178 void* coreDebug
; // ???
2181 // These are defined in dyldStartup.s
2182 extern "C" void stub_binding_helper();
2183 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
);
2184 extern "C" void fast_stub_binding_helper_interface();
2187 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
2189 if ( fDATAdyld
!= NULL
) {
2190 struct DATAdyld
* dd
= (struct DATAdyld
*)(fDATAdyld
->addr
+ fSlide
);
2191 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
2192 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
2193 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
2195 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
2196 if ( dd
->dyldFuncLookup
!= (void*)&dyld_func_lookup
)
2197 dd
->dyldFuncLookup
= (void*)&dyld_func_lookup
;
2199 //if ( fDATAdyld->size > offsetof(DATAdyld, startDebugThread) )
2200 // dd->startDebugThread = &start_debug_thread;
2202 //if ( fDATAdyld->size > offsetof(DATAdyld, stubBindHelper) )
2203 // save = dd->stubBindHelper;
2207 if ( ! this->usablePrebinding(context
) || !this->usesTwoLevelNameSpace() ) {
2208 // reset all "fast" stubs
2209 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2210 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2211 const struct load_command
* cmd
= cmds
;
2212 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2214 case LC_SEGMENT_COMMAND
:
2216 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2217 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2218 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2219 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2220 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2221 if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2222 // reset each jmp entry in this section
2223 uint8_t* start
= (uint8_t*)(sect
->addr
+ this->fSlide
);
2224 uint8_t* end
= start
+ sect
->size
;
2225 uintptr_t dyldHandler
= (uintptr_t)&fast_stub_binding_helper_interface
;
2226 for (uint8_t* entry
= start
; entry
< end
; entry
+= 5) {
2227 uint32_t rel32
= dyldHandler
- (((uint32_t)entry
)+5);
2228 entry
[0] = 0xE8; // CALL rel32
2229 entry
[1] = rel32
& 0xFF;
2230 entry
[2] = (rel32
>> 8) & 0xFF;
2231 entry
[3] = (rel32
>> 16) & 0xFF;
2232 entry
[4] = (rel32
>> 24) & 0xFF;
2238 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2244 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
2246 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2247 if ( this->isPrebindable() && this->allDependentLibrariesAsWhenPreBound() && (this->getSlide() == 0) ) {
2248 // allow environment variables to disable prebinding
2249 if ( context
.bindFlat
)
2251 switch ( context
.prebindUsage
) {
2252 case kUseAllPrebinding
:
2254 case kUseSplitSegPrebinding
:
2255 return this->fIsSplitSeg
;
2256 case kUseAllButAppPredbinding
:
2257 return (this != context
.mainExecutable
);
2258 case kUseNoPrebinding
:
2265 void ImageLoaderMachO::doBind(const LinkContext
& context
, BindingLaziness bindness
)
2267 // set dyld entry points in image
2268 this->setupLazyPointerHandler(context
);
2270 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2271 // note: flat-namespace binaries need to be imports rebound (even if correctly prebound)
2272 if ( this->usablePrebinding(context
) && this->usesTwoLevelNameSpace() ) {
2273 // if image has coalesced symbols, then these need to be rebound, unless this is the only image with weak symbols
2274 if ( this->needsCoalescing() && (fgCountOfImagesWithWeakExports
> 1) ) {
2275 this->doBindExternalRelocations(context
, true);
2276 this->doBindIndirectSymbolPointers(context
, kLazyAndNonLazy
, true);
2278 // skip binding because prebound and prebinding not disabled
2282 // values bound by name are stored two different ways in mach-o
2285 case kLazyAndNonLazy
:
2286 // external relocations are used for data initialized to external symbols
2287 this->doBindExternalRelocations(context
, false);
2290 case kLazyOnlyNoDependents
:
2293 // "indirect symbols" are used for code references to external symbols
2294 this->doBindIndirectSymbolPointers(context
, bindness
, false);
2299 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
2301 if ( fDashInit
!= NULL
) {
2302 Initializer func
= (Initializer
)(fDashInit
->init_address
+ fSlide
);
2303 if ( context
.verboseInit
)
2304 fprintf(stderr
, "dyld: calling -init function 0x%p in %s\n", func
, this->getPath());
2305 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2309 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
2311 if ( fModInitSection
!= NULL
) {
2312 Initializer
* inits
= (Initializer
*)(fModInitSection
->addr
+ fSlide
);
2313 const uint32_t count
= fModInitSection
->size
/ sizeof(uintptr_t);
2314 for (uint32_t i
=0; i
< count
; ++i
) {
2315 Initializer func
= inits
[i
];
2316 if ( context
.verboseInit
)
2317 fprintf(stderr
, "dyld: calling initializer function %p in %s\n", func
, this->getPath());
2318 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2324 void ImageLoaderMachO::doInitialization(const LinkContext
& context
)
2326 // mach-o has -init and static initializers
2327 doImageInit(context
);
2328 doModInitFunctions(context
);
2331 bool ImageLoaderMachO::needsInitialization()
2333 return ( (fDashInit
!= NULL
) || (fModInitSection
!= NULL
) );
2337 bool ImageLoaderMachO::needsTermination()
2339 return ( fModTermSection
!= NULL
);
2342 bool ImageLoaderMachO::hasImageNotification()
2344 return ( fImageNotifySection
!= NULL
);
2348 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
2350 if ( fModTermSection
!= NULL
) {
2351 Terminator
* terms
= (Terminator
*)(fModTermSection
->addr
+ fSlide
);
2352 const uint32_t count
= fModTermSection
->size
/ sizeof(uintptr_t);
2353 for (uint32_t i
=count
; i
> 0; --i
) {
2354 Terminator func
= terms
[i
-1];
2355 if ( context
.verboseInit
)
2356 fprintf(stderr
, "dyld: calling terminaton function %p in %s\n", func
, this->getPath());
2362 void ImageLoaderMachO::doNotification(enum dyld_image_mode mode
, uint32_t infoCount
, const struct dyld_image_info info
[])
2364 if ( fImageNotifySection
!= NULL
) {
2365 dyld_image_notifier
* notes
= (dyld_image_notifier
*)(fImageNotifySection
->addr
+ fSlide
);
2366 const uint32_t count
= fImageNotifySection
->size
/ sizeof(uintptr_t);
2367 for (uint32_t i
=count
; i
> 0; --i
) {
2368 dyld_image_notifier func
= notes
[i
-1];
2369 func(mode
, infoCount
, info
);
2374 void ImageLoaderMachO::printStatistics(unsigned int imageCount
)
2376 ImageLoader::printStatistics(imageCount
);
2377 fprintf(stderr
, "total hinted binary tree searches: %d\n", fgHintedBinaryTreeSearchs
);
2378 fprintf(stderr
, "total unhinted binary tree searches: %d\n", fgUnhintedBinaryTreeSearchs
);
2379 fprintf(stderr
, "total images with weak exports: %d\n", fgCountOfImagesWithWeakExports
);
2381 #if LINKEDIT_USAGE_DEBUG
2382 fprintf(stderr
, "linkedit pages accessed (%lu):\n", sLinkEditPageBuckets
.size());
2386 void ImageLoaderMachO::doPrebinding(const LinkContext
& context
, time_t timestamp
, uint8_t* fileToPrebind
)
2388 // update __DATA segment
2389 this->applyPrebindingToDATA(fileToPrebind
);
2391 // update load commands
2392 this->applyPrebindingToLoadCommands(context
, fileToPrebind
, timestamp
);
2394 // update symbol table
2395 this->applyPrebindingToLinkEdit(context
, fileToPrebind
);
2398 void ImageLoaderMachO::applyPrebindingToDATA(uint8_t* fileToPrebind
)
2400 const unsigned int segmentCount
= fSegments
.size();
2401 for(unsigned int i
=0; i
< segmentCount
; ++i
) {
2402 SegmentMachO
* seg
= (SegmentMachO
*)fSegments
[i
];
2403 if ( seg
->writeable() ) {
2404 memcpy(&fileToPrebind
[seg
->fFileOffset
], (void*)seg
->getActualLoadAddress(), seg
->fFileSize
);
2409 void ImageLoaderMachO::applyPrebindingToLoadCommands(const LinkContext
& context
, uint8_t* fileToPrebind
, time_t timestamp
)
2411 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2412 const uint32_t cmd_count
= mh
->ncmds
;
2413 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2414 const struct load_command
* cmd
= cmds
;
2415 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2418 case LC_LOAD_WEAK_DYLIB
:
2420 // update each dylib load command with the timestamp of the target dylib
2421 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2422 const char* name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
2423 for (const DependentLibrary
* dl
=fLibraries
; dl
< &fLibraries
[fLibrariesCount
]; dl
++) {
2424 if (strcmp(dl
->name
, name
) == 0 ) {
2425 // found matching DependentLibrary for this load command
2426 ImageLoaderMachO
* targetImage
= (ImageLoaderMachO
*)(dl
->image
); // !!! assume only mach-o images are prebound
2427 if ( ! targetImage
->isPrebindable() )
2428 throw "dependent dylib is not prebound";
2429 // if the target is currently being re-prebound then its timestamp will be the same as this one
2430 if ( ! targetImage
->usablePrebinding(context
) ) {
2431 dylib
->dylib
.timestamp
= timestamp
;
2434 // otherwise dependent library is already correctly prebound, so use its checksum
2435 dylib
->dylib
.timestamp
= targetImage
->doGetLibraryInfo().checksum
;
2444 // update the ID of this library with the new timestamp
2445 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2446 dylib
->dylib
.timestamp
= timestamp
;
2449 case LC_SEGMENT_COMMAND
:
2450 // if dylib was rebased, update segment commands
2451 if ( fSlide
!= 0 ) {
2452 struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2453 seg
->vmaddr
+= fSlide
;
2454 struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2455 struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2456 for (struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2457 sect
->addr
+= fSlide
;
2461 case LC_ROUTINES_COMMAND
:
2462 // if dylib was rebased, update -init command
2463 if ( fSlide
!= 0 ) {
2464 struct macho_routines_command
* routines
= (struct macho_routines_command
*)cmd
;
2465 routines
->init_address
+= fSlide
;
2469 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2473 void ImageLoaderMachO::applyPrebindingToLinkEdit(const LinkContext
& context
, uint8_t* fileToPrebind
)
2475 // In prebound images, the n_value of the symbol table entry for is the prebound address
2476 // This is needed when prebinding can't be used, to back solve for any possible addend in non-lazy pointers
2477 const char* stringPool
= NULL
;
2478 struct macho_nlist
* symbolTable
= NULL
;
2479 const struct dysymtab_command
* dysymtab
= NULL
;
2481 // get symbol table info
2482 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2483 const uint32_t cmd_count
= mh
->ncmds
;
2484 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2485 const struct load_command
* cmd
= cmds
;
2486 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2490 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
2491 stringPool
= (const char*)&fileToPrebind
[symtab
->stroff
];
2492 symbolTable
= (struct macho_nlist
*)(&fileToPrebind
[symtab
->symoff
]);
2496 dysymtab
= (struct dysymtab_command
*)cmd
;
2499 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2502 // walk all imports and re-resolve their n_value (needed incase prebinding is invalid)
2503 struct macho_nlist
* lastImport
= &symbolTable
[dysymtab
->iundefsym
+dysymtab
->nundefsym
];
2504 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iundefsym
]; entry
< lastImport
; ++entry
) {
2506 entry
->n_value
= this->resolveUndefined(context
, entry
, this->usesTwoLevelNameSpace(), &dummy
);
2509 // walk all exports and slide their n_value
2510 struct macho_nlist
* lastExport
= &symbolTable
[dysymtab
->iextdefsym
+dysymtab
->nextdefsym
];
2511 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iextdefsym
]; entry
< lastExport
; ++entry
) {
2512 if ( (entry
->n_type
& N_TYPE
) == N_SECT
)
2513 entry
->n_value
+= fSlide
;
2516 // walk all local symbols and slide their n_value
2517 struct macho_nlist
* lastLocal
= &symbolTable
[dysymtab
->ilocalsym
+dysymtab
->nlocalsym
];
2518 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->ilocalsym
]; entry
< lastLocal
; ++entry
) {
2519 if ( entry
->n_sect
!= NO_SECT
)
2520 entry
->n_value
+= fSlide
;
2523 // walk all local relocations and reset every PPC_RELOC_PB_LA_PTR r_value
2524 relocation_info
* const relocsStart
= (struct relocation_info
*)(&fileToPrebind
[dysymtab
->locreloff
]);
2525 relocation_info
* const relocsEnd
= &relocsStart
[dysymtab
->nlocrel
];
2526 for (relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2527 if ( (reloc
->r_address
& R_SCATTERED
) != 0 ) {
2528 struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
2529 if (sreloc
->r_length
== RELOC_SIZE
) {
2530 switch(sreloc
->r_type
) {
2531 #if __ppc__ || __ppc64__
2532 case PPC_RELOC_PB_LA_PTR
:
2534 case GENERIC_RELOC_PB_LA_PTR
:
2536 #error unknown architecture
2538 sreloc
->r_value
+= fSlide
;
2545 // if multi-module, fix up objc_addr (10.4 and later runtime does not use this, but we want to keep file checksum consistent)
2546 if ( dysymtab
->nmodtab
!= 0 ) {
2547 dylib_module
* const modulesStart
= (struct dylib_module
*)(&fileToPrebind
[dysymtab
->modtaboff
]);
2548 dylib_module
* const modulesEnd
= &modulesStart
[dysymtab
->nmodtab
];
2549 for (dylib_module
* module=modulesStart
; module < modulesEnd
; ++module) {
2550 if ( module->objc_module_info_size
!= 0 ) {
2551 module->objc_module_info_addr
+= fSlide
;
2557 // file on disk has been reprebound, but we are still mapped to old file
2558 void ImageLoaderMachO::prebindUnmap(const LinkContext
& context
)
2560 // this removes all mappings to the old file, so the kernel will unlink (delete) it.
2561 // We need to leave the load commands and __LINKEDIT in place
2562 for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it
!= fSegments
.end(); ++it
) {
2563 void* segmentAddress
= (void*)((*it
)->getActualLoadAddress());
2564 uintptr_t segmentSize
= (*it
)->getSize();
2565 //fprintf(stderr, "unmapping segment %s at %p for %s\n", (*it)->getName(), segmentAddress, this->getPath());
2566 // save load commands at beginning of __TEXT segment
2567 if ( segmentAddress
== fMachOData
) {
2568 // typically load commands are one or two pages in size, so ok to alloc on stack
2569 uint32_t loadCmdSize
= sizeof(macho_header
) + ((macho_header
*)fMachOData
)->sizeofcmds
;
2570 uint32_t loadCmdPages
= (loadCmdSize
+4095) & (-4096);
2571 uint8_t loadcommands
[loadCmdPages
];
2572 memcpy(loadcommands
, fMachOData
, loadCmdPages
);
2573 // unmap whole __TEXT segment
2574 munmap((void*)(fMachOData
), segmentSize
);
2575 // allocate and copy back mach_header and load commands
2576 vm_address_t addr
= (vm_address_t
)fMachOData
;
2577 int r2
= vm_allocate(mach_task_self(), &addr
, loadCmdPages
, false /*at this address*/);
2579 fprintf(stderr
, "prebindUnmap() vm_allocate for __TEXT %d failed\n", loadCmdPages
);
2580 memcpy((void*)fMachOData
, loadcommands
, loadCmdPages
);
2581 //fprintf(stderr, "copying back load commands to %p size=%u for %s\n", segmentAddress, loadCmdPages, this->getPath());
2583 else if ( strcmp((*it
)->getName(), "__LINKEDIT") == 0 ) {
2584 uint32_t linkEditSize
= segmentSize
;
2585 uint32_t linkEditPages
= (linkEditSize
+4095) & (-4096);
2586 void* linkEditTmp
= malloc(linkEditPages
);
2587 memcpy(linkEditTmp
, segmentAddress
, linkEditPages
);
2588 // unmap whole __LINKEDIT segment
2589 munmap(segmentAddress
, segmentSize
);
2590 vm_address_t addr
= (vm_address_t
)segmentAddress
;
2591 int r2
= vm_allocate(mach_task_self(), &addr
, linkEditPages
, false /*at this address*/);
2593 fprintf(stderr
, "prebindUnmap() vm_allocate for __LINKEDIT %d failed\n", linkEditPages
);
2594 memcpy(segmentAddress
, linkEditTmp
, linkEditPages
);
2595 //fprintf(stderr, "copying back __LINKEDIT to %p size=%u for %s\n", segmentAddress, linkEditPages, this->getPath());
2599 // unmap any other segment
2600 munmap((void*)(segmentAddress
), (*it
)->getSize());
2607 SegmentMachO::SegmentMachO(const struct macho_segment_command
* cmd
, ImageLoaderMachO
* image
, const uint8_t* fileData
)
2608 : fImage(image
), fSize(cmd
->vmsize
), fFileSize(cmd
->filesize
), fFileOffset(cmd
->fileoff
), fPreferredLoadAddress(cmd
->vmaddr
),
2609 fVMProtection(cmd
->initprot
), fHasFixUps(false), fUnMapOnDestruction(false)
2611 strncpy(fName
, cmd
->segname
, 16);
2613 // scan sections for fix-up bit
2614 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)cmd
+ sizeof(struct macho_segment_command
));
2615 const struct macho_section
* const sectionsEnd
= §ionsStart
[cmd
->nsects
];
2616 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2617 if ( (sect
->flags
& (S_ATTR_EXT_RELOC
| S_ATTR_LOC_RELOC
)) != 0 )
2622 SegmentMachO::~SegmentMachO()
2624 if ( fUnMapOnDestruction
) {
2625 //fprintf(stderr, "unmapping segment %s at 0x%08lX\n", getName(), getActualLoadAddress());
2626 munmap((void*)(this->getActualLoadAddress()), this->getSize());
2630 const ImageLoader
* SegmentMachO::getImage()
2635 const char* SegmentMachO::getName()
2640 uintptr_t SegmentMachO::getSize()
2645 uintptr_t SegmentMachO::getFileSize()
2650 uintptr_t SegmentMachO::getFileOffset()
2655 bool SegmentMachO::readable()
2657 return ( (fVMProtection
& VM_PROT_READ
) != 0);
2660 bool SegmentMachO::writeable()
2662 return ((fVMProtection
& VM_PROT_WRITE
) != 0);
2665 bool SegmentMachO::executable()
2667 return ((fVMProtection
& VM_PROT_EXECUTE
) != 0);
2670 bool SegmentMachO::unaccessible()
2672 return (fVMProtection
== 0);
2675 bool SegmentMachO::hasFixUps()
2680 uintptr_t SegmentMachO::getActualLoadAddress()
2682 return fPreferredLoadAddress
+ fImage
->fSlide
;
2685 uintptr_t SegmentMachO::getPreferredLoadAddress()
2687 return fPreferredLoadAddress
;
2690 bool SegmentMachO::hasPreferredLoadAddress()
2692 return (fPreferredLoadAddress
!= 0);
2695 void SegmentMachO::setUnMapWhenDestructed(bool unmap
)
2697 fUnMapOnDestruction
= unmap
;
2700 static uint32_t *buildCRCTable(void)
2702 uint32_t *table
= new uint32_t[256];
2703 uint32_t p
= 0xedb88320UL
; // standard CRC-32 polynomial
2705 for (unsigned int i
= 0; i
< 256; i
++) {
2707 for (unsigned int j
= 0; j
< 8; j
++) {
2708 if ( c
& 1 ) c
= p
^ (c
>> 1);
2717 uint32_t SegmentMachO::crc32()
2719 if ( !readable() ) return 0;
2721 static uint32_t *crcTable
= NULL
;
2722 if ( !crcTable
) crcTable
= buildCRCTable();
2724 uint32_t crc
= ~(uint32_t)0;
2725 uint8_t *p
= (uint8_t *)getActualLoadAddress();
2726 uint8_t *end
= p
+ getSize();
2728 crc
= crcTable
[(crc
& 0xff) ^ (*p
++)] ^ (crc
>> 8);
2730 return crc
^ ~(uint32_t)0;