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 // <rdar://problem/5146059> update_prebinding fails if a prebound dylib depends on a non-prebound dylib
1304 // In the unusual case that we find a prebound dylib dependent on un-prebound dylib and we are running
1305 // update_prebinding, we want the link of the prebound dylib to fail so that it will be excluded from
1306 // the list of dylibs to be re-written.
1307 if ( context
.prebinding
&& !this->isPrebindable() )
1308 throwf("dylib not prebound: %s", this->getPath());
1310 // print why prebinding was not used
1311 if ( context
.verbosePrebinding
) {
1312 if ( !this->isPrebindable() ) {
1313 fprintf(stderr
, "dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1315 else if ( fSlide
!= 0 ) {
1316 fprintf(stderr
, "dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1318 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1319 fprintf(stderr
, "dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1321 else if ( !this->usesTwoLevelNameSpace() ){
1322 fprintf(stderr
, "dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1325 fprintf(stderr
, "dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1329 // cache values that are used in the following loop
1330 const uintptr_t relocBase
= this->getRelocBase();
1331 register const uintptr_t slide
= this->fSlide
;
1333 #if __ppc__ || __i386__
1334 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1335 if ( this->isPrebindable() )
1336 this->resetPreboundLazyPointers(context
, relocBase
);
1339 // if loaded at preferred address, no rebasing necessary
1343 // if there are __TEXT fixups, temporarily make __TEXT writable
1344 if ( fTextSegmentWithFixups
!= NULL
)
1345 fTextSegmentWithFixups
->tempWritable();
1347 // loop through all local (internal) relocation records
1348 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->locreloff
]);
1349 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nlocrel
];
1350 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1352 // only one kind of local relocation supported for x86_64
1353 if ( reloc
->r_length
!= 3 )
1354 throw "bad local relocation length";
1355 if ( reloc
->r_type
!= X86_64_RELOC_UNSIGNED
)
1356 throw "unknown local relocation type";
1357 if ( reloc
->r_pcrel
!= 0 )
1358 throw "bad local relocation pc_rel";
1359 if ( reloc
->r_extern
!= 0 )
1360 throw "extern relocation found with local relocations";
1361 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1363 #if __ppc__ || __ppc64__ || __i386__
1364 if ( (reloc
->r_address
& R_SCATTERED
) == 0 ) {
1365 if ( reloc
->r_symbolnum
== R_ABS
) {
1366 // ignore absolute relocations
1368 else if (reloc
->r_length
== RELOC_SIZE
) {
1369 switch(reloc
->r_type
) {
1370 case GENERIC_RELOC_VANILLA
:
1371 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
1374 case PPC_RELOC_HI16
:
1375 case PPC_RELOC_LO16
:
1376 case PPC_RELOC_HA16
:
1377 // some tools leave object file relocations in linked images
1378 otherRelocsPPC((uintptr_t*)(reloc
->r_address
+ relocBase
), reloc
->r_type
, reloc
[1].r_address
, slide
);
1379 ++reloc
; // these relocations come in pairs, skip next
1383 throw "unknown local relocation type";
1387 throw "bad local relocation length";
1391 const struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
1392 if (sreloc
->r_length
== RELOC_SIZE
) {
1393 uintptr_t* locationToFix
= (uintptr_t*)(sreloc
->r_address
+ relocBase
);
1394 switch(sreloc
->r_type
) {
1395 case GENERIC_RELOC_VANILLA
:
1396 *locationToFix
+= slide
;
1399 case PPC_RELOC_HI16
:
1400 case PPC_RELOC_LO16
:
1401 case PPC_RELOC_HA16
:
1402 // Metrowerks compiler sometimes leaves object file relocations in linked images???
1403 ++reloc
; // these relocations come in pairs, get next one
1404 otherRelocsPPC(locationToFix
, sreloc
->r_type
, reloc
->r_address
, slide
);
1408 case PPC_RELOC_PB_LA_PTR
:
1412 case PPC_RELOC_PB_LA_PTR
:
1413 // these should never exist in ppc64, but the first ld64 had a bug and created them
1414 *locationToFix
= sreloc
->r_value
+ slide
;
1417 case GENERIC_RELOC_PB_LA_PTR
:
1422 throw "unknown local scattered relocation type";
1426 throw "bad local scattered relocation length";
1432 // if there were __TEXT fixups, restore write protection
1433 if ( fTextSegmentWithFixups
!= NULL
) {
1434 fTextSegmentWithFixups
->setPermissions();
1435 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
1439 fgTotalRebaseFixups
+= fDynamicInfo
->nlocrel
;
1443 const struct macho_nlist
* ImageLoaderMachO::binarySearchWithToc(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[],
1444 const struct dylib_table_of_contents toc
[], uint32_t symbolCount
, uint32_t hintIndex
)
1446 int32_t high
= symbolCount
-1;
1447 int32_t mid
= hintIndex
;
1449 // handle out of range hint
1450 if ( mid
>= (int32_t)symbolCount
) {
1451 mid
= symbolCount
/2;
1452 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1455 ++ImageLoaderMachO::fgHintedBinaryTreeSearchs
;
1458 for (int32_t low
= 0; low
<= high
; mid
= (low
+high
)/2) {
1459 const uint32_t index
= toc
[mid
].symbol_index
;
1460 const struct macho_nlist
* pivot
= &symbols
[index
];
1461 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1462 #if LINKEDIT_USAGE_DEBUG
1463 noteAccessedLinkEditAddress(&toc
[mid
]);
1464 noteAccessedLinkEditAddress(pivot
);
1465 noteAccessedLinkEditAddress(pivotStr
);
1467 int cmp
= astrcmp(key
, pivotStr
);
1482 const struct macho_nlist
* ImageLoaderMachO::binarySearch(const char* key
, const char stringPool
[], const struct macho_nlist symbols
[], uint32_t symbolCount
)
1484 ++ImageLoaderMachO::fgUnhintedBinaryTreeSearchs
;
1485 const struct macho_nlist
* base
= symbols
;
1486 for (uint32_t n
= symbolCount
; n
> 0; n
/= 2) {
1487 const struct macho_nlist
* pivot
= &base
[n
/2];
1488 const char* pivotStr
= &stringPool
[pivot
->n_un
.n_strx
];
1489 #if LINKEDIT_USAGE_DEBUG
1490 noteAccessedLinkEditAddress(pivot
);
1491 noteAccessedLinkEditAddress(pivotStr
);
1493 int cmp
= astrcmp(key
, pivotStr
);
1498 // move base to symbol after pivot
1510 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, const void* hint
, bool searchReExports
, ImageLoader
** foundIn
) const
1512 const struct macho_nlist
* sym
= NULL
;
1513 const struct twolevel_hint
* theHint
= (struct twolevel_hint
*)hint
;
1514 if ( fDynamicInfo
->tocoff
== 0 )
1515 sym
= binarySearch(name
, fStrings
, &fSymbolTable
[fDynamicInfo
->iextdefsym
], fDynamicInfo
->nextdefsym
);
1517 uint32_t start
= fDynamicInfo
->nextdefsym
;
1518 if ( theHint
!= NULL
)
1519 start
= theHint
->itoc
;
1520 if ( (theHint
== NULL
) || (theHint
->isub_image
== 0) ) {
1521 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1522 fDynamicInfo
->ntoc
, start
);
1525 if ( sym
!= NULL
) {
1526 if ( foundIn
!= NULL
)
1527 *foundIn
= (ImageLoader
*)this;
1529 return (const Symbol
*)sym
;
1532 if ( searchReExports
) {
1533 // hint might tell us to try a particular subimage
1534 if ( (theHint
!= NULL
) && (theHint
->isub_image
> 0) && (theHint
->isub_image
<= fLibrariesCount
) ) {
1535 // isub_image is an index into a list that is sorted non-rexported images first
1537 ImageLoader
* target
= NULL
;
1538 // pass one, only look at sub-frameworks
1539 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1540 DependentLibrary
& libInfo
= fLibraries
[i
];
1541 if ( libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
)) {
1542 if ( ++index
== theHint
->isub_image
) {
1543 target
= libInfo
.image
;
1548 if (target
!= NULL
) {
1549 // pass two, only look at non-sub-framework-reexports
1550 for (uint32_t i
=0; i
< fLibrariesCount
; ++i
) {
1551 DependentLibrary
& libInfo
= fLibraries
[i
];
1552 if ( libInfo
.isReExported
&& !libInfo
.isSubFramework
&& (libInfo
.image
!= NULL
) ) {
1553 if ( ++index
== theHint
->isub_image
) {
1554 target
= libInfo
.image
;
1560 if (target
!= NULL
) {
1561 const Symbol
* result
= target
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1562 if ( result
!= NULL
)
1567 // hint failed, try all sub images
1568 // pass one, only look at sub-frameworks
1569 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1570 DependentLibrary
& libInfo
= fLibraries
[i
];
1571 if ( (libInfo
.image
!= NULL
) && libInfo
.isSubFramework
) {
1572 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1573 if ( result
!= NULL
)
1577 // pass two, only look at non-sub-framework-reexports
1578 for(unsigned int i
=0; i
< fLibrariesCount
; ++i
){
1579 DependentLibrary
& libInfo
= fLibraries
[i
];
1580 if ( (libInfo
.image
!= NULL
) && libInfo
.isReExported
&& !libInfo
.isSubFramework
) {
1581 const Symbol
* result
= libInfo
.image
->findExportedSymbol(name
, NULL
, searchReExports
, foundIn
);
1582 if ( result
!= NULL
)
1588 // last change: the hint is wrong (non-zero but actually in this image)
1589 if ( (theHint
!= NULL
) && (theHint
->isub_image
!= 0) ) {
1590 sym
= binarySearchWithToc(name
, fStrings
, fSymbolTable
, (dylib_table_of_contents
*)&fLinkEditBase
[fDynamicInfo
->tocoff
],
1591 fDynamicInfo
->ntoc
, fDynamicInfo
->nextdefsym
);
1592 if ( sym
!= NULL
) {
1593 if ( foundIn
!= NULL
)
1594 *foundIn
= (ImageLoader
*)this;
1595 return (const Symbol
*)sym
;
1604 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
) const
1606 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1607 return nlistSym
->n_value
+ fSlide
;
1610 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1612 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1613 if ( (nlistSym
->n_desc
& N_WEAK_DEF
) != 0 )
1614 return kWeakDefinition
;
1615 return kNoDefinitionOptions
;
1618 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1620 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1621 return &fStrings
[nlistSym
->n_un
.n_strx
];
1624 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1626 return fDynamicInfo
->nextdefsym
;
1630 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1632 if ( index
< fDynamicInfo
->nextdefsym
) {
1633 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iextdefsym
+ index
];
1634 return (const ImageLoader::Symbol
*)sym
;
1640 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1642 return fDynamicInfo
->nundefsym
;
1646 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1648 if ( index
< fDynamicInfo
->nundefsym
) {
1649 const struct macho_nlist
* sym
= &fSymbolTable
[fDynamicInfo
->iundefsym
+ index
];
1650 return (const ImageLoader::Symbol
*)sym
;
1656 ImageLoader::ReferenceFlags
ImageLoaderMachO::geImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1658 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1659 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1660 if ( ((nlistSym
->n_type
& N_TYPE
) == N_UNDF
) && (nlistSym
->n_value
!= 0) )
1661 flags
|= ImageLoader::kTentativeDefinition
;
1662 if ( (nlistSym
->n_desc
& N_WEAK_REF
) != 0 )
1663 flags
|= ImageLoader::kWeakReference
;
1668 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1670 const struct macho_nlist
* nlistSym
= (const struct macho_nlist
*)sym
;
1671 return &fStrings
[nlistSym
->n_un
.n_strx
];
1675 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1677 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1678 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1679 const struct load_command
* cmd
= cmds
;
1680 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1682 case LC_SEGMENT_COMMAND
:
1684 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1685 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1686 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1687 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1688 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1689 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1690 *length
= sect
->size
;
1697 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1703 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1705 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1706 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1707 const struct load_command
* cmd
= cmds
;
1708 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1709 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1711 case LC_SEGMENT_COMMAND
:
1713 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1714 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1715 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1716 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1717 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1718 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1719 if ( segmentName
!= NULL
)
1720 *segmentName
= sect
->segname
;
1721 if ( sectionName
!= NULL
)
1722 *sectionName
= sect
->sectname
;
1723 if ( sectionOffset
!= NULL
)
1724 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1732 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1738 bool ImageLoaderMachO::symbolRequiresCoalescing(const struct macho_nlist
* symbol
)
1740 // if a define and weak ==> coalesced
1741 if ( ((symbol
->n_type
& N_TYPE
) == N_SECT
) && ((symbol
->n_desc
& N_WEAK_DEF
) != 0) )
1743 // if an undefine and not referencing a weak symbol ==> coalesced
1744 if ( ((symbol
->n_type
& N_TYPE
) != N_SECT
) && ((symbol
->n_desc
& N_REF_TO_WEAK
) != 0) )
1752 static void __attribute__((noreturn
)) throwSymbolNotFound(const char* symbol
, const char* referencedFrom
, const char* expectedIn
)
1754 const char* formatString
= "Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n";
1755 char buf
[strlen(symbol
)+strlen(referencedFrom
)+strlen(expectedIn
)+strlen(formatString
)];
1756 sprintf(buf
, formatString
, symbol
, referencedFrom
, expectedIn
);
1757 throw strdup(buf
); // this is a leak if exception doesn't halt program
1760 uintptr_t ImageLoaderMachO::resolveUndefined(const LinkContext
& context
, const struct macho_nlist
* undefinedSymbol
, bool twoLevel
, ImageLoader
** foundIn
)
1762 const char* symbolName
= &fStrings
[undefinedSymbol
->n_un
.n_strx
];
1764 if ( context
.bindFlat
|| !twoLevel
) {
1766 if ( ((undefinedSymbol
->n_type
& N_PEXT
) != 0) && ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) ) {
1767 // is a multi-module private_extern internal reference that the linker did not optimize away
1768 uintptr_t addr
= undefinedSymbol
->n_value
+ this->fSlide
;
1773 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1774 return (*foundIn
)->getExportedSymbolAddress(sym
);
1775 // if a bundle is loaded privately the above will not find its exports
1776 if ( this->isBundle() && this->hasHiddenExports() ) {
1777 // look in self for needed symbol
1778 sym
= this->findExportedSymbol(symbolName
, NULL
, false, foundIn
);
1780 return (*foundIn
)->getExportedSymbolAddress(sym
);
1782 if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1783 // definition can't be found anywhere
1784 // if reference is weak_import, then it is ok, just return 0
1787 throwSymbolNotFound(symbolName
, this->getPath(), "flat namespace");
1790 // symbol requires searching images with coalesced symbols
1791 if ( !context
.prebinding
&& this->needsCoalescing() && symbolRequiresCoalescing(undefinedSymbol
) ) {
1793 if ( context
.coalescedExportFinder(symbolName
, &sym
, foundIn
) )
1794 return (*foundIn
)->getExportedSymbolAddress(sym
);
1795 //throwSymbolNotFound(symbolName, this->getPath(), "coalesced namespace");
1796 //fprintf(stderr, "dyld: coalesced symbol %s not found in any coalesced image, falling back to two-level lookup", symbolName);
1801 ImageLoader
* target
= NULL
;
1802 uint8_t ord
= GET_LIBRARY_ORDINAL(undefinedSymbol
->n_desc
);
1803 if ( ord
== EXECUTABLE_ORDINAL
) {
1804 target
= context
.mainExecutable
;
1806 else if ( ord
== SELF_LIBRARY_ORDINAL
) {
1809 else if ( ord
== DYNAMIC_LOOKUP_ORDINAL
) {
1810 // rnielsen: HACKHACK
1813 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1814 return (*foundIn
)->getExportedSymbolAddress(sym
);
1815 // no image has exports this symbol
1816 // either report error or hope ZeroLink can just-in-time load an image
1817 context
.undefinedHandler(symbolName
);
1818 // try looking again
1819 if ( context
.flatExportFinder(symbolName
, &sym
, foundIn
) )
1820 return (*foundIn
)->getExportedSymbolAddress(sym
);
1822 throwSymbolNotFound(symbolName
, this->getPath(), "dynamic lookup");
1824 else if ( ord
<= fLibrariesCount
) {
1825 DependentLibrary
& libInfo
= fLibraries
[ord
-1];
1826 target
= libInfo
.image
;
1827 if ( (target
== NULL
) && (((undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0) || !libInfo
.required
) ) {
1828 // if target library not loaded and reference is weak or library is weak return 0
1833 throw "corrupt binary, library ordinal too big";
1836 if ( target
== NULL
) {
1837 //fprintf(stderr, "resolveUndefined(%s) in %s\n", symbolName, this->getPath());
1838 throw "symbol not found";
1842 if ( fTwoLevelHints
!= NULL
) {
1843 uint32_t symIndex
= undefinedSymbol
- fSymbolTable
;
1844 int32_t undefinedIndex
= symIndex
- fDynamicInfo
->iundefsym
;
1845 if ( (undefinedIndex
>= 0) && ((uint32_t)undefinedIndex
< fDynamicInfo
->nundefsym
) ) {
1846 const struct twolevel_hint
* hints
= (struct twolevel_hint
*)(&fLinkEditBase
[fTwoLevelHints
->offset
]);
1847 const struct twolevel_hint
* theHint
= &hints
[undefinedIndex
];
1848 hint
= (void*)theHint
;
1852 const Symbol
* sym
= target
->findExportedSymbol(symbolName
, hint
, true, foundIn
);
1854 return (*foundIn
)->getExportedSymbolAddress(sym
);
1856 else if ( (undefinedSymbol
->n_type
& N_PEXT
) != 0 ) {
1857 // don't know why the static linker did not eliminate the internal reference to a private extern definition
1859 return undefinedSymbol
->n_value
+ fSlide
;
1861 else if ( (undefinedSymbol
->n_desc
& N_WEAK_REF
) != 0 ) {
1862 // if definition not found and reference is weak return 0
1866 // nowhere to be found
1867 throwSymbolNotFound(symbolName
, this->getPath(), target
->getPath());
1871 // returns if 'addr' is within the address range of section 'sectionIndex'
1872 // fSlide is not used. 'addr' is assumed to be a prebound address in this image
1873 bool ImageLoaderMachO::isAddrInSection(uintptr_t addr
, uint8_t sectionIndex
)
1875 uint8_t currentSectionIndex
= 1;
1876 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1877 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1878 const struct load_command
* cmd
= cmds
;
1879 for (unsigned long i
= 0; i
< cmd_count
; ++i
) {
1880 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1881 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1882 if ( (currentSectionIndex
<= sectionIndex
) && (sectionIndex
< currentSectionIndex
+seg
->nsects
) ) {
1883 // 'sectionIndex' is in this segment, get section info
1884 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1885 const struct macho_section
* const section
= §ionsStart
[sectionIndex
-currentSectionIndex
];
1886 return ( (section
->addr
<= addr
) && (addr
< section
->addr
+section
->size
) );
1889 // 'sectionIndex' not in this segment, skip to next segment
1890 currentSectionIndex
+= seg
->nsects
;
1893 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1899 void ImageLoaderMachO::doBindExternalRelocations(const LinkContext
& context
, bool onlyCoalescedSymbols
)
1901 const uintptr_t relocBase
= this->getRelocBase();
1902 const bool twoLevel
= this->usesTwoLevelNameSpace();
1903 const bool prebound
= this->isPrebindable();
1905 // if there are __TEXT fixups, temporarily make __TEXT writable
1906 if ( fTextSegmentWithFixups
!= NULL
)
1907 fTextSegmentWithFixups
->tempWritable();
1909 // cache last lookup
1910 const struct macho_nlist
* lastUndefinedSymbol
= 0;
1911 uintptr_t symbolAddr
= 0;
1912 ImageLoader
* image
= NULL
;
1914 // loop through all external relocation records and bind each
1915 const relocation_info
* const relocsStart
= (struct relocation_info
*)(&fLinkEditBase
[fDynamicInfo
->extreloff
]);
1916 const relocation_info
* const relocsEnd
= &relocsStart
[fDynamicInfo
->nextrel
];
1917 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
1918 if (reloc
->r_length
== RELOC_SIZE
) {
1919 switch(reloc
->r_type
) {
1922 const struct macho_nlist
* undefinedSymbol
= &fSymbolTable
[reloc
->r_symbolnum
];
1923 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
1924 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(undefinedSymbol
) )
1926 uintptr_t* location
= ((uintptr_t*)(reloc
->r_address
+ relocBase
));
1927 uintptr_t value
= *location
;
1929 if ( reloc
->r_pcrel
) {
1930 value
+= (uintptr_t)location
+ 4 - fSlide
;
1934 // we are doing relocations, so prebinding was not usable
1935 // in a prebound executable, the n_value field of an undefined symbol is set to the address where the symbol was found when prebound
1936 // so, subtracting that gives the initial displacement which we need to add to the newly found symbol address
1937 // if mach-o relocation structs had an "addend" field this complication would not be necessary.
1938 if ( ((undefinedSymbol
->n_type
& N_TYPE
) == N_SECT
) && ((undefinedSymbol
->n_desc
& N_WEAK_DEF
) != 0) ) {
1939 // weak symbols need special casing, since *location may have been prebound to a definition in another image.
1940 // If *location is currently prebound to somewhere in the same section as the weak definition, we assume
1941 // that we can subtract off the weak symbol address to get the addend.
1942 // If prebound elsewhere, we've lost the addend and have to assume it is zero.
1943 // The prebinding to elsewhere only happens with 10.4+ update_prebinding which only operates on a small set of Apple dylibs
1944 if ( (value
== undefinedSymbol
->n_value
) || this->isAddrInSection(value
, undefinedSymbol
->n_sect
) )
1945 value
-= undefinedSymbol
->n_value
;
1950 // is undefined or non-weak symbol, so do subtraction to get addend
1951 value
-= undefinedSymbol
->n_value
;
1954 // if undefinedSymbol is same as last time, then symbolAddr and image will resolve to the same too
1955 if ( undefinedSymbol
!= lastUndefinedSymbol
) {
1956 symbolAddr
= this->resolveUndefined(context
, undefinedSymbol
, twoLevel
, &image
);
1957 lastUndefinedSymbol
= undefinedSymbol
;
1959 if ( context
.verboseBind
) {
1960 const char *path
= NULL
;
1962 path
= image
->getShortName();
1965 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx\n",
1966 this->getShortName(), (uintptr_t)location
,
1967 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
);
1970 fprintf(stderr
, "dyld: bind: %s:0x%08lx = %s:%s, *0x%08lx = 0x%08lx + %ld\n",
1971 this->getShortName(), (uintptr_t)location
,
1972 path
, &fStrings
[undefinedSymbol
->n_un
.n_strx
], (uintptr_t)location
, symbolAddr
, value
);
1975 value
+= symbolAddr
;
1977 if ( reloc
->r_pcrel
) {
1978 *location
= value
- ((uintptr_t)location
+ 4);
1981 // don't dirty page if prebound value was correct
1982 if ( !prebound
|| (*location
!= value
) )
1986 // don't dirty page if prebound value was correct
1987 if ( !prebound
|| (*location
!= value
) )
1993 throw "unknown external relocation type";
1997 throw "bad external relocation length";
2001 // if there were __TEXT fixups, restore write protection
2002 if ( fTextSegmentWithFixups
!= NULL
) {
2003 fTextSegmentWithFixups
->setPermissions();
2004 sys_icache_invalidate((void*)fTextSegmentWithFixups
->getActualLoadAddress(), fTextSegmentWithFixups
->getSize());
2008 fgTotalBindFixups
+= fDynamicInfo
->nextrel
;
2011 const mach_header
* ImageLoaderMachO::machHeader() const
2013 return (mach_header
*)fMachOData
;
2016 uintptr_t ImageLoaderMachO::getSlide() const
2021 // hmm. maybe this should be up in ImageLoader??
2022 const void* ImageLoaderMachO::getBaseAddress() const
2024 Segment
* seg
= fSegments
[0];
2025 return (const void*)seg
->getActualLoadAddress();
2028 uintptr_t ImageLoaderMachO::bindIndirectSymbol(uintptr_t* ptrToBind
, const struct macho_section
* sect
, const char* symbolName
, uintptr_t targetAddr
, ImageLoader
* targetImage
, const LinkContext
& context
)
2030 if ( context
.verboseBind
) {
2031 const char* path
= NULL
;
2032 if ( targetImage
!= NULL
)
2033 path
= targetImage
->getShortName();
2034 fprintf(stderr
, "dyld: bind: %s:%s$%s = %s:%s, *0x%08lx = 0x%08lx\n",
2035 this->getShortName(), symbolName
, (((sect
->flags
& SECTION_TYPE
)==S_NON_LAZY_SYMBOL_POINTERS
) ? "non_lazy_ptr" : "lazy_ptr"),
2036 path
, symbolName
, (uintptr_t)ptrToBind
, targetAddr
);
2038 if ( context
.bindingHandler
!= NULL
) {
2039 const char* path
= NULL
;
2040 if ( targetImage
!= NULL
)
2041 path
= targetImage
->getShortName();
2042 targetAddr
= (uintptr_t)context
.bindingHandler(path
, symbolName
, (void *)targetAddr
);
2045 // i386 has special self-modifying stubs that change from "CALL rel32" to "JMP rel32"
2046 if ( ((sect
->flags
& SECTION_TYPE
) == S_SYMBOL_STUBS
) && ((sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) != 0) && (sect
->reserved2
== 5) ) {
2047 uint32_t rel32
= targetAddr
- (((uint32_t)ptrToBind
)+5);
2048 // re-write instruction in a thread-safe manner
2049 // use 8-byte compare-and-swap to alter 5-byte jump table entries
2050 // loop is required in case the extra three bytes that cover the next entry are altered by another thread
2053 volatile int64_t* jumpPtr
= (int64_t*)ptrToBind
;
2055 // By default the three extra bytes swapped follow the 5-byte JMP.
2056 // But, if the 5-byte jump is up against the end of the __IMPORT segment
2057 // We don't want to access bytes off the end of the segment, so we shift
2058 // the extra bytes to precede the 5-byte JMP.
2059 if ( (((uint32_t)ptrToBind
+ 8) & 0x00000FFC) == 0x00000000 ) {
2060 jumpPtr
= (int64_t*)((uint32_t)ptrToBind
- 3);
2063 int64_t oldEntry
= *jumpPtr
;
2068 newEntry
.int64
= oldEntry
;
2069 newEntry
.bytes
[pad
+0] = 0xE9; // JMP rel32
2070 newEntry
.bytes
[pad
+1] = rel32
& 0xFF;
2071 newEntry
.bytes
[pad
+2] = (rel32
>> 8) & 0xFF;
2072 newEntry
.bytes
[pad
+3] = (rel32
>> 16) & 0xFF;
2073 newEntry
.bytes
[pad
+4] = (rel32
>> 24) & 0xFF;
2074 done
= OSAtomicCompareAndSwap64Barrier(oldEntry
, newEntry
.int64
, (int64_t*)jumpPtr
);
2079 *ptrToBind
= targetAddr
;
2084 uintptr_t ImageLoaderMachO::doBindLazySymbol(uintptr_t* lazyPointer
, const LinkContext
& context
)
2086 // scan for all non-lazy-pointer sections
2087 const bool twoLevel
= this->usesTwoLevelNameSpace();
2088 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2089 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2090 const struct load_command
* cmd
= cmds
;
2091 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2092 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2094 case LC_SEGMENT_COMMAND
:
2096 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2097 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2098 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2099 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2100 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2101 uint32_t symbolIndex
= INDIRECT_SYMBOL_LOCAL
;
2102 if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2103 const uint32_t pointerCount
= sect
->size
/ sizeof(uintptr_t);
2104 uintptr_t* const symbolPointers
= (uintptr_t*)(sect
->addr
+ fSlide
);
2105 if ( (lazyPointer
>= symbolPointers
) && (lazyPointer
< &symbolPointers
[pointerCount
]) ) {
2106 const uint32_t indirectTableOffset
= sect
->reserved1
;
2107 const uint32_t lazyIndex
= lazyPointer
- symbolPointers
;
2108 symbolIndex
= indirectTable
[indirectTableOffset
+ lazyIndex
];
2112 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2113 // 5 bytes stubs on i386 are new "fast stubs"
2114 uint8_t* const jmpTableBase
= (uint8_t*)(sect
->addr
+ fSlide
);
2115 uint8_t* const jmpTableEnd
= jmpTableBase
+ sect
->size
;
2116 // initial CALL instruction in jump table leaves pointer to next entry, so back up
2117 uint8_t* const jmpTableEntryToPatch
= ((uint8_t*)lazyPointer
) - 5;
2118 lazyPointer
= (uintptr_t*)jmpTableEntryToPatch
;
2119 if ( (jmpTableEntryToPatch
>= jmpTableBase
) && (jmpTableEntryToPatch
< jmpTableEnd
) ) {
2120 const uint32_t indirectTableOffset
= sect
->reserved1
;
2121 const uint32_t entryIndex
= (jmpTableEntryToPatch
- jmpTableBase
)/5;
2122 symbolIndex
= indirectTable
[indirectTableOffset
+ entryIndex
];
2126 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
&& symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
2127 const char* symbolName
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
];
2128 ImageLoader
* image
= NULL
;
2129 uintptr_t symbolAddr
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], twoLevel
, &image
);
2130 symbolAddr
= this->bindIndirectSymbol(lazyPointer
, sect
, symbolName
, symbolAddr
, image
, context
);
2131 ++fgTotalLazyBindFixups
;
2138 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2140 throw "lazy pointer not found";
2146 void ImageLoaderMachO::doBindIndirectSymbolPointers(const LinkContext
& context
, BindingLaziness bindness
, bool onlyCoalescedSymbols
)
2148 // scan for all non-lazy-pointer sections
2149 const bool twoLevel
= this->usesTwoLevelNameSpace();
2150 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2151 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2152 const struct load_command
* cmd
= cmds
;
2153 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2154 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2156 case LC_SEGMENT_COMMAND
:
2158 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2159 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2160 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2161 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2162 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2163 uint32_t elementSize
= sizeof(uintptr_t);
2164 uint32_t elementCount
= sect
->size
/ elementSize
;
2165 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
2166 if ( (bindness
== kLazyOnly
) || (bindness
== kLazyOnlyNoDependents
) )
2169 else if ( type
== S_LAZY_SYMBOL_POINTERS
) {
2170 // process each symbol pointer in this section
2171 fgTotalPossibleLazyBindFixups
+= elementCount
;
2172 if ( bindness
== kNonLazyOnly
)
2176 else if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2177 // process each jmp entry in this section
2178 elementCount
= sect
->size
/ 5;
2180 fgTotalPossibleLazyBindFixups
+= elementCount
;
2181 if ( bindness
== kNonLazyOnly
)
2188 const uint32_t indirectTableOffset
= sect
->reserved1
;
2189 uint8_t* ptrToBind
= (uint8_t*)(sect
->addr
+ fSlide
);
2190 for (uint32_t j
=0; j
< elementCount
; ++j
, ptrToBind
+= elementSize
) {
2191 uint32_t symbolIndex
= indirectTable
[indirectTableOffset
+ j
];
2192 if ( symbolIndex
== INDIRECT_SYMBOL_LOCAL
) {
2193 *((uintptr_t*)ptrToBind
) += this->fSlide
;
2195 else if ( symbolIndex
== INDIRECT_SYMBOL_ABS
) {
2196 // do nothing since already has absolute address
2199 const struct macho_nlist
* sym
= &fSymbolTable
[symbolIndex
];
2200 if ( symbolIndex
== 0 ) {
2201 // This could be rdar://problem/3534709
2202 if ( ((const macho_header
*)fMachOData
)->filetype
== MH_EXECUTE
) {
2203 static bool alreadyWarned
= false;
2204 if ( (sym
->n_type
& N_TYPE
) != N_UNDF
) {
2205 // The indirect table parallels the (non)lazy pointer sections. For
2206 // instance, to find info about the fifth lazy pointer you look at the
2207 // fifth entry in the indirect table. (try otool -Iv on a file).
2208 // The entry in the indirect table contains an index into the symbol table.
2210 // The bug in ld caused the entry in the indirect table to be zero
2211 // (instead of a magic value that means a local symbol). So, if the
2212 // symbolIndex == 0, we may be encountering the bug, or 0 may be a valid
2213 // symbol table index. The check I put in place is to see if the zero'th
2214 // symbol table entry is an import entry (usually it is a local symbol
2216 if ( context
.verboseWarnings
&& !alreadyWarned
) {
2217 fprintf(stderr
, "dyld: malformed executable '%s', skipping indirect symbol to %s\n",
2218 this->getPath(), &fStrings
[sym
->n_un
.n_strx
]);
2219 alreadyWarned
= true;
2225 ImageLoader
*image
= NULL
;
2226 // if only processing coalesced symbols and this one does not require coalesceing, skip to next
2227 if ( onlyCoalescedSymbols
&& !symbolRequiresCoalescing(sym
) )
2229 uintptr_t symbolAddr
;
2230 symbolAddr
= resolveUndefined(context
, sym
, twoLevel
, &image
);
2233 symbolAddr
= this->bindIndirectSymbol((uintptr_t*)ptrToBind
, sect
, &fStrings
[sym
->n_un
.n_strx
], symbolAddr
, image
, context
);
2237 fgTotalBindFixups
+= elementCount
;
2242 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2247 * The address of these symbols are written in to the (__DATA,__dyld) section
2248 * at the following offsets:
2249 * at offset 0 stub_binding_helper_interface
2250 * at offset 4 _dyld_func_lookup
2251 * at offset 8 start_debug_thread
2252 * The 'C' types (if any) for these symbols are ignored here and all are
2253 * declared as longs so the assignment of their address in to the section will
2254 * not require a cast. stub_binding_helper_interface is really a label in the
2255 * assembly code interface for the stub binding. It does not have a meaningful
2256 * 'C' type. _dyld_func_lookup is the routine in dyld_libfuncs.c.
2257 * start_debug_thread is the routine in debug.c.
2259 * For ppc the image's stub_binding_binding_helper is read from:
2260 * at offset 20 the image's stub_binding_binding_helper address
2261 * and saved into to the image structure.
2264 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
2265 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2266 void* startDebugThread
; // debugger interface ???
2267 void* debugPort
; // debugger interface ???
2268 void* debugThread
; // debugger interface ???
2269 void* stubBindHelper
; // filled in at static link time to point to stub helper in image
2270 void* coreDebug
; // ???
2273 // These are defined in dyldStartup.s
2274 extern "C" void stub_binding_helper();
2275 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
);
2276 extern "C" void fast_stub_binding_helper_interface();
2279 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
2281 if ( fDATAdyld
!= NULL
) {
2282 struct DATAdyld
* dd
= (struct DATAdyld
*)(fDATAdyld
->addr
+ fSlide
);
2283 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
2284 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
2285 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
2287 if ( fDATAdyld
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
2288 if ( dd
->dyldFuncLookup
!= (void*)&dyld_func_lookup
)
2289 dd
->dyldFuncLookup
= (void*)&dyld_func_lookup
;
2291 //if ( fDATAdyld->size > offsetof(DATAdyld, startDebugThread) )
2292 // dd->startDebugThread = &start_debug_thread;
2294 //if ( fDATAdyld->size > offsetof(DATAdyld, stubBindHelper) )
2295 // save = dd->stubBindHelper;
2299 if ( ! this->usablePrebinding(context
) || !this->usesTwoLevelNameSpace() ) {
2300 // reset all "fast" stubs
2301 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2302 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2303 const struct load_command
* cmd
= cmds
;
2304 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2306 case LC_SEGMENT_COMMAND
:
2308 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2309 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2310 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2311 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2312 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2313 if ( (type
== S_SYMBOL_STUBS
) && (sect
->flags
& S_ATTR_SELF_MODIFYING_CODE
) && (sect
->reserved2
== 5) ) {
2314 // reset each jmp entry in this section
2315 const uint32_t indirectTableOffset
= sect
->reserved1
;
2316 const uint32_t* const indirectTable
= (uint32_t*)&fLinkEditBase
[fDynamicInfo
->indirectsymoff
];
2317 uint8_t* start
= (uint8_t*)(sect
->addr
+ this->fSlide
);
2318 uint8_t* end
= start
+ sect
->size
;
2319 uintptr_t dyldHandler
= (uintptr_t)&fast_stub_binding_helper_interface
;
2320 uint32_t entryIndex
= 0;
2321 for (uint8_t* entry
= start
; entry
< end
; entry
+= 5, ++entryIndex
) {
2322 bool installLazyHandler
= true;
2323 // jump table entries that cross a (64-byte) cache line boundary have the potential to cause crashes
2324 // if the instruction is updated by one thread while being executed by another
2325 if ( ((uint32_t)entry
& 0xFFFFFFC0) != ((uint32_t)entry
+4 & 0xFFFFFFC0) ) {
2326 // need to bind this now to avoid a potential problem if bound lazily
2327 uint32_t symbolIndex
= indirectTable
[indirectTableOffset
+ entryIndex
];
2328 // the latest linker marks 64-byte crossing stubs with INDIRECT_SYMBOL_ABS so they are not used
2329 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
) {
2330 const char* symbolName
= &fStrings
[fSymbolTable
[symbolIndex
].n_un
.n_strx
];
2331 ImageLoader
* image
= NULL
;
2333 uintptr_t symbolAddr
= this->resolveUndefined(context
, &fSymbolTable
[symbolIndex
], this->usesTwoLevelNameSpace(), &image
);
2334 symbolAddr
= this->bindIndirectSymbol((uintptr_t*)entry
, sect
, symbolName
, symbolAddr
, image
, context
);
2335 ++fgTotalBindFixups
;
2336 uint32_t rel32
= symbolAddr
- (((uint32_t)entry
)+5);
2337 entry
[0] = 0xE9; // JMP rel32
2338 entry
[1] = rel32
& 0xFF;
2339 entry
[2] = (rel32
>> 8) & 0xFF;
2340 entry
[3] = (rel32
>> 16) & 0xFF;
2341 entry
[4] = (rel32
>> 24) & 0xFF;
2342 installLazyHandler
= false;
2344 catch (const char* msg
) {
2345 // ignore errors when binding symbols early
2346 // maybe the function is never called, and therefore erroring out now would be a regression
2350 if ( installLazyHandler
) {
2351 uint32_t rel32
= dyldHandler
- (((uint32_t)entry
)+5);
2352 entry
[0] = 0xE8; // CALL rel32
2353 entry
[1] = rel32
& 0xFF;
2354 entry
[2] = (rel32
>> 8) & 0xFF;
2355 entry
[3] = (rel32
>> 16) & 0xFF;
2356 entry
[4] = (rel32
>> 24) & 0xFF;
2363 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2369 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
2371 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2372 if ( this->isPrebindable()
2373 && (this->getSlide() == 0)
2374 && (this->usesTwoLevelNameSpace() || context
.prebinding
)
2375 && this->allDependentLibrariesAsWhenPreBound() ) {
2376 // allow environment variables to disable prebinding
2377 if ( context
.bindFlat
)
2379 switch ( context
.prebindUsage
) {
2380 case kUseAllPrebinding
:
2382 case kUseSplitSegPrebinding
:
2383 return this->fIsSplitSeg
;
2384 case kUseAllButAppPredbinding
:
2385 return (this != context
.mainExecutable
);
2386 case kUseNoPrebinding
:
2393 void ImageLoaderMachO::doBind(const LinkContext
& context
, BindingLaziness bindness
)
2395 // set dyld entry points in image
2396 this->setupLazyPointerHandler(context
);
2398 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2399 // note: flat-namespace binaries need to be imports rebound (even if correctly prebound)
2400 if ( this->usablePrebinding(context
) && this->usesTwoLevelNameSpace() ) {
2401 // if image has coalesced symbols, then these need to be rebound, unless this is the only image with weak symbols
2402 if ( this->needsCoalescing() && (fgCountOfImagesWithWeakExports
> 1) ) {
2403 this->doBindExternalRelocations(context
, true);
2404 this->doBindIndirectSymbolPointers(context
, kLazyAndNonLazy
, true);
2406 // skip binding because prebound and prebinding not disabled
2410 // values bound by name are stored two different ways in mach-o
2413 case kLazyAndNonLazy
:
2414 // external relocations are used for data initialized to external symbols
2415 this->doBindExternalRelocations(context
, false);
2418 case kLazyOnlyNoDependents
:
2421 // "indirect symbols" are used for code references to external symbols
2422 this->doBindIndirectSymbolPointers(context
, bindness
, false);
2427 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
2429 if ( fDashInit
!= NULL
) {
2430 Initializer func
= (Initializer
)(fDashInit
->init_address
+ fSlide
);
2431 if ( context
.verboseInit
)
2432 fprintf(stderr
, "dyld: calling -init function 0x%p in %s\n", func
, this->getPath());
2433 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2437 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
2439 if ( fModInitSection
!= NULL
) {
2440 Initializer
* inits
= (Initializer
*)(fModInitSection
->addr
+ fSlide
);
2441 const uint32_t count
= fModInitSection
->size
/ sizeof(uintptr_t);
2442 for (uint32_t i
=0; i
< count
; ++i
) {
2443 Initializer func
= inits
[i
];
2444 if ( context
.verboseInit
)
2445 fprintf(stderr
, "dyld: calling initializer function %p in %s\n", func
, this->getPath());
2446 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
);
2452 void ImageLoaderMachO::doInitialization(const LinkContext
& context
)
2454 // mach-o has -init and static initializers
2455 doImageInit(context
);
2456 doModInitFunctions(context
);
2459 bool ImageLoaderMachO::needsInitialization()
2461 return ( (fDashInit
!= NULL
) || (fModInitSection
!= NULL
) );
2465 bool ImageLoaderMachO::needsTermination()
2467 return ( fModTermSection
!= NULL
);
2470 bool ImageLoaderMachO::hasImageNotification()
2472 return ( fImageNotifySection
!= NULL
);
2476 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
2478 if ( fModTermSection
!= NULL
) {
2479 Terminator
* terms
= (Terminator
*)(fModTermSection
->addr
+ fSlide
);
2480 const uint32_t count
= fModTermSection
->size
/ sizeof(uintptr_t);
2481 for (uint32_t i
=count
; i
> 0; --i
) {
2482 Terminator func
= terms
[i
-1];
2483 if ( context
.verboseInit
)
2484 fprintf(stderr
, "dyld: calling terminaton function %p in %s\n", func
, this->getPath());
2490 void ImageLoaderMachO::doNotification(enum dyld_image_mode mode
, uint32_t infoCount
, const struct dyld_image_info info
[])
2492 if ( fImageNotifySection
!= NULL
) {
2493 dyld_image_notifier
* notes
= (dyld_image_notifier
*)(fImageNotifySection
->addr
+ fSlide
);
2494 const uint32_t count
= fImageNotifySection
->size
/ sizeof(uintptr_t);
2495 for (uint32_t i
=count
; i
> 0; --i
) {
2496 dyld_image_notifier func
= notes
[i
-1];
2497 func(mode
, infoCount
, info
);
2502 void ImageLoaderMachO::printStatistics(unsigned int imageCount
)
2504 ImageLoader::printStatistics(imageCount
);
2505 fprintf(stderr
, "total hinted binary tree searches: %d\n", fgHintedBinaryTreeSearchs
);
2506 fprintf(stderr
, "total unhinted binary tree searches: %d\n", fgUnhintedBinaryTreeSearchs
);
2507 fprintf(stderr
, "total images with weak exports: %d\n", fgCountOfImagesWithWeakExports
);
2509 #if LINKEDIT_USAGE_DEBUG
2510 fprintf(stderr
, "linkedit pages accessed (%lu):\n", sLinkEditPageBuckets
.size());
2514 void ImageLoaderMachO::doPrebinding(const LinkContext
& context
, time_t timestamp
, uint8_t* fileToPrebind
)
2516 // update __DATA segment
2517 this->applyPrebindingToDATA(fileToPrebind
);
2519 // update load commands
2520 this->applyPrebindingToLoadCommands(context
, fileToPrebind
, timestamp
);
2522 // update symbol table
2523 this->applyPrebindingToLinkEdit(context
, fileToPrebind
);
2526 void ImageLoaderMachO::applyPrebindingToDATA(uint8_t* fileToPrebind
)
2528 const unsigned int segmentCount
= fSegments
.size();
2529 for(unsigned int i
=0; i
< segmentCount
; ++i
) {
2530 SegmentMachO
* seg
= (SegmentMachO
*)fSegments
[i
];
2531 if ( seg
->writeable() ) {
2532 memcpy(&fileToPrebind
[seg
->fFileOffset
], (void*)seg
->getActualLoadAddress(), seg
->fFileSize
);
2537 void ImageLoaderMachO::applyPrebindingToLoadCommands(const LinkContext
& context
, uint8_t* fileToPrebind
, time_t timestamp
)
2539 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2540 const uint32_t cmd_count
= mh
->ncmds
;
2541 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2542 const struct load_command
* cmd
= cmds
;
2543 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2546 case LC_LOAD_WEAK_DYLIB
:
2548 // update each dylib load command with the timestamp of the target dylib
2549 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2550 const char* name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
2551 for (const DependentLibrary
* dl
=fLibraries
; dl
< &fLibraries
[fLibrariesCount
]; dl
++) {
2552 if (strcmp(dl
->name
, name
) == 0 ) {
2553 // found matching DependentLibrary for this load command
2554 if ( dl
->image
== NULL
) {
2555 // missing weak linked dylib
2556 dylib
->dylib
.timestamp
= 0;
2559 ImageLoaderMachO
* targetImage
= (ImageLoaderMachO
*)(dl
->image
); // !!! assume only mach-o images are prebound
2560 if ( ! targetImage
->isPrebindable() )
2561 throw "dependent dylib is not prebound";
2562 // if the target is currently being re-prebound then its timestamp will be the same as this one
2563 if ( ! targetImage
->usablePrebinding(context
) ) {
2564 dylib
->dylib
.timestamp
= timestamp
;
2567 // otherwise dependent library is already correctly prebound, so use its checksum
2568 dylib
->dylib
.timestamp
= targetImage
->doGetLibraryInfo().checksum
;
2578 // update the ID of this library with the new timestamp
2579 struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
2580 dylib
->dylib
.timestamp
= timestamp
;
2583 case LC_SEGMENT_COMMAND
:
2584 // if dylib was rebased, update segment commands
2585 if ( fSlide
!= 0 ) {
2586 struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2587 seg
->vmaddr
+= fSlide
;
2588 struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2589 struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2590 for (struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2591 sect
->addr
+= fSlide
;
2595 case LC_ROUTINES_COMMAND
:
2596 // if dylib was rebased, update -init command
2597 if ( fSlide
!= 0 ) {
2598 struct macho_routines_command
* routines
= (struct macho_routines_command
*)cmd
;
2599 routines
->init_address
+= fSlide
;
2603 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2607 void ImageLoaderMachO::applyPrebindingToLinkEdit(const LinkContext
& context
, uint8_t* fileToPrebind
)
2609 // In prebound images, the n_value of the symbol table entry for is the prebound address
2610 // This is needed when prebinding can't be used, to back solve for any possible addend in non-lazy pointers
2611 const char* stringPool
= NULL
;
2612 struct macho_nlist
* symbolTable
= NULL
;
2613 const struct dysymtab_command
* dysymtab
= NULL
;
2615 // get symbol table info
2616 macho_header
* mh
= (macho_header
*)fileToPrebind
;
2617 const uint32_t cmd_count
= mh
->ncmds
;
2618 const struct load_command
* const cmds
= (struct load_command
*)&fileToPrebind
[sizeof(macho_header
)];
2619 const struct load_command
* cmd
= cmds
;
2620 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2624 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
2625 stringPool
= (const char*)&fileToPrebind
[symtab
->stroff
];
2626 symbolTable
= (struct macho_nlist
*)(&fileToPrebind
[symtab
->symoff
]);
2630 dysymtab
= (struct dysymtab_command
*)cmd
;
2633 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2636 // walk all imports and re-resolve their n_value (needed incase prebinding is invalid)
2637 struct macho_nlist
* lastImport
= &symbolTable
[dysymtab
->iundefsym
+dysymtab
->nundefsym
];
2638 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iundefsym
]; entry
< lastImport
; ++entry
) {
2640 entry
->n_value
= this->resolveUndefined(context
, entry
, this->usesTwoLevelNameSpace(), &dummy
);
2643 // walk all exports and slide their n_value
2644 struct macho_nlist
* lastExport
= &symbolTable
[dysymtab
->iextdefsym
+dysymtab
->nextdefsym
];
2645 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->iextdefsym
]; entry
< lastExport
; ++entry
) {
2646 if ( (entry
->n_type
& N_TYPE
) == N_SECT
)
2647 entry
->n_value
+= fSlide
;
2650 // walk all local symbols and slide their n_value
2651 struct macho_nlist
* lastLocal
= &symbolTable
[dysymtab
->ilocalsym
+dysymtab
->nlocalsym
];
2652 for (struct macho_nlist
* entry
= &symbolTable
[dysymtab
->ilocalsym
]; entry
< lastLocal
; ++entry
) {
2653 if ( entry
->n_sect
!= NO_SECT
)
2654 entry
->n_value
+= fSlide
;
2657 // walk all local relocations and reset every PPC_RELOC_PB_LA_PTR r_value
2658 relocation_info
* const relocsStart
= (struct relocation_info
*)(&fileToPrebind
[dysymtab
->locreloff
]);
2659 relocation_info
* const relocsEnd
= &relocsStart
[dysymtab
->nlocrel
];
2660 for (relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
2661 if ( (reloc
->r_address
& R_SCATTERED
) != 0 ) {
2662 struct scattered_relocation_info
* sreloc
= (struct scattered_relocation_info
*)reloc
;
2663 if (sreloc
->r_length
== RELOC_SIZE
) {
2664 switch(sreloc
->r_type
) {
2665 #if __ppc__ || __ppc64__
2666 case PPC_RELOC_PB_LA_PTR
:
2667 #elif __i386__ || __x86_64__
2668 case GENERIC_RELOC_PB_LA_PTR
:
2670 #error unknown architecture
2672 sreloc
->r_value
+= fSlide
;
2679 // if multi-module, fix up objc_addr (10.4 and later runtime does not use this, but we want to keep file checksum consistent)
2680 if ( dysymtab
->nmodtab
!= 0 ) {
2681 dylib_module
* const modulesStart
= (struct dylib_module
*)(&fileToPrebind
[dysymtab
->modtaboff
]);
2682 dylib_module
* const modulesEnd
= &modulesStart
[dysymtab
->nmodtab
];
2683 for (dylib_module
* module=modulesStart
; module < modulesEnd
; ++module) {
2684 if ( module->objc_module_info_size
!= 0 ) {
2685 module->objc_module_info_addr
+= fSlide
;
2691 // file on disk has been reprebound, but we are still mapped to old file
2692 void ImageLoaderMachO::prebindUnmap(const LinkContext
& context
)
2694 // this removes all mappings to the old file, so the kernel will unlink (delete) it.
2695 // We need to leave the load commands and __LINKEDIT in place
2696 for (std::vector
<class Segment
*>::iterator it
=fSegments
.begin(); it
!= fSegments
.end(); ++it
) {
2697 void* segmentAddress
= (void*)((*it
)->getActualLoadAddress());
2698 uintptr_t segmentSize
= (*it
)->getSize();
2699 //fprintf(stderr, "unmapping segment %s at %p for %s\n", (*it)->getName(), segmentAddress, this->getPath());
2700 // save load commands at beginning of __TEXT segment
2701 if ( segmentAddress
== fMachOData
) {
2702 // typically load commands are one or two pages in size, so ok to alloc on stack
2703 uint32_t loadCmdSize
= sizeof(macho_header
) + ((macho_header
*)fMachOData
)->sizeofcmds
;
2704 uint32_t loadCmdPages
= (loadCmdSize
+4095) & (-4096);
2705 uint8_t loadcommands
[loadCmdPages
];
2706 memcpy(loadcommands
, fMachOData
, loadCmdPages
);
2707 // unmap whole __TEXT segment
2708 munmap((void*)(fMachOData
), segmentSize
);
2709 // allocate and copy back mach_header and load commands
2710 vm_address_t addr
= (vm_address_t
)fMachOData
;
2711 int r2
= vm_allocate(mach_task_self(), &addr
, loadCmdPages
, false /*at this address*/);
2713 fprintf(stderr
, "prebindUnmap() vm_allocate for __TEXT %d failed\n", loadCmdPages
);
2714 memcpy((void*)fMachOData
, loadcommands
, loadCmdPages
);
2715 //fprintf(stderr, "copying back load commands to %p size=%u for %s\n", segmentAddress, loadCmdPages, this->getPath());
2717 else if ( strcmp((*it
)->getName(), "__LINKEDIT") == 0 ) {
2718 uint32_t linkEditSize
= segmentSize
;
2719 uint32_t linkEditPages
= (linkEditSize
+4095) & (-4096);
2720 void* linkEditTmp
= malloc(linkEditPages
);
2721 memcpy(linkEditTmp
, segmentAddress
, linkEditPages
);
2722 // unmap whole __LINKEDIT segment
2723 munmap(segmentAddress
, segmentSize
);
2724 vm_address_t addr
= (vm_address_t
)segmentAddress
;
2725 int r2
= vm_allocate(mach_task_self(), &addr
, linkEditPages
, false /*at this address*/);
2727 fprintf(stderr
, "prebindUnmap() vm_allocate for __LINKEDIT %d failed\n", linkEditPages
);
2728 memcpy(segmentAddress
, linkEditTmp
, linkEditPages
);
2729 //fprintf(stderr, "copying back __LINKEDIT to %p size=%u for %s\n", segmentAddress, linkEditPages, this->getPath());
2733 // unmap any other segment
2734 munmap((void*)(segmentAddress
), (*it
)->getSize());
2741 SegmentMachO::SegmentMachO(const struct macho_segment_command
* cmd
, ImageLoaderMachO
* image
, const uint8_t* fileData
)
2742 : fImage(image
), fSize(cmd
->vmsize
), fFileSize(cmd
->filesize
), fFileOffset(cmd
->fileoff
), fPreferredLoadAddress(cmd
->vmaddr
),
2743 fVMProtection(cmd
->initprot
), fHasFixUps(false), fUnMapOnDestruction(false)
2745 strncpy(fName
, cmd
->segname
, 16);
2747 // scan sections for fix-up bit
2748 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)cmd
+ sizeof(struct macho_segment_command
));
2749 const struct macho_section
* const sectionsEnd
= §ionsStart
[cmd
->nsects
];
2750 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2751 if ( (sect
->flags
& (S_ATTR_EXT_RELOC
| S_ATTR_LOC_RELOC
)) != 0 )
2756 SegmentMachO::~SegmentMachO()
2758 if ( fUnMapOnDestruction
) {
2759 //fprintf(stderr, "unmapping segment %s at 0x%08lX\n", getName(), getActualLoadAddress());
2760 munmap((void*)(this->getActualLoadAddress()), this->getSize());
2764 const ImageLoader
* SegmentMachO::getImage()
2769 const char* SegmentMachO::getName()
2774 uintptr_t SegmentMachO::getSize()
2779 uintptr_t SegmentMachO::getFileSize()
2784 uintptr_t SegmentMachO::getFileOffset()
2789 bool SegmentMachO::readable()
2791 return ( (fVMProtection
& VM_PROT_READ
) != 0);
2794 bool SegmentMachO::writeable()
2796 return ((fVMProtection
& VM_PROT_WRITE
) != 0);
2799 bool SegmentMachO::executable()
2801 return ((fVMProtection
& VM_PROT_EXECUTE
) != 0);
2804 bool SegmentMachO::unaccessible()
2806 return (fVMProtection
== 0);
2809 bool SegmentMachO::hasFixUps()
2814 uintptr_t SegmentMachO::getActualLoadAddress()
2816 return fPreferredLoadAddress
+ fImage
->fSlide
;
2819 uintptr_t SegmentMachO::getPreferredLoadAddress()
2821 return fPreferredLoadAddress
;
2824 bool SegmentMachO::hasPreferredLoadAddress()
2826 return (fPreferredLoadAddress
!= 0);
2829 void SegmentMachO::setUnMapWhenDestructed(bool unmap
)
2831 fUnMapOnDestruction
= unmap
;
2834 static uint32_t *buildCRCTable(void)
2836 uint32_t *table
= new uint32_t[256];
2837 uint32_t p
= 0xedb88320UL
; // standard CRC-32 polynomial
2839 for (unsigned int i
= 0; i
< 256; i
++) {
2841 for (unsigned int j
= 0; j
< 8; j
++) {
2842 if ( c
& 1 ) c
= p
^ (c
>> 1);
2851 uint32_t SegmentMachO::crc32()
2853 if ( !readable() ) return 0;
2855 static uint32_t *crcTable
= NULL
;
2856 if ( !crcTable
) crcTable
= buildCRCTable();
2858 uint32_t crc
= ~(uint32_t)0;
2859 uint8_t *p
= (uint8_t *)getActualLoadAddress();
2860 uint8_t *end
= p
+ getSize();
2862 crc
= crcTable
[(crc
& 0xff) ^ (*p
++)] ^ (crc
>> 8);
2864 return crc
^ ~(uint32_t)0;