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 #include <libkern/OSAtomic.h>
38 #if __ppc__ || __ppc64__
39 #include <mach-o/ppc/reloc.h>
42 #include <mach-o/x86_64/reloc.h>
45 #ifndef S_ATTR_SELF_MODIFYING_CODE
46 #define S_ATTR_SELF_MODIFYING_CODE 0x04000000
49 #include "ImageLoaderMachO.h"
50 #include "mach-o/dyld_gdb.h"
52 // no header for this yet, rdar://problem/3850825
53 extern "C" void sys_icache_invalidate(void *, size_t);
55 // optimize strcmp for ppc
57 #include <ppc_intrinsics.h>
59 #define astrcmp(a,b) strcmp(a,b)
62 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
65 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
66 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
67 struct macho_header
: public mach_header_64
{};
68 struct macho_segment_command
: public segment_command_64
{};
69 struct macho_section
: public section_64
{};
70 struct macho_nlist
: public nlist_64
{};
71 struct macho_routines_command
: public routines_command_64
{};
74 #define LC_SEGMENT_COMMAND LC_SEGMENT
75 #define LC_ROUTINES_COMMAND LC_ROUTINES
76 struct macho_header
: public mach_header
{};
77 struct macho_segment_command
: public segment_command
{};
78 struct macho_section
: public section
{};
79 struct macho_nlist
: public nlist
{};
80 struct macho_routines_command
: public routines_command
{};
84 #define POINTER_RELOC X86_64_RELOC_UNSIGNED
86 #define POINTER_RELOC GENERIC_RELOC_VANILLA
89 uint32_t ImageLoaderMachO::fgHintedBinaryTreeSearchs
= 0;
90 uint32_t ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
= 0;
91 uint32_t ImageLoaderMachO::fgCountOfImagesWithWeakExports
= 0;
94 //#define LINKEDIT_USAGE_DEBUG 1
96 #if LINKEDIT_USAGE_DEBUG
98 static std::set
<uintptr_t> sLinkEditPageBuckets
;
101 extern ImageLoader
* findImageContainingAddress(const void* addr
);
104 static void noteAccessedLinkEditAddress(const void* addr
)
106 uintptr_t page
= ((uintptr_t)addr
) & (-4096);
107 sLinkEditPageBuckets
.insert(page
);
108 fprintf(stderr
, "dyld: accessing page 0x%08lX in __LINKEDIT of %s\n", page
, dyld::findImageContainingAddress(addr
)->getPath());
112 // only way to share initialization in C++
113 void ImageLoaderMachO::init()
116 fLinkEditBase
= NULL
;
122 fHasSubLibraries
= false;
123 fHasSubUmbrella
= false;
125 fModInitSection
= NULL
;
126 fModTermSection
= NULL
;
128 fImageNotifySection
= NULL
;
129 fTwoLevelHints
= NULL
;
131 fReExportThruFramework
= NULL
;
132 fTextSegmentWithFixups
= NULL
;
135 // create image by copying an in-memory mach-o file
136 ImageLoaderMachO::ImageLoaderMachO(const char* moduleName
, const struct mach_header
* mh
, uint64_t len
, const LinkContext
& context
)
137 : ImageLoader(moduleName
)
142 // temporary use this buffer until TEXT is mapped in
143 fMachOData
= (const uint8_t*)mh
;
146 this->instantiateSegments((const uint8_t*)mh
);
149 if ( mh
->filetype
!= MH_EXECUTE
)
150 ImageLoader::mapSegments((const void*)mh
, len
, context
);
152 // get pointers to interesting things
153 this->parseLoadCmds();
157 // create image by mapping in a mach-o file
158 ImageLoaderMachO::ImageLoaderMachO(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,
159 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
160 : ImageLoader(path
, offsetInFat
, info
)
165 // read load commands
166 const unsigned int dataSize
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
;
167 uint8_t buffer
[dataSize
];
168 const uint8_t* fileData
= firstPage
;
169 if ( dataSize
> 4096 ) {
170 // only read more if cmds take up more space than first page
172 memcpy(buffer
, firstPage
, 4096);
173 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096);
176 // temporary use this buffer until TEXT is mapped in
177 fMachOData
= fileData
;
179 // the meaning of many fields changes in split seg mach-o files
180 fIsSplitSeg
= ((((macho_header
*)fileData
)->flags
& MH_SPLIT_SEGS
) != 0) && (((macho_header
*)fileData
)->filetype
== MH_DYLIB
);
183 this->instantiateSegments(fileData
);
185 // map segments, except for main executable which is already mapped in by kernel
186 if ( ((macho_header
*)fileData
)->filetype
!= MH_EXECUTE
)
187 this->mapSegments(fd
, offsetInFat
, lenInFat
, info
.st_size
, context
);
189 // get pointers to interesting things
190 this->parseLoadCmds();
193 ImageLoaderMachO::~ImageLoaderMachO()
195 // keep count of images with weak exports
196 if ( this->hasCoalescedExports() )
197 --fgCountOfImagesWithWeakExports
;
202 void ImageLoaderMachO::instantiateSegments(const uint8_t* fileData
)
204 const uint32_t cmd_count
= ((macho_header
*)fileData
)->ncmds
;
205 const struct load_command
* const cmds
= (struct load_command
*)&fileData
[sizeof(macho_header
)];
207 // construct Segment object for each LC_SEGMENT cmd and add to list
208 const struct load_command
* cmd
= cmds
;
209 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
210 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
211 if ( (((struct macho_segment_command
*)cmd
)->vmsize
!= 0) || !fIsSplitSeg
)
212 fSegments
.push_back(new SegmentMachO((struct macho_segment_command
*)cmd
, this, fileData
));
214 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
220 bool ImageLoaderMachO::segmentsMustSlideTogether() const
225 bool ImageLoaderMachO::segmentsCanSlide() const
227 const macho_header
* mh
= (macho_header
*)fMachOData
;
228 return ( (mh
->filetype
== MH_DYLIB
) || (mh
->filetype
== MH_BUNDLE
) );
231 bool ImageLoaderMachO::isBundle() const
233 const macho_header
* mh
= (macho_header
*)fMachOData
;
234 return ( mh
->filetype
== MH_BUNDLE
);
237 bool ImageLoaderMachO::isDylib() const
239 const macho_header
* mh
= (macho_header
*)fMachOData
;
240 return ( mh
->filetype
== MH_DYLIB
);
243 bool ImageLoaderMachO::forceFlat() const
245 const macho_header
* mh
= (macho_header
*)fMachOData
;
246 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
249 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
251 const macho_header
* mh
= (macho_header
*)fMachOData
;
252 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
255 bool ImageLoaderMachO::isPrebindable() const
257 const macho_header
* mh
= (macho_header
*)fMachOData
;
258 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
261 bool ImageLoaderMachO::hasCoalescedExports() const
263 const macho_header
* mh
= (macho_header
*)fMachOData
;
264 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
267 bool ImageLoaderMachO::needsCoalescing() const
269 const macho_header
* mh
= (macho_header
*)fMachOData
;
270 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
273 #if !__LP64__ // split segs not supported for 64-bits
275 #if 1 // hack until kernel headers and glue are in system
276 struct _shared_region_mapping_np
{
277 mach_vm_address_t address
;
279 mach_vm_offset_t file_offset
;
280 vm_prot_t max_prot
; /* read/write/execute/COW/ZF */
281 vm_prot_t init_prot
; /* read/write/execute/COW/ZF */
283 struct _shared_region_range_np
{
284 mach_vm_address_t address
;
289 // Requests the kernel to map a number of regions from the fd into the
290 // shared sections address range (0x90000000-0xAFFFFFFF).
291 // If shared_region_make_private_np() has not been called by this process,
292 // the file mapped in is seen in the address space of all processes that
293 // participate in using the shared region.
294 // If shared_region_make_private_np() _has_ been called by this process,
295 // the file mapped in is only seen by this process.
296 // If the slide parameter is not NULL and then regions cannot be mapped
297 // as requested, the kernel will try to map the file in at a different
298 // address in the shared region and return the distance slid.
299 // If the mapping requesting cannot be fulfilled, returns non-zero.
301 _shared_region_map_file_np(
302 int fd
, // file descriptor to map into shared region
303 unsigned int regionCount
, // number of entres in array of regions
304 const _shared_region_mapping_np regions
[], // the array of regions to map
305 uint64_t* slide
) // the amount all regions were slid, NULL means don't attempt to slide
307 //fprintf(stderr, "%s(%i, %u, %8p, %8p)\n", __func__, fd, regionCount, regions, slide);
308 //for ( unsigned int i=0; i < regionCount; ++i) {
309 // fprintf(stderr, "\taddress=0x%08llX, size=0x%08llX\n", regions[i].address, regions[i].size);
311 int r
= syscall(299, fd
, regionCount
, regions
, slide
);
313 // fprintf(stderr, "%s(%i, %u, %8p, %8p) errno=%i (%s)\n", __func__, fd, regionCount, regions, slide, errno, strerror(errno));
316 // Called by dyld if shared_region_map_file() fails.
317 // Requests the kernel to take this process out of using the shared region.
318 // The specified ranges are created as private copies from the shared region for this process.
320 _shared_region_make_private_np(
321 unsigned int rangeCount
, // number of entres in array of msrp_range
322 const _shared_region_range_np ranges
[]) // the array of shared regions to make private
324 //fprintf(stderr, "%s(%u, %8p)\n", __func__, rangeCount, ranges);
325 int r
= syscall(300, rangeCount
, ranges
);
327 // fprintf(stderr, "%s(%u, %8p) errno=%i (%s)\n", __func__, rangeCount, ranges, errno, strerror(errno));
330 #define KERN_SHREG_PRIVATIZABLE 54
331 #endif // hack until kernel headers and glue are in system
333 static uintptr_t sNextAltLoadAddress
341 _shared_region_map_file_with_mmap(
342 int fd
, // file descriptor to map into shared region
343 unsigned int regionCount
, // number of entres in array of regions
344 const _shared_region_mapping_np regions
[]) // the array of regions to map
346 // map in each region
347 for(unsigned int i
=0; i
< regionCount
; ++i
) {
348 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
);
349 size_t size
= regions
[i
].size
;
350 if ( (regions
[i
].init_prot
& VM_PROT_ZF
) != 0 ) {
351 // do nothing already vm_allocate() which zero fills
355 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
356 protection
|= PROT_EXEC
;
357 if ( regions
[i
].init_prot
& VM_PROT_READ
)
358 protection
|= PROT_READ
;
359 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
360 protection
|= PROT_WRITE
;
361 off_t offset
= regions
[i
].file_offset
;
362 //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
363 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FILE
| MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
364 if ( mmapAddress
== ((void*)(-1)) )
375 hasSharedRegionMapFile(void)
377 int mib
[CTL_MAXNAME
];
382 mib
[1] = KERN_SHREG_PRIVATIZABLE
;
384 if (sysctl(mib
, 2, &value
, &size
, NULL
, 0) != 0) {
392 ImageLoaderMachO::sharedRegionMapFilePrivateOutside(int fd
,
393 uint64_t offsetInFat
,
396 const LinkContext
& context
)
398 const unsigned int segmentCount
= fSegments
.size();
399 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
400 const unsigned int regionCount
= segmentCount
+extraZeroFillEntries
;
401 _shared_region_mapping_np regions
[regionCount
];
402 initMappingTable(offsetInFat
, regions
);
404 // find space somewhere to allocate split seg
405 bool foundRoom
= false;
406 vm_size_t biggestDiff
= 0;
407 while ( ! foundRoom
) {
409 for(unsigned int i
=0; i
< regionCount
; ++i
) {
410 vm_address_t addr
= sNextAltLoadAddress
+ regions
[i
].address
- regions
[0].address
;
411 vm_size_t size
= regions
[i
].size
;
412 r
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/);
414 // no room here, deallocate what has succeeded so far
415 for(unsigned int j
=0; j
< i
; ++j
) {
416 vm_address_t addr
= sNextAltLoadAddress
+ regions
[j
].address
- regions
[0].address
;
417 vm_size_t size
= regions
[j
].size
;
418 (void)vm_deallocate(mach_task_self(), addr
, size
);
420 sNextAltLoadAddress
+= 0x00100000; // skip ahead 1MB and try again
421 if ( (sNextAltLoadAddress
& 0xF0000000) == 0x90000000 )
422 sNextAltLoadAddress
= 0xB0000000;
423 if ( (sNextAltLoadAddress
& 0xF0000000) == 0xF0000000 )
424 throw "can't map split seg anywhere";
428 vm_size_t high
= (regions
[i
].address
+ size
- regions
[0].address
) & 0x0FFFFFFF;
429 if ( high
> biggestDiff
)
434 // map in each region
435 uintptr_t slide
= sNextAltLoadAddress
- regions
[0].address
;
436 this->setSlide(slide
);
437 for(unsigned int i
=0; i
< regionCount
; ++i
) {
438 if ( (regions
[i
].init_prot
& VM_PROT_ZF
) != 0 ) {
439 // do nothing vm_allocate() zero-fills by default
442 void* mmapAddress
= (void*)(uintptr_t)(regions
[i
].address
+ slide
);
443 size_t size
= regions
[i
].size
;
445 if ( regions
[i
].init_prot
& VM_PROT_EXECUTE
)
446 protection
|= PROT_EXEC
;
447 if ( regions
[i
].init_prot
& VM_PROT_READ
)
448 protection
|= PROT_READ
;
449 if ( regions
[i
].init_prot
& VM_PROT_WRITE
)
450 protection
|= PROT_WRITE
;
451 off_t offset
= regions
[i
].file_offset
;
452 //fprintf(stderr, "mmap(%p, 0x%08lX, block=0x%08X, %s\n", mmapAddress, size, biggestDiff, fPath);
453 mmapAddress
= mmap(mmapAddress
, size
, protection
, MAP_FILE
| MAP_FIXED
| MAP_PRIVATE
, fd
, offset
);
454 if ( mmapAddress
== ((void*)(-1)) )
458 // set so next maps right after this one
459 sNextAltLoadAddress
+= biggestDiff
;
460 sNextAltLoadAddress
= (sNextAltLoadAddress
+ 4095) & (-4096);
463 if ( context
.verboseMapping
) {
464 fprintf(stderr
, "dyld: Mapping split-seg outside shared region, slid by 0x%08lX %s\n", this->fSlide
, this->getPath());
465 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
466 Segment
* seg
= fSegments
[segIndex
];
467 const _shared_region_mapping_np
* entry
= ®ions
[entryIndex
];
468 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
469 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
470 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
471 if ( entryIndex
< (regionCount
-1) ) {
472 const _shared_region_mapping_np
* nextEntry
= ®ions
[entryIndex
+1];
473 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
474 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
475 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
476 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
487 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
489 enum SharedRegionState
491 kSharedRegionStartState
= 0,
492 kSharedRegionLoadFileState
,
493 kSharedRegionMapFileState
,
494 kSharedRegionMapFilePrivateState
,
495 kSharedRegionMapFilePrivateMMapState
,
496 kSharedRegionMapFilePrivateOutsideState
,
498 static SharedRegionState sSharedRegionState
= kSharedRegionStartState
;
500 // non-split segment libraries handled by super class
502 return ImageLoader::mapSegments(fd
, offsetInFat
, lenInFat
, fileLen
, context
);
504 if ( kSharedRegionStartState
== sSharedRegionState
) {
505 if ( hasSharedRegionMapFile() ) {
506 if ( context
.slideAndPackDylibs
) {
507 sharedRegionMakePrivate(context
);
508 // remove underlying submap and block out 0x90000000 to 0xAFFFFFFF
509 vm_address_t addr
= (vm_address_t
)0x90000000;
510 vm_deallocate(mach_task_self(), addr
, 0x20000000);
511 vm_allocate(mach_task_self(), &addr
, 0x20000000, false);
512 sSharedRegionState
= kSharedRegionMapFilePrivateMMapState
;
514 else if ( context
.sharedRegionMode
== kUsePrivateSharedRegion
) {
515 sharedRegionMakePrivate(context
);
516 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
518 else if ( context
.sharedRegionMode
== kDontUseSharedRegion
) {
519 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
522 sSharedRegionState
= kSharedRegionMapFileState
;
526 sSharedRegionState
= kSharedRegionLoadFileState
;
530 if ( kSharedRegionLoadFileState
== sSharedRegionState
) {
531 if ( 0 != sharedRegionLoadFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
532 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
536 if ( kSharedRegionMapFileState
== sSharedRegionState
) {
537 if ( 0 != sharedRegionMapFile(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
538 sharedRegionMakePrivate(context
);
539 sSharedRegionState
= kSharedRegionMapFilePrivateState
;
543 if ( (kSharedRegionMapFilePrivateState
== sSharedRegionState
) || (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
) ) {
544 if ( 0 != sharedRegionMapFilePrivate(fd
, offsetInFat
, lenInFat
, fileLen
, context
, (kSharedRegionMapFilePrivateMMapState
== sSharedRegionState
)) ) {
545 sSharedRegionState
= kSharedRegionMapFilePrivateOutsideState
;
549 if ( kSharedRegionMapFilePrivateOutsideState
== sSharedRegionState
) {
550 if ( 0 != sharedRegionMapFilePrivateOutside(fd
, offsetInFat
, lenInFat
, fileLen
, context
) ) {
551 throw "mapping error";
557 ImageLoaderMachO::getExtraZeroFillEntriesCount()
559 // calculate mapping entries
560 const unsigned int segmentCount
= fSegments
.size();
561 unsigned int extraZeroFillEntries
= 0;
562 for(unsigned int i
=0; i
< segmentCount
; ++i
){
563 Segment
* seg
= fSegments
[i
];
564 if ( seg
->hasTrailingZeroFill() )
565 ++extraZeroFillEntries
;
568 return extraZeroFillEntries
;
572 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
573 _shared_region_mapping_np
*mappingTable
)
575 unsigned int segmentCount
= fSegments
.size();
576 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
577 Segment
* seg
= fSegments
[segIndex
];
578 _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
579 entry
->address
= seg
->getActualLoadAddress();
580 entry
->size
= seg
->getFileSize();
581 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
582 entry
->init_prot
= VM_PROT_NONE
;
583 if ( !seg
->unaccessible() ) {
584 if ( seg
->executable() )
585 entry
->init_prot
|= VM_PROT_EXECUTE
;
586 if ( seg
->readable() )
587 entry
->init_prot
|= VM_PROT_READ
;
588 if ( seg
->writeable() )
589 entry
->init_prot
|= VM_PROT_WRITE
| VM_PROT_COW
;
591 entry
->max_prot
= entry
->init_prot
;
592 if ( seg
->hasTrailingZeroFill() ) {
593 _shared_region_mapping_np
* zfentry
= &mappingTable
[++entryIndex
];
594 zfentry
->address
= entry
->address
+ seg
->getFileSize();
595 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
596 zfentry
->file_offset
= 0;
597 zfentry
->init_prot
= entry
->init_prot
| VM_PROT_COW
| VM_PROT_ZF
;
598 zfentry
->max_prot
= zfentry
->init_prot
;
604 ImageLoaderMachO::sharedRegionMakePrivate(const LinkContext
& context
)
606 if ( context
.verboseMapping
)
607 fprintf(stderr
, "dyld: making shared regions private\n");
609 // shared mapping failed, so make private copy of shared region and try mapping private
610 RegionsVector allRegions
;
611 context
.getAllMappedRegions(allRegions
);
612 std::vector
<_shared_region_range_np
> splitSegRegions
;
613 const unsigned int allRegiontCount
= allRegions
.size();
614 for(unsigned int i
=0; i
< allRegiontCount
; ++i
){
615 MappedRegion region
= allRegions
[i
];
616 uint8_t highByte
= region
.address
>> 28;
617 if ( (highByte
== 9) || (highByte
== 0xA) ) {
618 _shared_region_range_np splitRegion
;
619 splitRegion
.address
= region
.address
;
620 splitRegion
.size
= region
.size
;
621 splitSegRegions
.push_back(splitRegion
);
624 int result
= _shared_region_make_private_np(splitSegRegions
.size(), &splitSegRegions
[0]);
625 // notify gdb or other lurkers that this process is no longer using the shared region
626 dyld_all_image_infos
.processDetachedFromSharedRegion
= true;
631 ImageLoaderMachO::sharedRegionMapFile(int fd
,
632 uint64_t offsetInFat
,
635 const LinkContext
& context
)
637 // build table of segments to map
638 const unsigned int segmentCount
= fSegments
.size();
639 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
640 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
641 _shared_region_mapping_np mappingTable
[mappingTableCount
];
642 initMappingTable(offsetInFat
, mappingTable
);
644 uint64_t *slidep
= NULL
;
646 // try to map it in shared
647 int r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, slidep
);
649 if(NULL
!= slidep
&& 0 != *slidep
) {
650 // update with actual load addresses
652 if ( context
.verboseMapping
) {
653 fprintf(stderr
, "dyld: Mapping split-seg shared %s\n", this->getPath());
654 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
655 Segment
* seg
= fSegments
[segIndex
];
656 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
657 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
658 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
659 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
660 if ( entryIndex
< (mappingTableCount
-1) ) {
661 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
662 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
663 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
664 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
665 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
677 ImageLoaderMachO::sharedRegionMapFilePrivate(int fd
,
678 uint64_t offsetInFat
,
681 const LinkContext
& context
,
684 const unsigned int segmentCount
= fSegments
.size();
686 // adjust base address of segments to pack next to last dylib
687 if ( context
.slideAndPackDylibs
) {
688 uintptr_t lowestReadOnly
= (uintptr_t)(-1);
689 uintptr_t lowestWritable
= (uintptr_t)(-1);
690 for(unsigned int segIndex
=0; segIndex
< segmentCount
; ++segIndex
){
691 Segment
* seg
= fSegments
[segIndex
];
692 uintptr_t segEnd
= seg
->getActualLoadAddress();
693 if ( seg
->writeable() ) {
694 if ( segEnd
< lowestWritable
)
695 lowestWritable
= segEnd
;
698 if ( segEnd
< lowestReadOnly
)
699 lowestReadOnly
= segEnd
;
702 uintptr_t baseAddress
;
703 if ( lowestWritable
- 256*1024*1024 < lowestReadOnly
)
704 baseAddress
= lowestWritable
- 256*1024*1024;
706 baseAddress
= lowestReadOnly
;
707 // record that we want dylb slid to fgNextSplitSegAddress
708 this->setSlide(fgNextSplitSegAddress
- baseAddress
);
711 // build table of segments to map
712 const unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
713 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
714 _shared_region_mapping_np mappingTable
[mappingTableCount
];
715 initMappingTable(offsetInFat
, mappingTable
);
718 // try map it in privately (don't allow sliding if we pre-calculated the load address to pack dylibs)
721 r
= _shared_region_map_file_with_mmap(fd
, mappingTableCount
, mappingTable
);
723 r
= _shared_region_map_file_np(fd
, mappingTableCount
, mappingTable
, context
.slideAndPackDylibs
? NULL
: &slide
);
726 slide
= (slide
) & (-4096); // round down to page boundary
727 this->setSlide(slide
);
729 if ( context
.verboseMapping
) {
731 fprintf(stderr
, "dyld: Mapping split-seg un-shared %s\n", this->getPath());
733 fprintf(stderr
, "dyld: Mapping split-seg un-shared slid by 0x%08llX %s\n", slide
, this->getPath());
734 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
735 Segment
* seg
= fSegments
[segIndex
];
736 const _shared_region_mapping_np
* entry
= &mappingTable
[entryIndex
];
737 if ( (entry
->init_prot
& VM_PROT_ZF
) == 0 )
738 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
739 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
740 if ( entryIndex
< (mappingTableCount
-1) ) {
741 const _shared_region_mapping_np
* nextEntry
= &mappingTable
[entryIndex
+1];
742 if ( (nextEntry
->init_prot
& VM_PROT_ZF
) != 0 ) {
743 uint64_t segOffset
= nextEntry
->address
- entry
->address
;
744 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX (zerofill)\n",
745 seg
->getName(), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
), (uintptr_t)(seg
->getActualLoadAddress() + segOffset
+ nextEntry
->size
- 1));
751 if ( context
.slideAndPackDylibs
) {
752 // calculate where next split-seg dylib can load
753 uintptr_t largestReadOnly
= 0;
754 uintptr_t largestWritable
= 0;
755 for (unsigned int segIndex
=0; segIndex
< segmentCount
; ++segIndex
) {
756 Segment
* seg
= fSegments
[segIndex
];
757 uintptr_t segEnd
= seg
->getActualLoadAddress()+seg
->getSize();
758 segEnd
= (segEnd
+4095) & (-4096); // page align
759 if ( seg
->writeable() ) {
760 if ( segEnd
> largestWritable
)
761 largestWritable
= segEnd
;
764 if ( segEnd
> largestReadOnly
)
765 largestReadOnly
= segEnd
;
768 if ( largestWritable
- 256*1024*1024 > largestReadOnly
)
769 fgNextSplitSegAddress
= largestWritable
- 256*1024*1024;
771 fgNextSplitSegAddress
= largestReadOnly
;
774 if ( context
.slideAndPackDylibs
&& (r
!= 0) )
775 throwf("can't rebase split-seg dylib %s because shared_region_map_file_np() returned %d", this->getPath(), r
);
782 ImageLoaderMachO::sharedRegionLoadFile(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
785 // map in split segment file at random address, then tell kernel to share it
786 void* loadAddress
= 0;
787 loadAddress
= mmap(NULL
, fileLen
, PROT_READ
, MAP_FILE
, fd
, 0);
788 if ( loadAddress
== ((void*)(-1)) )
791 // calculate mapping entries
792 const unsigned int segmentCount
= fSegments
.size();
793 unsigned int extraZeroFillEntries
= getExtraZeroFillEntriesCount();
795 // build table of segments to map
796 const unsigned int mappingTableCount
= segmentCount
+extraZeroFillEntries
;
797 const uintptr_t baseAddress
= fSegments
[0]->getPreferredLoadAddress();
798 sf_mapping mappingTable
[mappingTableCount
];
799 initMappingTable(offsetInFat
, mappingTable
, baseAddress
);
802 // use load_shared_file() to map all segments at once
803 int flags
= 0; // might need to set NEW_LOCAL_SHARED_REGIONS on first use
804 static bool firstTime
= true;
806 // when NEW_LOCAL_SHARED_REGIONS bit is set, this process will get is own shared region
807 // this is used by Xcode to prevent development libraries from polluting the global shared segment
808 if ( context
.sharedRegionMode
== kUsePrivateSharedRegion
)
809 flags
|= NEW_LOCAL_SHARED_REGIONS
;
813 caddr_t base_address
= (caddr_t
)baseAddress
;
815 r
= load_shared_file( (char*)fPath
, // path of file to map shared
816 (char*)loadAddress
, // beginning of local copy of sharable pages in file
817 fileLen
, // end of shareable pages in file
818 &base_address
, // beginning of address range to map
819 mappingTableCount
, // number of entres in array of sf_mapping
820 mappingTable
, // the array of sf_mapping
821 &flags
); // in/out flags
823 // try again but tell kernel it is ok to slide
824 flags
|= ALTERNATE_LOAD_SITE
;
825 r
= load_shared_file((char*)fPath
,(char*)loadAddress
, fileLen
, &base_address
,
826 mappingTableCount
, mappingTable
, &flags
);
829 // unmap file from random address now that they are (hopefully) mapped into the shared region
830 munmap(loadAddress
, fileLen
);
833 if ( base_address
!= (caddr_t
)baseAddress
)
834 this->setSlide((uintptr_t)base_address
- baseAddress
);
835 if ( context
.verboseMapping
) {
836 if ( base_address
!= (caddr_t
)baseAddress
)
837 fprintf(stderr
, "dyld: Mapping split-seg load_shared_alt_region %s\n", this->getPath());
839 fprintf(stderr
, "dyld: Mapping split-seg load_shared %s\n", this->getPath());
840 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
841 Segment
* seg
= fSegments
[segIndex
];
842 const sf_mapping
* entry
= &mappingTable
[entryIndex
];
843 if ( (entry
->protection
& VM_PROT_ZF
) == 0 )
844 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
845 seg
->getName(), seg
->getActualLoadAddress(), seg
->getActualLoadAddress()+seg
->getFileSize()-1);
846 if ( entryIndex
< (mappingTableCount
-1) ) {
847 const sf_mapping
* nextEntry
= &mappingTable
[entryIndex
+1];
848 if ( (nextEntry
->protection
& VM_PROT_ZF
) != 0 ) {
849 fprintf(stderr
, "%18s at 0x%08lX->0x%08lX\n",
850 seg
->getName(), (uintptr_t)(nextEntry
->mapping_offset
+ base_address
), (uintptr_t)(nextEntry
->mapping_offset
+ base_address
+ nextEntry
->size
- 1));
860 ImageLoaderMachO::initMappingTable(uint64_t offsetInFat
,
861 sf_mapping
*mappingTable
,
862 uintptr_t baseAddress
)
864 unsigned int segmentCount
= fSegments
.size();
865 for(unsigned int segIndex
=0,entryIndex
=0; segIndex
< segmentCount
; ++segIndex
, ++entryIndex
){
866 Segment
* seg
= fSegments
[segIndex
];
867 sf_mapping
* entry
= &mappingTable
[entryIndex
];
868 entry
->mapping_offset
= seg
->getPreferredLoadAddress() - baseAddress
;
869 entry
->size
= seg
->getFileSize();
870 entry
->file_offset
= seg
->getFileOffset() + offsetInFat
;
871 entry
->protection
= VM_PROT_NONE
;
872 if ( !seg
->unaccessible() ) {
873 if ( seg
->executable() )
874 entry
->protection
|= VM_PROT_EXECUTE
;
875 if ( seg
->readable() )
876 entry
->protection
|= VM_PROT_READ
;
877 if ( seg
->writeable() )
878 entry
->protection
|= VM_PROT_WRITE
| VM_PROT_COW
;
882 if ( seg
->hasTrailingZeroFill() ) {
883 sf_mapping
* zfentry
= &mappingTable
[++entryIndex
];
884 zfentry
->mapping_offset
= entry
->mapping_offset
+ seg
->getFileSize();
885 zfentry
->size
= seg
->getSize() - seg
->getFileSize();
886 zfentry
->file_offset
= 0;
887 zfentry
->protection
= entry
->protection
| VM_PROT_COW
| VM_PROT_ZF
;
893 #endif // !__LP64__ split segs not supported for 64-bits
896 void ImageLoaderMachO::setSlide(intptr_t slide
)
901 void ImageLoaderMachO::parseLoadCmds()
903 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
904 const unsigned int segmentCount
= fSegments
.size();
905 for(unsigned int i
=0; i
< segmentCount
; ++i
){
906 Segment
* seg
= fSegments
[i
];
907 // set up pointer to __LINKEDIT segment
908 if ( strcmp(seg
->getName(),"__LINKEDIT") == 0 )
909 fLinkEditBase
= (uint8_t*)(seg
->getActualLoadAddress() - seg
->getFileOffset());
910 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
911 if ( strcmp(seg
->getName(),"__TEXT") == 0 ) {
912 if ( seg
->hasFixUps() )
913 fTextSegmentWithFixups
= (SegmentMachO
*)seg
;
915 // some segment always starts at beginning of file and contains mach_header and load commands
916 if ( (seg
->getFileOffset() == 0) && (seg
->getFileSize() != 0) ) {
917 fMachOData
= (uint8_t*)(seg
->getActualLoadAddress());
921 // keep count of prebound images with weak exports
922 if ( this->hasCoalescedExports() )
923 ++fgCountOfImagesWithWeakExports
;
925 // walk load commands (mapped in at start of __TEXT segment)
926 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
927 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
928 const struct load_command
* cmd
= cmds
;
929 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
933 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
934 fStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
935 fSymbolTable
= (struct macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
939 fDynamicInfo
= (struct dysymtab_command
*)cmd
;
941 case LC_SUB_UMBRELLA
:
942 fHasSubUmbrella
= true;
944 case LC_SUB_FRAMEWORK
:
946 const struct sub_framework_command
* subf
= (struct sub_framework_command
*)cmd
;
947 fReExportThruFramework
= (char*)cmd
+ subf
->umbrella
.offset
;
951 fHasSubLibraries
= true;
953 case LC_ROUTINES_COMMAND
:
954 fDashInit
= (struct macho_routines_command
*)cmd
;
956 case LC_SEGMENT_COMMAND
:
958 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
959 const bool isDataSeg
= (strcmp(seg
->segname
, "__DATA") == 0);
960 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
961 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
962 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
963 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
964 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
965 fModInitSection
= sect
;
966 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
967 fModTermSection
= sect
;
968 else if ( isDataSeg
&& (strcmp(sect
->sectname
, "__dyld") == 0) ) {
971 else if ( isDataSeg
&& (strcmp(sect
->sectname
, "__image_notify") == 0) )
972 fImageNotifySection
= sect
;
976 case LC_TWOLEVEL_HINTS
:
977 fTwoLevelHints
= (struct twolevel_hints_command
*)cmd
;
981 fDylibID
= (struct dylib_command
*)cmd
;
984 case LC_LOAD_WEAK_DYLIB
:
985 // do nothing, just prevent LC_REQ_DYLD exception from occuring
988 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 )
989 throwf("unknown required load command 0x%08X", cmd
->cmd
);
991 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
998 const char* ImageLoaderMachO::getInstallPath() const
1000 if ( fDylibID
!= NULL
) {
1001 return (char*)fDylibID
+ fDylibID
->dylib
.name
.offset
;
1006 // test if this image is re-exported through parent (the image that loaded this one)
1007 bool ImageLoaderMachO::isSubframeworkOf(const LinkContext
& context
, const ImageLoader
* parent
) const
1009 if ( fReExportThruFramework
!= NULL
) {
1010 // need to match LC_SUB_FRAMEWORK string against the leaf name of the install location of parent...
1011 const char* parentInstallPath
= parent
->getInstallPath();
1012 if ( parentInstallPath
!= NULL
) {
1013 const char* lastSlash
= strrchr(parentInstallPath
, '/');
1014 if ( lastSlash
!= NULL
) {
1015 if ( strcmp(&lastSlash
[1], fReExportThruFramework
) == 0 )
1017 if ( context
.imageSuffix
!= NULL
) {
1018 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1019 char reexportAndSuffix
[strlen(context
.imageSuffix
)+strlen(fReExportThruFramework
)+1];
1020 strcpy(reexportAndSuffix
, fReExportThruFramework
);
1021 strcat(reexportAndSuffix
, context
.imageSuffix
);
1022 if ( strcmp(&lastSlash
[1], reexportAndSuffix
) == 0 )
1031 // test if child is re-exported
1032 bool ImageLoaderMachO::hasSubLibrary(const LinkContext
& context
, const ImageLoader
* child
) const
1034 if ( fHasSubLibraries
) {
1035 // need to match LC_SUB_LIBRARY string against the leaf name (without extension) of the install location of child...
1036 const char* childInstallPath
= child
->getInstallPath();
1037 if ( childInstallPath
!= NULL
) {
1038 const char* lastSlash
= strrchr(childInstallPath
, '/');
1039 if ( lastSlash
!= NULL
) {
1040 const char* firstDot
= strchr(lastSlash
, '.');
1042 if ( firstDot
== NULL
)
1043 len
= strlen(lastSlash
);
1045 len
= firstDot
-lastSlash
-1;
1046 char childLeafName
[len
+1];
1047 strncpy(childLeafName
, &lastSlash
[1], len
);
1048 childLeafName
[len
] = '\0';
1049 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1050 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1051 const struct load_command
* cmd
= cmds
;
1052 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1054 case LC_SUB_LIBRARY
:
1056 const struct sub_library_command
* lib
= (struct sub_library_command
*)cmd
;
1057 const char* aSubLibName
= (char*)cmd
+ lib
->sub_library
.offset
;
1058 if ( strcmp(aSubLibName
, childLeafName
) == 0 )
1060 if ( context
.imageSuffix
!= NULL
) {
1061 // when DYLD_IMAGE_SUFFIX is used, childLeafName string needs imageSuffix removed from end
1062 char aSubLibNameAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubLibName
)+1];
1063 strcpy(aSubLibNameAndSuffix
, aSubLibName
);
1064 strcat(aSubLibNameAndSuffix
, context
.imageSuffix
);
1065 if ( strcmp(aSubLibNameAndSuffix
, childLeafName
) == 0 )
1071 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1076 if ( fHasSubUmbrella
) {
1077 // need to match LC_SUB_UMBRELLA string against the leaf name of install location of child...
1078 const char* childInstallPath
= child
->getInstallPath();
1079 if ( childInstallPath
!= NULL
) {
1080 const char* lastSlash
= strrchr(childInstallPath
, '/');
1081 if ( lastSlash
!= NULL
) {
1082 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1083 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1084 const struct load_command
* cmd
= cmds
;
1085 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1087 case LC_SUB_UMBRELLA
:
1089 const struct sub_umbrella_command
* um
= (struct sub_umbrella_command
*)cmd
;
1090 const char* aSubUmbrellaName
= (char*)cmd
+ um
->sub_umbrella
.offset
;
1091 if ( strcmp(aSubUmbrellaName
, &lastSlash
[1]) == 0 )
1093 if ( context
.imageSuffix
!= NULL
) {
1094 // when DYLD_IMAGE_SUFFIX is used, lastSlash string needs imageSuffix removed from end
1095 char umbrellaAndSuffix
[strlen(context
.imageSuffix
)+strlen(aSubUmbrellaName
)+1];
1096 strcpy(umbrellaAndSuffix
, aSubUmbrellaName
);
1097 strcat(umbrellaAndSuffix
, context
.imageSuffix
);
1098 if ( strcmp(umbrellaAndSuffix
, &lastSlash
[1]) == 0 )
1104 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1113 void* ImageLoaderMachO::getMain() const
1115 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1116 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1117 const struct load_command
* cmd
= cmds
;
1118 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1123 const ppc_thread_state_t
* registers
= (ppc_thread_state_t
*)(((char*)cmd
) + 16);
1124 return (void*)registers
->srr0
;
1126 const ppc_thread_state64_t
* registers
= (ppc_thread_state64_t
*)(((char*)cmd
) + 16);
1127 return (void*)registers
->srr0
;
1129 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
1130 return (void*)registers
->eip
;
1132 const x86_thread_state64_t
* registers
= (x86_thread_state64_t
*)(((char*)cmd
) + 16);
1133 return (void*)registers
->rip
;
1135 #warning need processor specific code
1140 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1146 uint32_t ImageLoaderMachO::doGetDependentLibraryCount()
1148 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1149 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1151 const struct load_command
* cmd
= cmds
;
1152 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1155 case LC_LOAD_WEAK_DYLIB
:
1159 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1164 void ImageLoaderMachO::doGetDependentLibraries(DependentLibrary libs
[])
1167 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1168 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1169 const struct load_command
* cmd
= cmds
;
1170 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1173 case LC_LOAD_WEAK_DYLIB
:
1175 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
1176 DependentLibrary
* lib
= &libs
[index
++];
1177 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
1178 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1180 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
1181 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
1182 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
1183 lib
->required
= (cmd
->cmd
== LC_LOAD_DYLIB
);
1184 lib
->checksumMatches
= false;
1185 lib
->isReExported
= false;
1189 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1193 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo()
1196 if ( fDylibID
!= NULL
) {
1197 info
.minVersion
= fDylibID
->dylib
.compatibility_version
;
1198 info
.maxVersion
= fDylibID
->dylib
.current_version
;
1199 info
.checksum
= fDylibID
->dylib
.timestamp
;
1202 info
.minVersion
= 0;
1203 info
.maxVersion
= 0;
1209 uintptr_t ImageLoaderMachO::getFirstWritableSegmentAddress()
1211 // in split segment libraries r_address is offset from first writable segment
1212 for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it
!= fSegments
.end(); ++it
) {
1213 if ( (*it
)->writeable() ) {
1214 return (*it
)->getActualLoadAddress();
1217 throw "no writable segment";
1220 uintptr_t ImageLoaderMachO::getRelocBase()
1223 // r_address is offset from first writable segment
1224 return getFirstWritableSegmentAddress();
1226 #if __ppc__ || __i386__
1227 if ( fIsSplitSeg
) {
1228 // in split segment libraries r_address is offset from first writable segment
1229 return getFirstWritableSegmentAddress();
1233 // in non-split segment libraries r_address is offset from first segment
1234 return fSegments
[0]->getActualLoadAddress();
1238 static inline void otherRelocsPPC(uintptr_t* locationToFix
, uint8_t relocationType
, uint16_t otherHalf
, uintptr_t slide
)
1240 // low 16 bits of 32-bit ppc instructions need fixing
1241 struct ppcInstruction
{ uint16_t opcode
; int16_t immediateValue
; };
1242 ppcInstruction
* instruction
= (ppcInstruction
*)locationToFix
;
1243 //uint32_t before = *((uint32_t*)locationToFix);
1244 switch ( relocationType
)
1246 case PPC_RELOC_LO16
:
1247 instruction
->immediateValue
= ((otherHalf
<< 16) | instruction
->immediateValue
) + slide
;
1249 case PPC_RELOC_HI16
:
1250 instruction
->immediateValue
= ((((instruction
->immediateValue
<< 16) | otherHalf
) + slide
) >> 16);
1252 case PPC_RELOC_HA16
:
1253 int16_t signedOtherHalf
= (int16_t)(otherHalf
& 0xffff);
1254 uint32_t temp
= (instruction
->immediateValue
<< 16) + signedOtherHalf
+ slide
;
1255 if ( (temp
& 0x00008000) != 0 )
1257 instruction
->immediateValue
= temp
>> 16;
1259 //uint32_t after = *((uint32_t*)locationToFix);
1260 //fprintf(stderr, "dyld: ppc fixup %0p type %d from 0x%08X to 0x%08X\n", locationToFix, relocationType, before, after);
1264 #if __ppc__ || __i386__
1265 void ImageLoaderMachO::resetPreboundLazyPointers(const LinkContext
& context
, uintptr_t relocBase
)
1267 // loop through all local (internal) relocation records looking for pre-bound-lazy-pointer values
1268 register const uintptr_t slide
= this->fSlide
;
1269 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]);
1270 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nlocrel
];
1271 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1272 if ( (reloc
->r_address
& R_SCATTERED
) != 0 ) {
1273 const struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
1274 if (sreloc
->r_length
== RELOC_SIZE
) {
1275 uintptr_t* locationToFix
= (uintptr_t*)(sreloc
->r_address
+ relocBase
);
1276 switch(sreloc
->r_type
) {
1278 case PPC_RELOC_PB_LA_PTR
:
1279 *locationToFix
= sreloc
->r_value
+ slide
;
1283 case GENERIC_RELOC_PB_LA_PTR
:
1284 *locationToFix
= sreloc
->r_value
+ slide
;
1294 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1296 // if prebound and loaded at prebound address, then no need to rebase
1297 if ( this->usablePrebinding(context
) ) {
1298 // skip rebasing cause prebound and prebinding not disabled
1299 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1303 // print why prebinding was not used
1304 if ( context
.verbosePrebinding
) {
1305 if ( !this->isPrebindable() ) {
1306 fprintf(stderr
, "dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1308 else if ( fSlide
!= 0 ) {
1309 fprintf(stderr
, "dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1311 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1312 fprintf(stderr
, "dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1314 else if ( !this->usesTwoLevelNameSpace() ){
1315 fprintf(stderr
, "dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1318 fprintf(stderr
, "dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1322 // cache values that are used in the following loop
1323 const uintptr_t relocBase
= this->getRelocBase();
1324 register const uintptr_t slide
= this->fSlide
;
1326 #if __ppc__ || __i386__
1327 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1328 if ( this->isPrebindable() )
1329 this->resetPreboundLazyPointers(context
, relocBase
);
1332 // if loaded at preferred address, no rebasing necessary
1336 // if there are __TEXT fixups, temporarily make __TEXT writable
1337 if ( fTextSegmentWithFixups
!= NULL
)
1338 fTextSegmentWithFixups
->tempWritable();
1340 // loop through all local (internal) relocation records
1341 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]);
1342 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nlocrel
];
1343 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1345 // only one kind of local relocation supported for x86_64
1346 if ( reloc
->r_length
!= 3 )
1347 throw "bad local relocation length";
1348 if ( reloc
->r_type
!= X86_64_RELOC_UNSIGNED
)
1349 throw "unknown local relocation type";
1350 if ( reloc
->r_pcrel
!= 0 )
1351 throw "bad local relocation pc_rel";
1352 if ( reloc
->r_extern
!= 0 )
1353 throw "extern relocation found with local relocations";
1354 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1356 #if __ppc__ || __ppc64__ || __i386__
1357 if ( (reloc
->r_address
& R_SCATTERED
) == 0 ) {
1358 if ( reloc
->r_symbolnum
== R_ABS
) {
1359 // ignore absolute relocations
1361 else if (reloc
->r_length
== RELOC_SIZE
) {
1362 switch(reloc
->r_type
) {
1363 case GENERIC_RELOC_VANILLA
:
1364 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1367 case PPC_RELOC_HI16
:
1368 case PPC_RELOC_LO16
:
1369 case PPC_RELOC_HA16
:
1370 // some tools leave object file relocations in linked images
1371 otherRelocsPPC((uintptr_t*)(reloc
->r_address
+ relocBase
), reloc
->r_type
, reloc
[1].r_address
, slide
);
1372 ++reloc
; // these relocations come in pairs, skip next
1376 throw "unknown local relocation type";
1380 throw "bad local relocation length";
1384 const struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
1385 if (sreloc
->r_length
== RELOC_SIZE
) {
1386 uintptr_t* locationToFix
= (uintptr_t*)(sreloc
->r_address
+ relocBase
);
1387 switch(sreloc
->r_type
) {
1388 case GENERIC_RELOC_VANILLA
:
1389 *locationToFix
+= slide
;
1392 case PPC_RELOC_HI16
:
1393 case PPC_RELOC_LO16
:
1394 case PPC_RELOC_HA16
:
1395 // Metrowerks compiler sometimes leaves object file relocations in linked images???
1396 ++reloc
; // these relocations come in pairs, get next one
1397 otherRelocsPPC(locationToFix
, sreloc
->r_type
, reloc
->r_address
, slide
);
1401 case PPC_RELOC_PB_LA_PTR
:
1405 case PPC_RELOC_PB_LA_PTR
:
1406 // these should never exist in ppc64, but the first ld64 had a bug and created them
1407 *locationToFix
= sreloc
->r_value
+ slide
;
1410 case GENERIC_RELOC_PB_LA_PTR
:
1415 throw "unknown local scattered relocation type";
1419 throw "bad local scattered relocation length";
1425 // if there were __TEXT fixups, restore write protection
1426 if ( fTextSegmentWithFixups
!= NULL
) {
1427 fTextSegmentWithFixups
->setPermissions();
1428 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
1432 fgTotalRebaseFixups
+= fDynamicInfo
->nlocrel
;
1436 const struct macho_nlist
* ImageLoaderMachO::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],
1437 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
)
1439 int32_t high
= symbolCount
-1;
1440 int32_t mid
= hintIndex
;
1442 // handle out of range hint
1443 if ( mid
>= (int32_t)symbolCount
) {
1444 mid
= symbolCount
/2;
1445 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1448 ++ImageLoaderMachO::fgHintedBinaryTreeSearchs
;
1451 for (int32_t low
= 0; low
<= high
; mid
= (low
+high
)/2) {
1452 const uint32_t index
= toc
[mid
].symbol_index
;
1453 const struct macho_nlist
* pivot
= &symbols
[index
];
1454 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1455 #if LINKEDIT_USAGE_DEBUG
1456 noteAccessedLinkEditAddress(&toc
[mid
]);
1457 noteAccessedLinkEditAddress(pivot
);
1458 noteAccessedLinkEditAddress(pivotStr
);
1460 int cmp
= astrcmp(key
, pivotStr
);
1475 const struct macho_nlist
* ImageLoaderMachO::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
)
1477 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1478 const struct macho_nlist
* base
= symbols
;
1479 for (uint32_t n
= symbolCount
; n
> 0; n
/= 2) {
1480 const struct macho_nlist
* pivot
= &base
[n
/2];
1481 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1482 #if LINKEDIT_USAGE_DEBUG
1483 noteAccessedLinkEditAddress(pivot
);
1484 noteAccessedLinkEditAddress(pivotStr
);
1486 int cmp
= astrcmp(key
, pivotStr
);
1491 // move base to symbol after pivot
1503 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, const void* hint
, bool searchReExports
, ImageLoader
** foundIn
) const
1505 const struct macho_nlist
* sym
= NULL
;
1506 const struct twolevel_hint
* theHint
= (struct twolevel_hint
*)hint
;
1507 if ( fDynamicInfo
->tocoff
== 0 )
1508 sym
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
);
1510 uint32_t start
= fDynamicInfo
->nextdefsym
;
1511 if ( theHint
!= NULL
)
1512 start
= theHint
->itoc
;
1513 if ( (theHint
== NULL
) || (theHint
->isub_image
== 0) ) {
1514 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1515 fDynamicInfo
->ntoc
, start
);
1518 if ( sym
!= NULL
) {
1519 if ( foundIn
!= NULL
)
1520 *foundIn
= (ImageLoader
*)this;
1522 return (const Symbol
*)sym
;
1525 if ( searchReExports
) {
1526 // hint might tell us to try a particular subimage
1527 if ( (theHint
!= NULL
) && (theHint
->isub_image
> 0) && (theHint
->isub_image
<= fLibrariesCount
) ) {
1528 // isub_image is an index into a list that is sorted non-rexported images first
1530 ImageLoader
* target
= NULL
;
1531 // pass one, only look at sub-frameworks
1532 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1533 DependentLibrary
& libInfo
= fLibraries
[i
];
1534 if ( libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
)) {
1535 if ( ++index
== theHint
->isub_image
) {
1536 target
= libInfo
.image
;
1541 if (target
!= NULL
) {
1542 // pass two, only look at non-sub-framework-reexports
1543 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1544 DependentLibrary
& libInfo
= fLibraries
[i
];
1545 if ( libInfo
.isReExported
&& !libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
) ) {
1546 if ( ++index
== theHint
->isub_image
) {
1547 target
= libInfo
.image
;
1553 if (target
!= NULL
) {
1554 const Symbol
* result
= target
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1555 if ( result
!= NULL
)
1560 // hint failed, try all sub images
1561 // pass one, only look at sub-frameworks
1562 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1563 DependentLibrary
& libInfo
= fLibraries
[i
];
1564 if ( (libInfo
.image
!= NULL
) && libInfo
.isSubFramework
) {
1565 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1566 if ( result
!= NULL
)
1570 // pass two, only look at non-sub-framework-reexports
1571 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1572 DependentLibrary
& libInfo
= fLibraries
[i
];
1573 if ( (libInfo
.image
!= NULL
) && libInfo
.isReExported
&& !libInfo
.isSubFramework
) {
1574 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1575 if ( result
!= NULL
)
1581 // last change: the hint is wrong (non-zero but actually in this image)
1582 if ( (theHint
!= NULL
) && (theHint
->isub_image
!= 0) ) {
1583 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1584 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
);
1585 if ( sym
!= NULL
) {
1586 if ( foundIn
!= NULL
)
1587 *foundIn
= (ImageLoader
*)this;
1588 return (const Symbol
*)sym
;
1597 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
) const
1599 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1600 return nlistSym
->n_value
+ fSlide
;
1603 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1605 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1606 if ( (nlistSym
->n_desc
& N_WEAK_DEF
) != 0 )
1607 return kWeakDefinition
;
1608 return kNoDefinitionOptions
;
1611 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1613 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1614 return &fStrings
[nlistSym
->n_un
.n_strx
];
1617 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1619 return fDynamicInfo
->nextdefsym
;
1623 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1625 if ( index
< fDynamicInfo
->nextdefsym
) {
1626 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iextdefsym
+ index
];
1627 return (const ImageLoader::Symbol
*)sym
;
1633 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1635 return fDynamicInfo
->nundefsym
;
1639 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1641 if ( index
< fDynamicInfo
->nundefsym
) {
1642 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iundefsym
+ index
];
1643 return (const ImageLoader::Symbol
*)sym
;
1649 ImageLoader::ReferenceFlags
ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1651 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1652 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1653 if ( ((nlistSym
->n_type
& N_TYPE
) == N_UNDF
) && (nlistSym
->n_value
!= 0) )
1654 flags
|= ImageLoader::kTentativeDefinition
;
1655 if ( (nlistSym
->n_desc
& N_WEAK_REF
) != 0 )
1656 flags
|= ImageLoader::kWeakReference
;
1661 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1663 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1664 return &fStrings
[nlistSym
->n_un
.n_strx
];
1668 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1670 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1671 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1672 const struct load_command
* cmd
= cmds
;
1673 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1675 case LC_SEGMENT_COMMAND
:
1677 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1678 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1679 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1680 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1681 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1682 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1683 *length
= sect
->size
;
1690 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1696 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1698 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1699 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1700 const struct load_command
* cmd
= cmds
;
1701 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1702 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1704 case LC_SEGMENT_COMMAND
:
1706 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1707 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1708 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1709 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1710 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1711 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1712 if ( segmentName
!= NULL
)
1713 *segmentName
= sect
->segname
;
1714 if ( sectionName
!= NULL
)
1715 *sectionName
= sect
->sectname
;
1716 if ( sectionOffset
!= NULL
)
1717 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1725 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1731 bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist
* symbol
)
1733 // if a define and weak ==> coalesced
1734 if ( ((symbol
->n_type
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc
& N_WEAK_DEF
) != 0) )
1736 // if an undefine and not referencing a weak symbol ==> coalesced
1737 if ( ((symbol
->n_type
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc
& N_REF_TO_WEAK
) != 0) )
1745 static void __attribute__((noreturn
)) throwSymbolNotFound(const char* symbol
, const char* referencedFrom
, const char* expectedIn
)
1747 const char* formatString
= "Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n";
1748 char buf
[strlen(symbol
)+strlen(referencedFrom
)+strlen(expectedIn
)+strlen(formatString
)];
1749 sprintf(buf
, formatString
, symbol
, referencedFrom
, expectedIn
);
1750 throw strdup(buf
); // this is a leak if exception doesn't halt program
1753 uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
, bool twoLevel
, ImageLoader
** foundIn
)
1755 const char* symbolName
= &fStrings
[undefinedSymbol
->n_un
.n_strx
];
1757 if ( context
.bindFlat
|| !twoLevel
) {
1759 if ( ((undefinedSymbol
->n_type
& N_PEXT
) != 0) && ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) ) {
1760 // is a multi-module private_extern internal reference that the linker did not optimize away
1761 uintptr_t addr
= undefinedSymbol
->n_value
+ this->fSlide
;
1766 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1767 return (*foundIn
)->getExportedSymbolAddress(sym
);
1768 // if a bundle is loaded privately the above will not find its exports
1769 if ( this->isBundle() && this->hasHiddenExports() ) {
1770 // look in self for needed symbol
1771 sym
= this->findExportedSymbol(symbolName
, NULL
, false, foundIn
);
1773 return (*foundIn
)->getExportedSymbolAddress(sym
);
1775 if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1776 // definition can't be found anywhere
1777 // if reference is weak_import, then it is ok, just return 0
1780 throwSymbolNotFound(symbolName
, this->getPath(), "flat namespace");
1783 // symbol requires searching images with coalesced symbols
1784 if ( this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol
) ) {
1786 if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) )
1787 return (*foundIn
)->getExportedSymbolAddress(sym
);
1788 //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace");
1789 //fprintf(stderr, "dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
1794 ImageLoader
* target
= NULL
;
1795 uint8_t ord
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
);
1796 if ( ord
== EXECUTABLE_ORDINAL
) {
1797 target
= context
.mainExecutable
;
1799 else if ( ord
== SELF_LIBRARY_ORDINAL
) {
1802 else if ( ord
== DYNAMIC_LOOKUP_ORDINAL
) {
1803 // rnielsen: HACKHACK
1806 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1807 return (*foundIn
)->getExportedSymbolAddress(sym
);
1808 // no image has exports this symbol
1809 // either report error or hope ZeroLink can just-in-time load an image
1810 context
.undefinedHandler(symbolName
);
1811 // try looking again
1812 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1813 return (*foundIn
)->getExportedSymbolAddress(sym
);
1815 throwSymbolNotFound(symbolName
, this->getPath(), "dynamic lookup");
1817 else if ( ord
<= fLibrariesCount
) {
1818 DependentLibrary
& libInfo
= fLibraries
[ord
-1];
1819 target
= libInfo
.image
;
1820 if ( (target
== NULL
) && (((undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0) || !libInfo
.required
) ) {
1821 // if target library not loaded and reference is weak or library is weak return 0
1826 throw "corrupt binary, library ordinal too big";
1829 if ( target
== NULL
) {
1830 fprintf(stderr
, "resolveUndefined(%s) in %s\n", symbolName
, this->getPath());
1831 throw "symbol not found";
1835 if ( fTwoLevelHints
!= NULL
) {
1836 uint32_t symIndex
= undefinedSymbol
- fSymbolTable
;
1837 int32_t undefinedIndex
= symIndex
- fDynamicInfo
->iundefsym
;
1838 if ( (undefinedIndex
>= 0) && ((uint32_t)undefinedIndex
< fDynamicInfo
->nundefsym
) ) {
1839 const struct twolevel_hint
* hints
= (struct twolevel_hint
*)(&fLinkEditBase
[fTwoLevelHints
->offset
]);
1840 const struct twolevel_hint
* theHint
= &hints
[undefinedIndex
];
1841 hint
= (void*)theHint
;
1845 const Symbol
* sym
= target
->findExportedSymbol(symbolName
, hint
, true, foundIn
);
1847 return (*foundIn
)->getExportedSymbolAddress(sym
);
1849 else if ( (undefinedSymbol
->n_type
& N_PEXT
) != 0 ) {
1850 // don't know why the static linker did not eliminate the internal reference to a private extern definition
1852 return undefinedSymbol
->n_value
+ fSlide
;
1854 else if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1855 // if definition not found and reference is weak return 0
1859 // nowhere to be found
1860 throwSymbolNotFound(symbolName
, this->getPath(), target
->getPath());
1864 // returns if 'addr' is within the address range of section 'sectionIndex'
1865 // fSlide is not used. 'addr' is assumed to be a prebound address in this image
1866 bool ImageLoaderMachO::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
)
1868 uint8_t currentSectionIndex
= 1;
1869 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1870 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1871 const struct load_command
* cmd
= cmds
;
1872 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1873 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1874 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1875 if ( (currentSectionIndex
<= sectionIndex
) && (sectionIndex
< currentSectionIndex
+seg
->nsects
) ) {
1876 // 'sectionIndex' is in this segment, get section info
1877 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1878 const struct macho_section
* const section
= §ionsStart
[sectionIndex
-currentSectionIndex
];
1879 return ( (section
->addr
<= addr
) && (addr
< section
->addr
+section
->size
) );
1882 // 'sectionIndex' not in this segment, skip to next segment
1883 currentSectionIndex
+= seg
->nsects
;
1886 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1892 void ImageLoaderMachO::doBindExternalRelocations(const LinkContext
& context
, bool onlyCoalescedSymbols
)
1894 const uintptr_t relocBase
= this->getRelocBase();
1895 const bool twoLevel
= this->usesTwoLevelNameSpace();
1896 const bool prebound
= this->isPrebindable();
1898 // if there are __TEXT fixups, temporarily make __TEXT writable
1899 if ( fTextSegmentWithFixups
!= NULL
)
1900 fTextSegmentWithFixups
->tempWritable();
1902 // cache last lookup
1903 const struct macho_nlist
* lastUndefinedSymbol
= 0;
1904 uintptr_t symbolAddr
= 0;
1905 ImageLoader
* image
= NULL
;
1907 // loop through all external relocation records and bind each
1908 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]);
1909 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nextrel
];
1910 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1911 if (reloc
->r_length
== RELOC_SIZE
) {
1912 switch(reloc
->r_type
) {
1915 const struct macho_nlist
* undefinedSymbol
= &fSymbolTable
[reloc
->r_symbolnum
];
1916 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
1917 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(undefinedSymbol
) )
1919 uintptr_t* location
= ((uintptr_t*)(reloc
->r_address
+ relocBase
));
1920 uintptr_t value
= *location
;
1922 if ( reloc
->r_pcrel
) {
1923 value
+= (uintptr_t)location
+ 4 - fSlide
;
1927 // we are doing relocations, so prebinding was not usable
1928 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1929 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1930 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1931 if ( ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc
& N_WEAK_DEF
) != 0) ) {
1932 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1933 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1934 // that we can subtract off the weak symbol address to get the addend.
1935 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1936 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1937 if ( (value
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) )
1938 value
-= undefinedSymbol
->n_value
;
1943 // is undefined or non-weak symbol, so do subtraction to get addend
1944 value
-= undefinedSymbol
->n_value
;
1947 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
1948 if ( undefinedSymbol
!= lastUndefinedSymbol
) {
1949 symbolAddr
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, &image
);
1950 lastUndefinedSymbol
= undefinedSymbol
;
1952 if ( context
.verboseBind
) {
1953 const char *path
= NULL
;
1955 path
= image
->getShortName();
1958 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx\n",
1959 this->getShortName(), (uintptr_t)location
,
1960 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
);
1963 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx + %ld\n",
1964 this->getShortName(), (uintptr_t)location
,
1965 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, value
);
1968 value
+= symbolAddr
;
1970 if ( reloc
->r_pcrel
) {
1971 *location
= value
- ((uintptr_t)location
+ 4);
1974 // don't dirty page if prebound value was correct
1975 if ( !prebound
|| (*location
!= value
) )
1979 // don't dirty page if prebound value was correct
1980 if ( !prebound
|| (*location
!= value
) )
1986 throw "unknown external relocation type";
1990 throw "bad external relocation length";
1994 // if there were __TEXT fixups, restore write protection
1995 if ( fTextSegmentWithFixups
!= NULL
) {
1996 fTextSegmentWithFixups
->setPermissions();
1997 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
2001 fgTotalBindFixups
+= fDynamicInfo
->nextrel
;
2004 const mach_header
* ImageLoaderMachO::machHeader() const
2006 return (mach_header
*)fMachOData
;
2009 uintptr_t ImageLoaderMachO::getSlide() const
2014 // hmm. maybe this should be up in ImageLoader??
2015 const void* ImageLoaderMachO::getBaseAddress() const
2017 Segment
* seg
= fSegments
[0];
2018 return (const void*)seg
->getActualLoadAddress();
2021 uintptr_t ImageLoaderMachO::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, ImageLoader
* targetImage
, const LinkContext
& context
)
2023 if ( context
.verboseBind
) {
2024 const char* path
= NULL
;
2025 if ( targetImage
!= NULL
)
2026 path
= targetImage
->getShortName();
2027 fprintf(stderr
, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
2028 this->getShortName(), symbolName
, (((sect
->flags
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"),
2029 path
, symbolName
, (uintptr_t)ptrToBind
, targetAddr
);
2031 if ( context
.bindingHandler
!= NULL
) {
2032 const char* path
= NULL
;
2033 if ( targetImage
!= NULL
)
2034 path
= targetImage
->getShortName();
2035 targetAddr
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
);
2038 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
2039 if ( ((sect
->flags
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2
== 5) ) {
2040 uint32_t rel32
= targetAddr
- (((uint32_t)ptrToBind
)+5);
2041 // re-write instruction in a thread-safe manner
2042 // use 8-byte compare-and-swap to alter 5-byte jump table entries
2043 // loop is required in case the extra three bytes that cover the next entry are altered by another thread
2046 volatile int64_t* jumpPtr
= (int64_t*)ptrToBind
;
2048 // By default the three extra bytes swapped follow the 5-byte JMP.
2049 // But, if the 5-byte jump is up against the end of the __IMPORT segment
2050 // We don't want to access bytes off the end of the segment, so we shift
2051 // the extra bytes to precede the 5-byte JMP.
2052 if ( (((uint32_t)ptrToBind
+ 8) & 0x00000FFC) == 0x00000000 ) {
2053 jumpPtr
= (int64_t*)((uint32_t)ptrToBind
- 3);
2056 int64_t oldEntry
= *jumpPtr
;
2061 newEntry
.int64
= oldEntry
;
2062 newEntry
.bytes
[pad
+0] = 0xE9; // JMP rel32
2063 newEntry
.bytes
[pad
+1] = rel32
& 0xFF;
2064 newEntry
.bytes
[pad
+2] = (rel32
>> 8) & 0xFF;
2065 newEntry
.bytes
[pad
+3] = (rel32
>> 16) & 0xFF;
2066 newEntry
.bytes
[pad
+4] = (rel32
>> 24) & 0xFF;
2067 done
= OSAtomicCompareAndSwap64Barrier(oldEntry
, newEntry
.int64
, (int64_t*)jumpPtr
);
2072 *ptrToBind
= targetAddr
;
2077 uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
)
2079 // scan for all non-lazy-pointer sections
2080 const bool twoLevel
= this->usesTwoLevelNameSpace();
2081 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2082 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2083 const struct load_command
* cmd
= cmds
;
2084 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2085 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2087 case LC_SEGMENT_COMMAND
:
2089 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2090 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2091 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2092 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2093 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2094 uint32_t symbolIndex
= INDIRECT_SYMBOL_LOCAL
;
2095 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2096 const uint32_t pointerCount
= sect
->size
/ sizeof(uintptr_t);
2097 uintptr_t* const symbolPointers
= (uintptr_t*)(sect
->addr
+ fSlide
);
2098 if ( (lazyPointer
>= symbolPointers
) && (lazyPointer
< &symbolPointers
[pointerCount
]) ) {
2099 const uint32_t indirectTableOffset
= sect
->reserved1
;
2100 const uint32_t lazyIndex
= lazyPointer
- symbolPointers
;
2101 symbolIndex
= indirectTable
[indirectTableOffset
+ lazyIndex
];
2105 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2106 // 5 bytes stubs on i386 are new "fast stubs"
2107 uint8_t* const jmpTableBase
= (uint8_t*)(sect
->addr
+ fSlide
);
2108 uint8_t* const jmpTableEnd
= jmpTableBase
+ sect
->size
;
2109 // initial CALL instruction in jump table leaves pointer to next entry, so back up
2110 uint8_t* const jmpTableEntryToPatch
= ((uint8_t*)lazyPointer
) - 5;
2111 lazyPointer
= (uintptr_t*)jmpTableEntryToPatch
;
2112 if ( (jmpTableEntryToPatch
>= jmpTableBase
) && (jmpTableEntryToPatch
< jmpTableEnd
) ) {
2113 const uint32_t indirectTableOffset
= sect
->reserved1
;
2114 const uint32_t entryIndex
= (jmpTableEntryToPatch
- jmpTableBase
)/5;
2115 symbolIndex
= indirectTable
[indirectTableOffset
+ entryIndex
];
2119 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
&& symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2120 const char* symbolName
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
];
2121 ImageLoader
* image
= NULL
;
2122 uintptr_t symbolAddr
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], twoLevel
, &image
);
2123 symbolAddr
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
, context
);
2124 ++fgTotalLazyBindFixups
;
2131 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2133 throw "lazy pointer not found";
2139 void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext
& context
, BindingLaziness bindness
, bool onlyCoalescedSymbols
)
2141 // scan for all non-lazy-pointer sections
2142 const bool twoLevel
= this->usesTwoLevelNameSpace();
2143 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2144 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2145 const struct load_command
* cmd
= cmds
;
2146 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2147 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2149 case LC_SEGMENT_COMMAND
:
2151 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2152 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2153 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2154 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2155 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2156 uint32_t elementSize
= sizeof(uintptr_t);
2157 uint32_t elementCount
= sect
->size
/ elementSize
;
2158 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2159 if ( (bindness
== kLazyOnly
) || (bindness
== kLazyOnlyNoDependents
) )
2162 else if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2163 // process each symbol pointer in this section
2164 fgTotalPossibleLazyBindFixups
+= elementCount
;
2165 if ( bindness
== kNonLazyOnly
)
2169 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2170 // process each jmp entry in this section
2171 elementCount
= sect
->size
/ 5;
2173 fgTotalPossibleLazyBindFixups
+= elementCount
;
2174 if ( bindness
== kNonLazyOnly
)
2181 const uint32_t indirectTableOffset
= sect
->reserved1
;
2182 uint8_t* ptrToBind
= (uint8_t*)(sect
->addr
+ fSlide
);
2183 for (uint32_t j
=0; j
< elementCount
; ++j
, ptrToBind
+= elementSize
) {
2184 uint32_t symbolIndex
= indirectTable
[indirectTableOffset
+ j
];
2185 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2186 *((uintptr_t*)ptrToBind
) += this->fSlide
;
2188 else if ( symbolIndex
== INDIRECT_SYMBOL_ABS
) {
2189 // do nothing since already has absolute address
2192 const struct macho_nlist
* sym
= &fSymbolTable
[symbolIndex
];
2193 if ( symbolIndex
== 0 ) {
2194 // This could be rdar://problem/3534709
2195 if ( ((const macho_header
*)fMachOData
)->filetype
== MH_EXECUTE
) {
2196 static bool alreadyWarned
= false;
2197 if ( (sym
->n_type
& N_TYPE
) != N_UNDF
) {
2198 // The indirect table parallels the (non)lazy pointer sections. For
2199 // instance, to find info about the fifth lazy pointer you look at the
2200 // fifth entry in the indirect table. (try otool -Iv on a file).
2201 // The entry in the indirect table contains an index into the symbol table.
2203 // The bug in ld caused the entry in the indirect table to be zero
2204 // (instead of a magic value that means a local symbol). So, if the
2205 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
2206 // symbol table index. The check I put in place is to see if the zero'th
2207 // symbol table entry is an import entry (usually it is a local symbol
2209 if ( context
.verboseWarnings
&& !alreadyWarned
) {
2210 fprintf(stderr
, "dyld: malformed executable '%s', skipping indirect symbol to %s\n",
2211 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]);
2212 alreadyWarned
= true;
2218 ImageLoader
*image
= NULL
;
2219 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
2220 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(sym
) )
2222 uintptr_t symbolAddr
;
2223 symbolAddr
= resolveUndefined(context
, sym
, twoLevel
, &image
);
2226 symbolAddr
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
, context
);
2230 fgTotalBindFixups
+= elementCount
;
2235 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2240 * The address of these symbols are written in to the (__DATA,__dyld) section
2241 * at the following offsets:
2242 * at offset 0 stub_binding_helper_interface
2243 * at offset 4 _dyld_func_lookup
2244 * at offset 8 start_debug_thread
2245 * The 'C' types (if any) for these symbols are ignored here and all are
2246 * declared as longs so the assignment of their address in to the section will
2247 * not require a cast. stub_binding_helper_interface is really a label in the
2248 * assembly code interface for the stub binding. It does not have a meaningful
2249 * 'C' type. _dyld_func_lookup is the routine in dyld_libfuncs.c.
2250 * start_debug_thread is the routine in debug.c.
2252 * For ppc the image's stub_binding_binding_helper is read from:
2253 * at offset 20 the image's stub_binding_binding_helper address
2254 * and saved into to the image structure.
2257 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
2258 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2259 void* startDebugThread
; // debugger interface ???
2260 void* debugPort
; // debugger interface ???
2261 void* debugThread
; // debugger interface ???
2262 void* stubBindHelper
; // filled in at static link time to point to stub helper in image
2263 void* coreDebug
; // ???
2266 // These are defined in dyldStartup.s
2267 extern "C" void stub_binding_helper();
2268 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
);
2269 extern "C" void fast_stub_binding_helper_interface();
2272 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
2274 if ( fDATAdyld
!= NULL
) {
2275 struct DATAdyld
* dd
= (struct DATAdyld
*)(fDATAdyld
->addr
+ fSlide
);
2276 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
2277 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
2278 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
2280 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
2281 if ( dd
->dyldFuncLookup
!= (void*)&dyld_func_lookup
)
2282 dd
->dyldFuncLookup
= (void*)&dyld_func_lookup
;
2284 //if ( fDATAdyld->size > offsetof(DATAdyld, startDebugThread) )
2285 // dd->startDebugThread = &start_debug_thread;
2287 //if ( fDATAdyld->size > offsetof(DATAdyld, stubBindHelper) )
2288 // save = dd->stubBindHelper;
2292 if ( ! this->usablePrebinding(context
) || !this->usesTwoLevelNameSpace() ) {
2293 // reset all "fast" stubs
2294 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2295 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2296 const struct load_command
* cmd
= cmds
;
2297 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2299 case LC_SEGMENT_COMMAND
:
2301 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2302 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2303 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2304 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2305 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2306 if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2307 // reset each jmp entry in this section
2308 uint8_t* start
= (uint8_t*)(sect
->addr
+ this->fSlide
);
2309 uint8_t* end
= start
+ sect
->size
;
2310 uintptr_t dyldHandler
= (uintptr_t)&fast_stub_binding_helper_interface
;
2311 for (uint8_t* entry
= start
; entry
< end
; entry
+= 5) {
2312 uint32_t rel32
= dyldHandler
- (((uint32_t)entry
)+5);
2313 entry
[0] = 0xE8; // CALL rel32
2314 entry
[1] = rel32
& 0xFF;
2315 entry
[2] = (rel32
>> 8) & 0xFF;
2316 entry
[3] = (rel32
>> 16) & 0xFF;
2317 entry
[4] = (rel32
>> 24) & 0xFF;
2323 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2329 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
2331 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2332 if ( this->isPrebindable()
2333 && (this->getSlide() == 0)
2334 && this->usesTwoLevelNameSpace()
2335 && this->allDependentLibrariesAsWhenPreBound() ) {
2336 // allow environment variables to disable prebinding
2337 if ( context
.bindFlat
)
2339 switch ( context
.prebindUsage
) {
2340 case kUseAllPrebinding
:
2342 case kUseSplitSegPrebinding
:
2343 return this->fIsSplitSeg
;
2344 case kUseAllButAppPredbinding
:
2345 return (this != context
.mainExecutable
);
2346 case kUseNoPrebinding
:
2353 void ImageLoaderMachO::doBind(const LinkContext
& context
, BindingLaziness bindness
)
2355 // set dyld entry points in image
2356 this->setupLazyPointerHandler(context
);
2358 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2359 // note: flat-namespace binaries need to be imports rebound (even if correctly prebound)
2360 if ( this->usablePrebinding(context
) && this->usesTwoLevelNameSpace() ) {
2361 // if image has coalesced symbols, then these need to be rebound, unless this is the only image with weak symbols
2362 if ( this->needsCoalescing() && (fgCountOfImagesWithWeakExports
> 1) ) {
2363 this->doBindExternalRelocations(context
, true);
2364 this->doBindIndirectSymbolPointers(context
, kLazyAndNonLazy
, true);
2366 // skip binding because prebound and prebinding not disabled
2370 // values bound by name are stored two different ways in mach-o
2373 case kLazyAndNonLazy
:
2374 // external relocations are used for data initialized to external symbols
2375 this->doBindExternalRelocations(context
, false);
2378 case kLazyOnlyNoDependents
:
2381 // "indirect symbols" are used for code references to external symbols
2382 this->doBindIndirectSymbolPointers(context
, bindness
, false);
2387 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
2389 if ( fDashInit
!= NULL
) {
2390 Initializer func
= (Initializer
)(fDashInit
->init_address
+ fSlide
);
2391 if ( context
.verboseInit
)
2392 fprintf(stderr
, "dyld: calling -init function 0x%p in %s\n", func
, this->getPath());
2393 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2397 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
2399 if ( fModInitSection
!= NULL
) {
2400 Initializer
* inits
= (Initializer
*)(fModInitSection
->addr
+ fSlide
);
2401 const uint32_t count
= fModInitSection
->size
/ sizeof(uintptr_t);
2402 for (uint32_t i
=0; i
< count
; ++i
) {
2403 Initializer func
= inits
[i
];
2404 if ( context
.verboseInit
)
2405 fprintf(stderr
, "dyld: calling initializer function %p in %s\n", func
, this->getPath());
2406 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2412 void ImageLoaderMachO::doInitialization(const LinkContext
& context
)
2414 // mach-o has -init and static initializers
2415 doImageInit(context
);
2416 doModInitFunctions(context
);
2419 bool ImageLoaderMachO::needsInitialization()
2421 return ( (fDashInit
!= NULL
) || (fModInitSection
!= NULL
) );
2425 bool ImageLoaderMachO::needsTermination()
2427 return ( fModTermSection
!= NULL
);
2430 bool ImageLoaderMachO::hasImageNotification()
2432 return ( fImageNotifySection
!= NULL
);
2436 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
2438 if ( fModTermSection
!= NULL
) {
2439 Terminator
* terms
= (Terminator
*)(fModTermSection
->addr
+ fSlide
);
2440 const uint32_t count
= fModTermSection
->size
/ sizeof(uintptr_t);
2441 for (uint32_t i
=count
; i
> 0; --i
) {
2442 Terminator func
= terms
[i
-1];
2443 if ( context
.verboseInit
)
2444 fprintf(stderr
, "dyld: calling terminaton function %p in %s\n", func
, this->getPath());
2450 void ImageLoaderMachO::doNotification(enum dyld_image_mode mode
, uint32_t infoCount
, const struct dyld_image_info info
[])
2452 if ( fImageNotifySection
!= NULL
) {
2453 dyld_image_notifier
* notes
= (dyld_image_notifier
*)(fImageNotifySection
->addr
+ fSlide
);
2454 const uint32_t count
= fImageNotifySection
->size
/ sizeof(uintptr_t);
2455 for (uint32_t i
=count
; i
> 0; --i
) {
2456 dyld_image_notifier func
= notes
[i
-1];
2457 func(mode
, infoCount
, info
);
2462 void ImageLoaderMachO::printStatistics(unsigned int imageCount
)
2464 ImageLoader::printStatistics(imageCount
);
2465 fprintf(stderr
, "total hinted binary tree searches: %d\n", fgHintedBinaryTreeSearchs
);
2466 fprintf(stderr
, "total unhinted binary tree searches: %d\n", fgUnhintedBinaryTreeSearchs
);
2467 fprintf(stderr
, "total images with weak exports: %d\n", fgCountOfImagesWithWeakExports
);
2469 #if LINKEDIT_USAGE_DEBUG
2470 fprintf(stderr
, "linkedit pages accessed (%lu):\n", sLinkEditPageBuckets
.size());
2474 void ImageLoaderMachO::doPrebinding(const LinkContext
& context
, time_t timestamp
, uint8_t* fileToPrebind
)
2476 // update __DATA segment
2477 this->applyPrebindingToDATA(fileToPrebind
);
2479 // update load commands
2480 this->applyPrebindingToLoadCommands(context
, fileToPrebind
, timestamp
);
2482 // update symbol table
2483 this->applyPrebindingToLinkEdit(context
, fileToPrebind
);
2486 void ImageLoaderMachO::applyPrebindingToDATA(uint8_t* fileToPrebind
)
2488 const unsigned int segmentCount
= fSegments
.size();
2489 for(unsigned int i
=0; i
< segmentCount
; ++i
) {
2490 SegmentMachO
* seg
= (SegmentMachO
*)fSegments
[i
];
2491 if ( seg
->writeable() ) {
2492 memcpy(&fileToPrebind
[seg
->fFileOffset
], (void*)seg
->getActualLoadAddress(), seg
->fFileSize
);
2497 void ImageLoaderMachO::applyPrebindingToLoadCommands(const LinkContext
& context
, uint8_t* fileToPrebind
, time_t timestamp
)
2499 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2500 const uint32_t cmd_count
= mh
->ncmds
;
2501 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2502 const struct load_command
* cmd
= cmds
;
2503 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2506 case LC_LOAD_WEAK_DYLIB
:
2508 // update each dylib load command with the timestamp of the target dylib
2509 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2510 const char* name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
2511 for (const DependentLibrary
* dl
=fLibraries
; dl
< &fLibraries
[fLibrariesCount
]; dl
++) {
2512 if (strcmp(dl
->name
, name
) == 0 ) {
2513 // found matching DependentLibrary for this load command
2514 ImageLoaderMachO
* targetImage
= (ImageLoaderMachO
*)(dl
->image
); // !!! assume only mach-o images are prebound
2515 if ( ! targetImage
->isPrebindable() )
2516 throw "dependent dylib is not prebound";
2517 // if the target is currently being re-prebound then its timestamp will be the same as this one
2518 if ( ! targetImage
->usablePrebinding(context
) ) {
2519 dylib
->dylib
.timestamp
= timestamp
;
2522 // otherwise dependent library is already correctly prebound, so use its checksum
2523 dylib
->dylib
.timestamp
= targetImage
->doGetLibraryInfo().checksum
;
2532 // update the ID of this library with the new timestamp
2533 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2534 dylib
->dylib
.timestamp
= timestamp
;
2537 case LC_SEGMENT_COMMAND
:
2538 // if dylib was rebased, update segment commands
2539 if ( fSlide
!= 0 ) {
2540 struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2541 seg
->vmaddr
+= fSlide
;
2542 struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2543 struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2544 for (struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2545 sect
->addr
+= fSlide
;
2549 case LC_ROUTINES_COMMAND
:
2550 // if dylib was rebased, update -init command
2551 if ( fSlide
!= 0 ) {
2552 struct macho_routines_command
* routines
= (struct macho_routines_command
*)cmd
;
2553 routines
->init_address
+= fSlide
;
2557 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2561 void ImageLoaderMachO::applyPrebindingToLinkEdit(const LinkContext
& context
, uint8_t* fileToPrebind
)
2563 // In prebound images, the n_value of the symbol table entry for is the prebound address
2564 // This is needed when prebinding can't be used, to back solve for any possible addend in non-lazy pointers
2565 const char* stringPool
= NULL
;
2566 struct macho_nlist
* symbolTable
= NULL
;
2567 const struct dysymtab_command
* dysymtab
= NULL
;
2569 // get symbol table info
2570 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2571 const uint32_t cmd_count
= mh
->ncmds
;
2572 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2573 const struct load_command
* cmd
= cmds
;
2574 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2578 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
2579 stringPool
= (const char*)&fileToPrebind
[symtab
->stroff
];
2580 symbolTable
= (struct macho_nlist
*)(&fileToPrebind
[symtab
->symoff
]);
2584 dysymtab
= (struct dysymtab_command
*)cmd
;
2587 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2590 // walk all imports and re-resolve their n_value (needed incase prebinding is invalid)
2591 struct macho_nlist
* lastImport
= &symbolTable
[dysymtab
->iundefsym
+dysymtab
->nundefsym
];
2592 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iundefsym
]; entry
< lastImport
; ++entry
) {
2594 entry
->n_value
= this->resolveUndefined(context
, entry
, this->usesTwoLevelNameSpace(), &dummy
);
2597 // walk all exports and slide their n_value
2598 struct macho_nlist
* lastExport
= &symbolTable
[dysymtab
->iextdefsym
+dysymtab
->nextdefsym
];
2599 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iextdefsym
]; entry
< lastExport
; ++entry
) {
2600 if ( (entry
->n_type
& N_TYPE
) == N_SECT
)
2601 entry
->n_value
+= fSlide
;
2604 // walk all local symbols and slide their n_value
2605 struct macho_nlist
* lastLocal
= &symbolTable
[dysymtab
->ilocalsym
+dysymtab
->nlocalsym
];
2606 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->ilocalsym
]; entry
< lastLocal
; ++entry
) {
2607 if ( entry
->n_sect
!= NO_SECT
)
2608 entry
->n_value
+= fSlide
;
2611 // walk all local relocations and reset every PPC_RELOC_PB_LA_PTR r_value
2612 relocation_info
* const relocsStart
= (struct relocation_info
*)(&fileToPrebind
[dysymtab
->locreloff
]);
2613 relocation_info
* const relocsEnd
= &relocsStart
[dysymtab
->nlocrel
];
2614 for (relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2615 if ( (reloc
->r_address
& R_SCATTERED
) != 0 ) {
2616 struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
2617 if (sreloc
->r_length
== RELOC_SIZE
) {
2618 switch(sreloc
->r_type
) {
2619 #if __ppc__ || __ppc64__
2620 case PPC_RELOC_PB_LA_PTR
:
2621 #elif __i386__ || __x86_64__
2622 case GENERIC_RELOC_PB_LA_PTR
:
2624 #error unknown architecture
2626 sreloc
->r_value
+= fSlide
;
2633 // if multi-module, fix up objc_addr (10.4 and later runtime does not use this, but we want to keep file checksum consistent)
2634 if ( dysymtab
->nmodtab
!= 0 ) {
2635 dylib_module
* const modulesStart
= (struct dylib_module
*)(&fileToPrebind
[dysymtab
->modtaboff
]);
2636 dylib_module
* const modulesEnd
= &modulesStart
[dysymtab
->nmodtab
];
2637 for (dylib_module
* module=modulesStart
; module < modulesEnd
; ++module) {
2638 if ( module->objc_module_info_size
!= 0 ) {
2639 module->objc_module_info_addr
+= fSlide
;
2645 // file on disk has been reprebound, but we are still mapped to old file
2646 void ImageLoaderMachO::prebindUnmap(const LinkContext
& context
)
2648 // this removes all mappings to the old file, so the kernel will unlink (delete) it.
2649 // We need to leave the load commands and __LINKEDIT in place
2650 for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it
!= fSegments
.end(); ++it
) {
2651 void* segmentAddress
= (void*)((*it
)->getActualLoadAddress());
2652 uintptr_t segmentSize
= (*it
)->getSize();
2653 //fprintf(stderr, "unmapping segment %s at %p for %s\n", (*it)->getName(), segmentAddress, this->getPath());
2654 // save load commands at beginning of __TEXT segment
2655 if ( segmentAddress
== fMachOData
) {
2656 // typically load commands are one or two pages in size, so ok to alloc on stack
2657 uint32_t loadCmdSize
= sizeof(macho_header
) + ((macho_header
*)fMachOData
)->sizeofcmds
;
2658 uint32_t loadCmdPages
= (loadCmdSize
+4095) & (-4096);
2659 uint8_t loadcommands
[loadCmdPages
];
2660 memcpy(loadcommands
, fMachOData
, loadCmdPages
);
2661 // unmap whole __TEXT segment
2662 munmap((void*)(fMachOData
), segmentSize
);
2663 // allocate and copy back mach_header and load commands
2664 vm_address_t addr
= (vm_address_t
)fMachOData
;
2665 int r2
= vm_allocate(mach_task_self(), &addr
, loadCmdPages
, false /*at this address*/);
2667 fprintf(stderr
, "prebindUnmap() vm_allocate for __TEXT %d failed\n", loadCmdPages
);
2668 memcpy((void*)fMachOData
, loadcommands
, loadCmdPages
);
2669 //fprintf(stderr, "copying back load commands to %p size=%u for %s\n", segmentAddress, loadCmdPages, this->getPath());
2671 else if ( strcmp((*it
)->getName(), "__LINKEDIT") == 0 ) {
2672 uint32_t linkEditSize
= segmentSize
;
2673 uint32_t linkEditPages
= (linkEditSize
+4095) & (-4096);
2674 void* linkEditTmp
= malloc(linkEditPages
);
2675 memcpy(linkEditTmp
, segmentAddress
, linkEditPages
);
2676 // unmap whole __LINKEDIT segment
2677 munmap(segmentAddress
, segmentSize
);
2678 vm_address_t addr
= (vm_address_t
)segmentAddress
;
2679 int r2
= vm_allocate(mach_task_self(), &addr
, linkEditPages
, false /*at this address*/);
2681 fprintf(stderr
, "prebindUnmap() vm_allocate for __LINKEDIT %d failed\n", linkEditPages
);
2682 memcpy(segmentAddress
, linkEditTmp
, linkEditPages
);
2683 //fprintf(stderr, "copying back __LINKEDIT to %p size=%u for %s\n", segmentAddress, linkEditPages, this->getPath());
2687 // unmap any other segment
2688 munmap((void*)(segmentAddress
), (*it
)->getSize());
2695 SegmentMachO::SegmentMachO(const struct macho_segment_command
* cmd
, ImageLoaderMachO
* image
, const uint8_t* fileData
)
2696 : fImage(image
), fSize(cmd
->vmsize
), fFileSize(cmd
->filesize
), fFileOffset(cmd
->fileoff
), fPreferredLoadAddress(cmd
->vmaddr
),
2697 fVMProtection(cmd
->initprot
), fHasFixUps(false), fUnMapOnDestruction(false)
2699 strncpy(fName
, cmd
->segname
, 16);
2701 // scan sections for fix-up bit
2702 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)cmd
+ sizeof(struct macho_segment_command
));
2703 const struct macho_section
* const sectionsEnd
= §ionsStart
[cmd
->nsects
];
2704 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2705 if ( (sect
->flags
& (S_ATTR_EXT_RELOC
| S_ATTR_LOC_RELOC
)) != 0 )
2710 SegmentMachO::~SegmentMachO()
2712 if ( fUnMapOnDestruction
) {
2713 //fprintf(stderr, "unmapping segment %s at 0x%08lX\n", getName(), getActualLoadAddress());
2714 munmap((void*)(this->getActualLoadAddress()), this->getSize());
2718 const ImageLoader
* SegmentMachO::getImage()
2723 const char* SegmentMachO::getName()
2728 uintptr_t SegmentMachO::getSize()
2733 uintptr_t SegmentMachO::getFileSize()
2738 uintptr_t SegmentMachO::getFileOffset()
2743 bool SegmentMachO::readable()
2745 return ( (fVMProtection
& VM_PROT_READ
) != 0);
2748 bool SegmentMachO::writeable()
2750 return ((fVMProtection
& VM_PROT_WRITE
) != 0);
2753 bool SegmentMachO::executable()
2755 return ((fVMProtection
& VM_PROT_EXECUTE
) != 0);
2758 bool SegmentMachO::unaccessible()
2760 return (fVMProtection
== 0);
2763 bool SegmentMachO::hasFixUps()
2768 uintptr_t SegmentMachO::getActualLoadAddress()
2770 return fPreferredLoadAddress
+ fImage
->fSlide
;
2773 uintptr_t SegmentMachO::getPreferredLoadAddress()
2775 return fPreferredLoadAddress
;
2778 bool SegmentMachO::hasPreferredLoadAddress()
2780 return (fPreferredLoadAddress
!= 0);
2783 void SegmentMachO::setUnMapWhenDestructed(bool unmap
)
2785 fUnMapOnDestruction
= unmap
;
2788 static uint32_t *buildCRCTable(void)
2790 uint32_t *table
= new uint32_t[256];
2791 uint32_t p
= 0xedb88320UL
; // standard CRC-32 polynomial
2793 for (unsigned int i
= 0; i
< 256; i
++) {
2795 for (unsigned int j
= 0; j
< 8; j
++) {
2796 if ( c
& 1 ) c
= p
^ (c
>> 1);
2805 uint32_t SegmentMachO::crc32()
2807 if ( !readable() ) return 0;
2809 static uint32_t *crcTable
= NULL
;
2810 if ( !crcTable
) crcTable
= buildCRCTable();
2812 uint32_t crc
= ~(uint32_t)0;
2813 uint8_t *p
= (uint8_t *)getActualLoadAddress();
2814 uint8_t *end
= p
+ getSize();
2816 crc
= crcTable
[(crc
& 0xff) ^ (*p
++)] ^ (crc
>> 8);
2818 return crc
^ ~(uint32_t)0;