1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 // work around until conformance work is complete rdar://problem/4508801
30 #define __STDC_LIMIT_MACROS
34 #include <sys/types.h>
35 #include <sys/fcntl.h>
38 #include <mach/mach.h>
39 #include <mach/thread_status.h>
40 #include <mach-o/loader.h>
41 #include <mach-o/nlist.h>
42 #include <sys/sysctl.h>
43 #include <libkern/OSAtomic.h>
44 #include <libkern/OSCacheControl.h>
47 #include "ImageLoaderMachO.h"
48 #include "ImageLoaderMachOCompressed.h"
49 #include "ImageLoaderMachOClassic.h"
50 #include "mach-o/dyld_images.h"
52 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs
53 extern "C" long __stack_chk_guard
;
55 #ifndef LC_LOAD_UPWARD_DYLIB
56 #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
59 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
61 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
62 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
63 struct macho_segment_command
: public segment_command_64
{};
64 struct macho_section
: public section_64
{};
65 struct macho_routines_command
: public routines_command_64
{};
67 #define LC_SEGMENT_COMMAND LC_SEGMENT
68 #define LC_ROUTINES_COMMAND LC_ROUTINES
69 struct macho_segment_command
: public segment_command
{};
70 struct macho_section
: public section
{};
71 struct macho_routines_command
: public routines_command
{};
74 uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs
= 0;
75 uint32_t ImageLoaderMachO::fgSymbolTrieSearchs
= 0;
78 ImageLoaderMachO::ImageLoaderMachO(const macho_header
* mh
, const char* path
, unsigned int segCount
,
79 uint32_t segOffsets
[], unsigned int libCount
)
80 : ImageLoader(path
, libCount
), fMachOData((uint8_t*)mh
), fLinkEditBase(NULL
), fSlide(0),
81 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
82 fSegmentsCount(segCount
), fIsSplitSeg(false), fInSharedCache(false),
83 #if TEXT_RELOC_SUPPORT
84 fTextSegmentRebases(false),
85 fTextSegmentBinds(false),
88 fReadOnlyImportSegment(false),
90 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
91 fHasInitializers(false), fHasTerminators(false), fGoodFirstSegment(false), fRegisteredAsRequiresCoalescing(false)
93 fIsSplitSeg
= ((mh
->flags
& MH_SPLIT_SEGS
) != 0);
95 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
96 // each SegmentMachO object in array at end of ImageLoaderMachO object
97 const uint32_t cmd_count
= mh
->ncmds
;
98 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
99 const struct load_command
* cmd
= cmds
;
100 for (uint32_t i
= 0, segIndex
=0; i
< cmd_count
; ++i
) {
101 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
102 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
103 // ignore zero-sized segments
104 if ( segCmd
->vmsize
!= 0 ) {
105 // record offset of load command
106 segOffsets
[segIndex
++] = (uint8_t*)segCmd
- fMachOData
;
109 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
115 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
116 void ImageLoaderMachO::sniffLoadCommands(const macho_header
* mh
, const char* path
, bool* compressed
,
117 unsigned int* segCount
, unsigned int* libCount
,
118 const linkedit_data_command
** codeSigCmd
)
124 const uint32_t cmd_count
= mh
->ncmds
;
125 const struct load_command
* const cmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
));
126 const struct load_command
* const endCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
) + mh
->sizeofcmds
);
127 const struct load_command
* cmd
= cmds
;
128 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
131 case LC_DYLD_INFO_ONLY
:
134 case LC_SEGMENT_COMMAND
:
135 // ignore zero-sized segments
136 if ( ((struct macho_segment_command
*)cmd
)->vmsize
!= 0 )
140 case LC_LOAD_WEAK_DYLIB
:
141 case LC_REEXPORT_DYLIB
:
142 case LC_LOAD_UPWARD_DYLIB
:
145 case LC_CODE_SIGNATURE
:
146 *codeSigCmd
= (struct linkedit_data_command
*)cmd
; // only support one LC_CODE_SIGNATURE per image
149 uint32_t cmdLength
= cmd
->cmdsize
;
150 cmd
= (const struct load_command
*)(((char*)cmd
)+cmdLength
);
151 if ( cmd
> endCmds
) {
152 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
153 i
, cmdLength
, mh
->sizeofcmds
, path
);
156 // fSegmentsArrayCount is only 8-bits
157 if ( *segCount
> 255 )
158 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path
);
160 // fSegmentsArrayCount is only 8-bits
161 if ( *libCount
> 4095 )
162 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path
);
164 if ( needsAddedLibSystemDepency(*libCount
, mh
) )
170 // create image for main executable
171 ImageLoader
* ImageLoaderMachO::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
)
173 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
174 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
176 unsigned int segCount
;
177 unsigned int libCount
;
178 const linkedit_data_command
* codeSigCmd
;
179 sniffLoadCommands(mh
, path
, &compressed
, &segCount
, &libCount
, &codeSigCmd
);
180 // instantiate concrete class based on content of load commands
182 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
184 return ImageLoaderMachOClassic::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
188 // create image by mapping in a mach-o file
189 ImageLoader
* ImageLoaderMachO::instantiateFromFile(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,
190 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
193 const unsigned int dataSize
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
;
194 uint8_t buffer
[dataSize
];
195 const uint8_t* fileData
= firstPage
;
196 if ( dataSize
> 4096 ) {
197 // only read more if cmds take up more space than first page
199 memcpy(buffer
, firstPage
, 4096);
200 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096);
204 unsigned int segCount
;
205 unsigned int libCount
;
206 const linkedit_data_command
* codeSigCmd
;
207 sniffLoadCommands((const macho_header
*)fileData
, path
, &compressed
, &segCount
, &libCount
, &codeSigCmd
);
208 // instantiate concrete class based on content of load commands
210 return ImageLoaderMachOCompressed::instantiateFromFile(path
, fd
, fileData
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
);
212 return ImageLoaderMachOClassic::instantiateFromFile(path
, fd
, fileData
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
);
215 // create image by using cached mach-o file
216 ImageLoader
* ImageLoaderMachO::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, const LinkContext
& context
)
218 // instantiate right concrete class
220 unsigned int segCount
;
221 unsigned int libCount
;
222 const linkedit_data_command
* codeSigCmd
;
223 sniffLoadCommands(mh
, path
, &compressed
, &segCount
, &libCount
, &codeSigCmd
);
224 // instantiate concrete class based on content of load commands
226 return ImageLoaderMachOCompressed::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
228 return ImageLoaderMachOClassic::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
231 // create image by copying an in-memory mach-o file
232 ImageLoader
* ImageLoaderMachO::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
, const LinkContext
& context
)
235 unsigned int segCount
;
236 unsigned int libCount
;
237 const linkedit_data_command
* sigcmd
;
238 sniffLoadCommands(mh
, moduleName
, &compressed
, &segCount
, &libCount
, &sigcmd
);
239 // instantiate concrete class based on content of load commands
241 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
243 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
248 void ImageLoaderMachO::parseLoadCmds()
250 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
251 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
252 // set up pointer to __LINKEDIT segment
253 if ( strcmp(segName(i
),"__LINKEDIT") == 0 )
254 fLinkEditBase
= (uint8_t*)(segActualLoadAddress(i
) - segFileOffset(i
));
255 #if TEXT_RELOC_SUPPORT
256 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
257 if ( strcmp(segName(i
),"__TEXT") == 0 ) {
258 if ( segHasRebaseFixUps(i
) && (fSlide
!= 0) )
259 fTextSegmentRebases
= true;
260 if ( segHasBindFixUps(i
) )
261 fTextSegmentBinds
= true;
265 if ( segIsReadOnlyImport(i
) )
266 fReadOnlyImportSegment
= true;
268 // some segment always starts at beginning of file and contains mach_header and load commands
269 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
270 fMachOData
= (uint8_t*)(segActualLoadAddress(i
));
274 // keep count of prebound images with weak exports
275 if ( this->participatesInCoalescing() ) {
276 ++fgImagesRequiringCoalescing
;
277 fRegisteredAsRequiresCoalescing
= true;
278 if ( this->hasCoalescedExports() )
279 ++fgImagesHasWeakDefinitions
;
282 // keep count of images used in shared cache
283 if ( fInSharedCache
)
284 ++fgImagesUsedFromSharedCache
;
286 // walk load commands (mapped in at start of __TEXT segment)
287 const dyld_info_command
* dyldInfo
= NULL
;
288 const macho_nlist
* symbolTable
= NULL
;
289 const char* symbolTableStrings
= NULL
;
290 const dysymtab_command
* dynSymbolTable
= NULL
;
291 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
292 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
293 const struct load_command
* cmd
= cmds
;
294 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
298 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
299 symbolTableStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
300 symbolTable
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
304 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
306 case LC_SUB_UMBRELLA
:
307 fHasSubUmbrella
= true;
309 case LC_SUB_FRAMEWORK
:
313 fHasSubLibraries
= true;
315 case LC_ROUTINES_COMMAND
:
319 case LC_DYLD_INFO_ONLY
:
320 dyldInfo
= (struct dyld_info_command
*)cmd
;
322 case LC_SEGMENT_COMMAND
:
324 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
325 const bool isTextSeg
= (strcmp(seg
->segname
, "__TEXT") == 0);
326 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
327 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
328 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
329 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
330 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
331 fHasInitializers
= true;
332 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
333 fHasTerminators
= true;
334 else if ( type
== S_DTRACE_DOF
)
335 fHasDOFSections
= true;
336 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__eh_frame") == 0) )
337 fEHFrameSectionOffset
= (uint8_t*)sect
- fMachOData
;
338 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__unwind_info") == 0) )
339 fUnwindInfoSectionOffset
= (uint8_t*)sect
- fMachOData
;;
343 case LC_TWOLEVEL_HINTS
:
344 // no longer supported
348 fDylibIDOffset
= (uint8_t*)cmd
- fMachOData
;
352 case LC_LOAD_WEAK_DYLIB
:
353 case LC_REEXPORT_DYLIB
:
354 case LC_LOAD_UPWARD_DYLIB
:
355 // do nothing, just prevent LC_REQ_DYLD exception from occuring
358 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 )
359 dyld::throwf("unknown required load command 0x%08X", cmd
->cmd
);
361 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
364 if ( dyldInfo
!= NULL
)
365 this->setDyldInfo(dyldInfo
);
366 if ( symbolTable
!= NULL
)
367 this->setSymbolTableInfo(symbolTable
, symbolTableStrings
, dynSymbolTable
);
371 // don't do this work in destructor because we need object to be full subclass
372 // for UnmapSegments() to work
373 void ImageLoaderMachO::destroy()
375 // update count of images with weak exports
376 if ( fRegisteredAsRequiresCoalescing
) {
377 --fgImagesRequiringCoalescing
;
378 if ( this->hasCoalescedExports() )
379 --fgImagesHasWeakDefinitions
;
382 // keep count of images used in shared cache
383 if ( fInSharedCache
)
384 --fgImagesUsedFromSharedCache
;
386 // unmap image when done
391 unsigned int ImageLoaderMachO::segmentCount() const
393 return fSegmentsCount
;
397 const macho_segment_command
* ImageLoaderMachO::segLoadCommand(unsigned int segIndex
) const
399 uint32_t* lcOffsets
= this->segmentCommandOffsets();
400 uint32_t lcOffset
= lcOffsets
[segIndex
];
401 return (macho_segment_command
*)(&fMachOData
[lcOffset
]);
404 const char* ImageLoaderMachO::segName(unsigned int segIndex
) const
406 return segLoadCommand(segIndex
)->segname
;
410 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex
) const
412 return segLoadCommand(segIndex
)->vmsize
;
416 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex
) const
418 return segLoadCommand(segIndex
)->filesize
;
422 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex
)
424 return ( segWriteable(segIndex
) && (segSize(segIndex
) > segFileSize(segIndex
)) );
428 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex
) const
430 return segLoadCommand(segIndex
)->fileoff
;
434 bool ImageLoaderMachO::segReadable(unsigned int segIndex
) const
436 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_READ
) != 0);
440 bool ImageLoaderMachO::segWriteable(unsigned int segIndex
) const
442 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_WRITE
) != 0);
446 bool ImageLoaderMachO::segExecutable(unsigned int segIndex
) const
448 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_EXECUTE
) != 0);
452 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex
) const
454 return (segLoadCommand(segIndex
)->initprot
== 0);
457 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex
) const
459 return (segLoadCommand(segIndex
)->vmaddr
!= 0);
462 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex
) const
464 return segLoadCommand(segIndex
)->vmaddr
;
467 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex
) const
469 return segLoadCommand(segIndex
)->vmaddr
+ fSlide
;
473 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex
) const
475 return segActualLoadAddress(segIndex
) + segSize(segIndex
);
478 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex
) const
480 // scan sections for fix-up bit
481 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
482 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
483 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
484 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
485 if ( (sect
->flags
& S_ATTR_LOC_RELOC
) != 0 )
491 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex
) const
493 // scan sections for fix-up bit
494 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
495 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
496 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
497 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
498 if ( (sect
->flags
& S_ATTR_EXT_RELOC
) != 0 )
505 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex
) const
507 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
508 return ( (segCmd
->initprot
& VM_PROT_EXECUTE
)
509 && ((segCmd
->initprot
& VM_PROT_WRITE
) == 0)
510 && (strcmp(segCmd
->segname
, "__IMPORT") == 0) );
515 void ImageLoaderMachO::UnmapSegments()
517 // usually unmap image when done
518 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) {
519 // unmap TEXT segment last because it contains load command being inspected
520 unsigned int textSegmentIndex
= 0;
521 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
522 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
523 if ( strcmp(segName(i
), "__TEXT") == 0 ) {
524 textSegmentIndex
= i
;
528 --ImageLoader::fgTotalSegmentsMapped
;
529 ImageLoader::fgTotalBytesMapped
-= segSize(i
);
530 munmap((void*)segActualLoadAddress(i
), segSize(i
));
534 --ImageLoader::fgTotalSegmentsMapped
;
535 ImageLoader::fgTotalBytesMapped
-= segSize(textSegmentIndex
);
536 munmap((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
));
541 // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
542 void ImageLoaderMachO::preFetchDATA(int fd
, uint64_t offsetInFat
, const LinkContext
& context
)
544 if ( context
.linkingMainExecutable
) {
545 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
546 if ( segWriteable(i
) && (segFileSize(i
) > 0) ) {
547 // prefetch writable segment that have mmap'ed regions
549 advice
.ra_offset
= offsetInFat
+ segFileOffset(i
);
550 advice
.ra_count
= segFileSize(i
);
551 // limit prefetch to 1MB (256 pages)
552 if ( advice
.ra_count
> 1024*1024 )
553 advice
.ra_count
= 1024*1024;
554 // don't prefetch single pages, let them fault in
555 fgTotalBytesPreFetched
+= advice
.ra_count
;
556 fcntl(fd
, F_RDADVISE
, &advice
);
557 if ( context
.verboseMapping
) {
558 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n",
559 segName(i
), segActualLoadAddress(i
), segActualLoadAddress(i
)+advice
.ra_count
-1);
567 bool ImageLoaderMachO::segmentsMustSlideTogether() const
572 bool ImageLoaderMachO::segmentsCanSlide() const
574 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
577 bool ImageLoaderMachO::isBundle() const
579 const macho_header
* mh
= (macho_header
*)fMachOData
;
580 return ( mh
->filetype
== MH_BUNDLE
);
583 bool ImageLoaderMachO::isDylib() const
585 const macho_header
* mh
= (macho_header
*)fMachOData
;
586 return ( mh
->filetype
== MH_DYLIB
);
589 bool ImageLoaderMachO::isExecutable() const
591 const macho_header
* mh
= (macho_header
*)fMachOData
;
592 return ( mh
->filetype
== MH_EXECUTE
);
595 bool ImageLoaderMachO::isPositionIndependentExecutable() const
597 const macho_header
* mh
= (macho_header
*)fMachOData
;
598 return ( (mh
->filetype
== MH_EXECUTE
) && ((mh
->flags
& MH_PIE
) != 0) );
602 bool ImageLoaderMachO::forceFlat() const
604 const macho_header
* mh
= (macho_header
*)fMachOData
;
605 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
608 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
610 const macho_header
* mh
= (macho_header
*)fMachOData
;
611 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
614 bool ImageLoaderMachO::isPrebindable() const
616 const macho_header
* mh
= (macho_header
*)fMachOData
;
617 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
620 bool ImageLoaderMachO::hasCoalescedExports() const
622 const macho_header
* mh
= (macho_header
*)fMachOData
;
623 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
626 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
628 const macho_header
* mh
= (macho_header
*)fMachOData
;
629 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
632 bool ImageLoaderMachO::participatesInCoalescing() const
634 const macho_header
* mh
= (macho_header
*)fMachOData
;
635 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
636 // is reduced and it can't coalesce with other images
637 if ( this->hasHiddenExports() )
639 return ( (mh
->flags
& (MH_WEAK_DEFINES
|MH_BINDS_TO_WEAK
)) != 0 );
644 void ImageLoaderMachO::setSlide(intptr_t slide
)
649 #if CODESIGNING_SUPPORT
650 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command
* codeSigCmd
, int fd
, uint64_t offsetInFatFile
)
652 fsignatures_t siginfo
;
653 siginfo
.fs_file_start
=offsetInFatFile
; // start of mach-o slice in fat file
654 siginfo
.fs_blob_start
=(void*)(codeSigCmd
->dataoff
); // start of CD in mach-o file
655 siginfo
.fs_blob_size
=codeSigCmd
->datasize
; // size of CD
656 int result
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
);
658 dyld::log("dyld: F_ADDFILESIGS failed for %s with errno=%d\n", this->getPath(), errno
);
659 //dyld::log("dyld: registered code signature for %s\n", this->getPath());
664 const char* ImageLoaderMachO::getInstallPath() const
666 if ( fDylibIDOffset
!= 0 ) {
667 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
668 return (char*)dylibID
+ dylibID
->dylib
.name
.offset
;
673 void ImageLoaderMachO::registerInterposing()
675 // mach-o files advertise interposing by having a __DATA __interpose section
676 uintptr_t textStart
= this->segActualLoadAddress(0);
677 uintptr_t textEnd
= this->segActualEndAddress(0);
678 // <rdar://problem/8268602> verify that the first segment load command is for a read-only segment
679 if ( ! fGoodFirstSegment
)
681 struct InterposeData
{ uintptr_t replacement
; uintptr_t replacee
; };
682 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
683 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
684 const struct load_command
* cmd
= cmds
;
685 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
687 case LC_SEGMENT_COMMAND
:
689 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
690 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
691 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
692 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
693 if ( ((sect
->flags
& SECTION_TYPE
) == S_INTERPOSING
) || ((strcmp(sect
->sectname
, "__interpose") == 0) && (strcmp(seg
->segname
, "__DATA") == 0)) ) {
694 const InterposeData
* interposeArray
= (InterposeData
*)(sect
->addr
+ fSlide
);
695 const unsigned int count
= sect
->size
/ sizeof(InterposeData
);
696 for (uint32_t i
=0; i
< count
; ++i
) {
697 ImageLoader::InterposeTuple tuple
;
698 tuple
.replacement
= interposeArray
[i
].replacement
;
699 tuple
.replacementImage
= this;
700 tuple
.replacee
= interposeArray
[i
].replacee
;
701 // <rdar://problem/7937695> verify that replacement is in this image
702 if ( (tuple
.replacement
>= textStart
) && (tuple
.replacement
< textEnd
) ) {
703 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it
!= fgInterposingTuples
.end(); it
++) {
704 if ( it
->replacee
== tuple
.replacee
) {
705 tuple
.replacee
= it
->replacement
;
708 ImageLoader::fgInterposingTuples
.push_back(tuple
);
716 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
721 void* ImageLoaderMachO::getMain() const
723 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
724 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
725 const struct load_command
* cmd
= cmds
;
726 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
731 const ppc_thread_state_t
* registers
= (ppc_thread_state_t
*)(((char*)cmd
) + 16);
732 return (void*)(registers
->srr0
+ fSlide
);
734 const ppc_thread_state64_t
* registers
= (ppc_thread_state64_t
*)(((char*)cmd
) + 16);
735 return (void*)(registers
->srr0
+ fSlide
);
737 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
738 return (void*)(registers
->eip
+ fSlide
);
740 const x86_thread_state64_t
* registers
= (x86_thread_state64_t
*)(((char*)cmd
) + 16);
741 return (void*)(registers
->rip
+ fSlide
);
743 const arm_thread_state_t
* registers
= (arm_thread_state_t
*)(((char*)cmd
) + 16);
744 return (void*)(registers
->__pc
+ fSlide
);
746 #warning need processor specific code
751 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
756 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount
, const macho_header
* mh
)
758 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
762 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
763 if ( mh
->filetype
== MH_EXECUTE
)
766 bool isNonOSdylib
= false;
767 const uint32_t cmd_count
= mh
->ncmds
;
768 const struct load_command
* const cmds
= (struct load_command
*)((uint8_t*)mh
+sizeof(macho_header
));
769 const struct load_command
* cmd
= cmds
;
770 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
773 case LC_LOAD_WEAK_DYLIB
:
774 case LC_REEXPORT_DYLIB
:
775 case LC_LOAD_UPWARD_DYLIB
:
779 const dylib_command
* dylibID
= (dylib_command
*)cmd
;
780 const char* installPath
= (char*)cmd
+ dylibID
->dylib
.name
.offset
;
781 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents
782 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
783 // <rdar://problem/6497528> rosetta circular dependency spew
784 isNonOSdylib
= ( (strncmp(installPath
, "/usr/lib/", 9) != 0) && (strncmp(installPath
, "/usr/libexec/oah/Shims", 9) != 0) );
788 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
794 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[])
796 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) {
797 DependentLibraryInfo
* lib
= &libs
[0];
798 lib
->name
= "/usr/lib/libSystem.B.dylib";
799 lib
->info
.checksum
= 0;
800 lib
->info
.minVersion
= 0;
801 lib
->info
.maxVersion
= 0;
802 lib
->required
= false;
803 lib
->reExported
= false;
808 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
809 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
810 const struct load_command
* cmd
= cmds
;
811 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
814 case LC_LOAD_WEAK_DYLIB
:
815 case LC_REEXPORT_DYLIB
:
816 case LC_LOAD_UPWARD_DYLIB
:
818 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
819 DependentLibraryInfo
* lib
= &libs
[index
++];
820 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
821 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
822 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
823 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
824 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
825 lib
->required
= (cmd
->cmd
!= LC_LOAD_WEAK_DYLIB
);
826 lib
->reExported
= (cmd
->cmd
== LC_REEXPORT_DYLIB
);
827 lib
->upward
= (cmd
->cmd
== LC_LOAD_UPWARD_DYLIB
);
831 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
836 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo()
839 if ( fDylibIDOffset
!= 0 ) {
840 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
841 info
.minVersion
= dylibID
->dylib
.compatibility_version
;
842 info
.maxVersion
= dylibID
->dylib
.current_version
;
843 info
.checksum
= dylibID
->dylib
.timestamp
;
853 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const
855 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
856 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
857 const struct load_command
* cmd
= cmds
;
858 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
861 const char* pathToAdd
= NULL
;
862 const char* path
= (char*)cmd
+ ((struct rpath_command
*)cmd
)->path
.offset
;
863 if ( strncmp(path
, "@loader_path/", 13) == 0 ) {
864 if ( context
.processIsRestricted
&& (context
.mainExecutable
== this) ) {
865 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path
, this->getPath());
868 char resolvedPath
[PATH_MAX
];
869 if ( realpath(this->getPath(), resolvedPath
) != NULL
) {
870 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
871 strcpy(newRealPath
, resolvedPath
);
872 char* addPoint
= strrchr(newRealPath
,'/');
873 if ( addPoint
!= NULL
)
874 strcpy(&addPoint
[1], &path
[13]);
876 strcpy(newRealPath
, &path
[13]);
877 pathToAdd
= strdup(newRealPath
);
880 else if ( strncmp(path
, "@executable_path/", 17) == 0 ) {
881 if ( context
.processIsRestricted
) {
882 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path
, this->getPath());
885 char resolvedPath
[PATH_MAX
];
886 if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL
) {
887 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
888 strcpy(newRealPath
, resolvedPath
);
889 char* addPoint
= strrchr(newRealPath
,'/');
890 if ( addPoint
!= NULL
)
891 strcpy(&addPoint
[1], &path
[17]);
893 strcpy(newRealPath
, &path
[17]);
894 pathToAdd
= strdup(newRealPath
);
897 else if ( (path
[0] != '/') && context
.processIsRestricted
) {
898 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path
, this->getPath());
901 else if ( (path
[0] == '/') && (context
.rootPaths
!= NULL
) ) {
902 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
903 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
905 for(const char** rp
= context
.rootPaths
; *rp
!= NULL
; ++rp
) {
906 char newPath
[PATH_MAX
];
907 strcpy(newPath
, *rp
);
908 strcat(newPath
, path
);
909 struct stat stat_buf
;
910 if ( stat(newPath
, &stat_buf
) != -1 ) {
911 //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
912 pathToAdd
= strdup(newPath
);
918 // make copy so that all elements of 'paths' can be freed
919 pathToAdd
= strdup(path
);
923 // make copy so that all elements of 'paths' can be freed
924 pathToAdd
= strdup(path
);
926 if ( pathToAdd
!= NULL
)
927 paths
.push_back(pathToAdd
);
930 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
934 bool ImageLoaderMachO::getUUID(uuid_t uuid
) const
936 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
937 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
938 const struct load_command
* cmd
= cmds
;
939 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
942 uuid_command
* uc
= (uuid_command
*)cmd
;
943 memcpy(uuid
, uc
->uuid
, 16);
946 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
952 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
954 // if prebound and loaded at prebound address, then no need to rebase
955 if ( this->usablePrebinding(context
) ) {
956 // skip rebasing because prebinding is valid
957 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
961 // print why prebinding was not used
962 if ( context
.verbosePrebinding
) {
963 if ( !this->isPrebindable() ) {
964 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
966 else if ( fSlide
!= 0 ) {
967 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
969 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
970 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
972 else if ( !this->usesTwoLevelNameSpace() ){
973 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
976 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
980 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
982 #if PREBOUND_IMAGE_SUPPORT
983 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
984 // if this image is in the shared cache, do not reset, they will be bound in doBind()
985 if ( this->isPrebindable() && !fInSharedCache
)
986 this->resetPreboundLazyPointers(context
);
989 // if loaded at preferred address, no rebasing necessary
990 if ( this->fSlide
== 0 )
993 #if TEXT_RELOC_SUPPORT
994 // if there are __TEXT fixups, temporarily make __TEXT writable
995 if ( fTextSegmentRebases
)
996 this->makeTextSegmentWritable(context
, true);
999 // do actual rebasing
1000 this->rebase(context
);
1002 #if TEXT_RELOC_SUPPORT
1003 // if there were __TEXT fixups, restore write protection
1004 if ( fTextSegmentRebases
)
1005 this->makeTextSegmentWritable(context
, false);
1010 #if TEXT_RELOC_SUPPORT
1011 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext
& context
, bool writeable
)
1013 int textSegmentIndex
= 0;
1014 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1015 if ( strcmp(segName(i
), "__TEXT") == 0 ) {
1016 textSegmentIndex
= i
;
1022 segMakeWritable(textSegmentIndex
, context
);
1025 // iPhoneOS requires range to be invalidated before it is made executable
1026 sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
));
1027 segProtect(textSegmentIndex
, context
);
1032 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, bool searchReExports
, const ImageLoader
** foundIn
) const
1034 // look in this image first
1035 const ImageLoader::Symbol
* result
= this->findExportedSymbol(name
, foundIn
);
1036 if ( result
!= NULL
)
1039 if ( searchReExports
) {
1040 for(unsigned int i
=0; i
< libraryCount(); ++i
){
1041 if ( libReExported(i
) ) {
1042 ImageLoader
* image
= libImage(i
);
1043 if ( image
!= NULL
) {
1044 const Symbol
* result
= image
->findExportedSymbol(name
, searchReExports
, foundIn
);
1045 if ( result
!= NULL
)
1058 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
1059 const ImageLoader
* requestor
, bool runResolver
) const
1061 return this->getSymbolAddress(sym
, requestor
, context
, runResolver
);
1064 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol
* sym
, const ImageLoader
* requestor
,
1065 const LinkContext
& context
, bool runResolver
) const
1067 uintptr_t result
= exportedSymbolAddress(context
, sym
, runResolver
);
1068 // check for interposing overrides
1069 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it
!= fgInterposingTuples
.end(); it
++) {
1070 // replace all references to 'replacee' with 'replacement'
1071 if ( (result
== it
->replacee
) && (requestor
!= it
->replacementImage
) ) {
1072 if ( context
.verboseInterposing
) {
1073 dyld::log("dyld interposing: replace 0x%lX with 0x%lX in %s\n",
1074 it
->replacee
, it
->replacement
, this->getPath());
1076 result
= it
->replacement
;
1082 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1084 if ( exportedSymbolIsWeakDefintion(sym
) )
1085 return kWeakDefinition
;
1087 return kNoDefinitionOptions
;
1090 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1092 return exportedSymbolName(sym
);
1095 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1097 return exportedSymbolCount();
1101 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1103 return exportedSymbolIndexed(index
);
1107 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1109 return importedSymbolCount();
1113 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1115 return importedSymbolIndexed(index
);
1119 ImageLoader::ReferenceFlags
ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1121 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1126 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1128 return importedSymbolName(sym
);
1132 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1134 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1135 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1136 const struct load_command
* cmd
= cmds
;
1137 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1139 case LC_SEGMENT_COMMAND
:
1141 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1142 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1143 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1144 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1145 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1146 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1147 *length
= sect
->size
;
1154 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1161 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections
* info
)
1163 info
->mh
= this->machHeader();
1164 info
->dwarf_section
= 0;
1165 info
->dwarf_section_length
= 0;
1166 info
->compact_unwind_section
= 0;
1167 info
->compact_unwind_section_length
= 0;
1168 if ( fEHFrameSectionOffset
!= 0 ) {
1169 const macho_section
* sect
= (macho_section
*)&fMachOData
[fEHFrameSectionOffset
];
1170 info
->dwarf_section
= (void*)(sect
->addr
+ fSlide
);
1171 info
->dwarf_section_length
= sect
->size
;
1173 if ( fUnwindInfoSectionOffset
!= 0 ) {
1174 const macho_section
* sect
= (macho_section
*)&fMachOData
[fUnwindInfoSectionOffset
];
1175 info
->compact_unwind_section
= (void*)(sect
->addr
+ fSlide
);
1176 info
->compact_unwind_section_length
= sect
->size
;
1181 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1183 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1184 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1185 const struct load_command
* cmd
= cmds
;
1186 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1187 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1189 case LC_SEGMENT_COMMAND
:
1191 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1192 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1193 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1194 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1195 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1196 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1197 if ( segmentName
!= NULL
)
1198 *segmentName
= sect
->segname
;
1199 if ( sectionName
!= NULL
)
1200 *sectionName
= sect
->sectname
;
1201 if ( sectionOffset
!= NULL
)
1202 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1210 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1216 void __attribute__((noreturn
)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext
& context
, const char* symbol
,
1217 const char* referencedFrom
, const char* expectedIn
)
1219 // record values for possible use by CrashReporter or Finder
1220 (*context
.setErrorStrings
)(dyld_error_kind_symbol_missing
, referencedFrom
, expectedIn
, symbol
);
1221 dyld::throwf("Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n", symbol
, referencedFrom
, expectedIn
);
1224 const mach_header
* ImageLoaderMachO::machHeader() const
1226 return (mach_header
*)fMachOData
;
1229 uintptr_t ImageLoaderMachO::getSlide() const
1234 // hmm. maybe this should be up in ImageLoader??
1235 const void* ImageLoaderMachO::getEnd() const
1237 uintptr_t lastAddress
= 0;
1238 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1239 uintptr_t segEnd
= segActualEndAddress(i
);
1240 if ( strcmp(segName(i
), "__UNIXSTACK") != 0 ) {
1241 if ( segEnd
> lastAddress
)
1242 lastAddress
= segEnd
;
1245 return (const void*)lastAddress
;
1249 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext
& context
, uintptr_t location
, uintptr_t value
,
1250 const ImageLoader
* targetImage
, uint8_t type
, const char* symbolName
,
1251 intptr_t addend
, const char* msg
)
1254 if ( context
.verboseBind
) {
1256 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1257 msg
, this->getShortName(), (uintptr_t)location
,
1258 ((targetImage
!= NULL
) ? targetImage
->getShortName() : "<weak_import-missing>"),
1259 symbolName
, (uintptr_t)location
, value
, addend
);
1261 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1262 msg
, this->getShortName(), (uintptr_t)location
,
1263 ((targetImage
!= NULL
) ? targetImage
->getShortName() : "<weak>import-missing>"),
1264 symbolName
, (uintptr_t)location
, value
);
1267 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
1271 uintptr_t* locationToFix
= (uintptr_t*)location
;
1273 uintptr_t newValue
= value
+addend
;
1276 case BIND_TYPE_POINTER
:
1277 // test first so we don't needless dirty pages
1278 if ( *locationToFix
!= newValue
)
1279 *locationToFix
= newValue
;
1281 case BIND_TYPE_TEXT_ABSOLUTE32
:
1282 loc32
= (uint32_t*)locationToFix
;
1283 value32
= (uint32_t)newValue
;
1284 if ( *loc32
!= value32
)
1287 case BIND_TYPE_TEXT_PCREL32
:
1288 loc32
= (uint32_t*)locationToFix
;
1289 value32
= (uint32_t)newValue
- (((uintptr_t)locationToFix
) + 4);
1290 if ( *loc32
!= value32
)
1294 dyld::throwf("bad bind type %d", type
);
1297 // update statistics
1298 ++fgTotalBindFixups
;
1307 #if SUPPORT_OLD_CRT_INITIALIZATION
1308 // first 16 bytes of "start" in crt1.o
1310 static uint32_t sStandardEntryPointInstructions
[4] = { 0x7c3a0b78, 0x3821fffc, 0x54210034, 0x38000000 };
1312 static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
1317 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
1318 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
1319 // the following only exist in main executables built for 10.5 or later
1323 // These are defined in dyldStartup.s
1324 extern "C" void stub_binding_helper();
1325 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
);
1328 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
1330 const macho_header
* mh
= (macho_header
*)fMachOData
;
1331 const uint32_t cmd_count
= mh
->ncmds
;
1332 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1333 const struct load_command
* cmd
;
1334 // set up __dyld section
1336 // 1) do nothing if image is in dyld shared cache and dyld loaded at same address as when cache built
1337 // 2) first read __dyld value, if already correct don't write, this prevents dirtying a page
1338 if ( !fInSharedCache
|| !context
.dyldLoadedAtSameAddressNeededBySharedCache
) {
1340 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1341 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1342 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1343 if ( strcmp(seg
->segname
, "__DATA") == 0 ) {
1344 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1345 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1346 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1347 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) {
1348 struct DATAdyld
* dd
= (struct DATAdyld
*)(sect
->addr
+ fSlide
);
1349 if ( sect
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
1350 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
1351 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
1353 if ( sect
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
1354 if ( dd
->dyldFuncLookup
!= (void*)&dyld_func_lookup
)
1355 dd
->dyldFuncLookup
= (void*)&dyld_func_lookup
;
1357 if ( mh
->filetype
== MH_EXECUTE
) {
1358 // there are two ways to get the program variables
1359 if ( (sect
->size
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh
== mh
) ) {
1360 // some really old binaries have space for vars, but it is zero filled
1361 // main executable has 10.5 style __dyld section that has program variable pointers
1362 context
.setNewProgramVars(dd
->vars
);
1365 // main executable is pre-10.5 and requires the symbols names to be looked up
1366 this->lookupProgramVars(context
);
1367 #if SUPPORT_OLD_CRT_INITIALIZATION
1368 // If the first 16 bytes of the entry point's instructions do not
1369 // match what crt1.o supplies, then the program has a custom entry point.
1370 // This means it might be doing something that needs to be executed before
1371 // initializers are run.
1372 if ( memcmp(this->getMain(), sStandardEntryPointInstructions
, 16) != 0 ) {
1373 if ( context
.verboseInit
)
1374 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
1375 context
.setRunInitialzersOldWay();
1381 else if ( (strcmp(sect
->sectname
, "__program_vars" ) == 0) && (mh
->filetype
== MH_EXECUTE
) ) {
1382 // this is a Mac OS X 10.6 or later main executable
1383 struct ProgramVars
* pv
= (struct ProgramVars
*)(sect
->addr
+ fSlide
);
1384 context
.setNewProgramVars(*pv
);
1389 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1395 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const
1397 ProgramVars vars
= context
.programVars
;
1398 const ImageLoader::Symbol
* sym
;
1400 // get mach header directly
1401 vars
.mh
= (macho_header
*)fMachOData
;
1404 sym
= this->findExportedSymbol("_NXArgc", false, NULL
);
1406 vars
.NXArgcPtr
= (int*)this->getExportedSymbolAddress(sym
, context
, this, false);
1409 sym
= this->findExportedSymbol("_NXArgv", false, NULL
);
1411 vars
.NXArgvPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false);
1414 sym
= this->findExportedSymbol("_environ", false, NULL
);
1416 vars
.environPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false);
1418 // lookup __progname
1419 sym
= this->findExportedSymbol("___progname", false, NULL
);
1421 vars
.__prognamePtr
= (const char**)this->getExportedSymbolAddress(sym
, context
, this, false);
1423 context
.setNewProgramVars(vars
);
1427 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
1429 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
1430 if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache
)
1431 && this->usesTwoLevelNameSpace()
1432 && this->allDependentLibrariesAsWhenPreBound() ) {
1433 // allow environment variables to disable prebinding
1434 if ( context
.bindFlat
)
1436 switch ( context
.prebindUsage
) {
1437 case kUseAllPrebinding
:
1439 case kUseSplitSegPrebinding
:
1440 return this->fIsSplitSeg
;
1441 case kUseAllButAppPredbinding
:
1442 return (this != context
.mainExecutable
);
1443 case kUseNoPrebinding
:
1451 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
1453 if ( fHasDashInit
) {
1454 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1455 // <rdar://problem/8543820> verify initializers are in first segment for dylibs
1456 if ( this->isDylib() && !fGoodFirstSegment
) {
1457 if ( context
.verboseInit
)
1458 dyld::log("dyld: ignoring -init in %s\n", this->getPath());
1461 uintptr_t textStart
= this->segActualLoadAddress(0);
1462 uintptr_t textEnd
= this->segActualEndAddress(0);
1464 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1465 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1466 const struct load_command
* cmd
= cmds
;
1467 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1469 case LC_ROUTINES_COMMAND
:
1470 Initializer func
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address
+ fSlide
);
1471 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1472 // <rdar://problem/8543820> verify initializers are in first segment for dylibs
1473 if ( this->isDylib() && (((uintptr_t)func
>= textEnd
) || ((uintptr_t)func
< textStart
)) ) {
1474 if ( context
.verboseInit
)
1475 dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func
, this->getPath());
1479 if ( context
.verboseInit
)
1480 dyld::log("dyld: calling -init function 0x%p in %s\n", func
, this->getPath());
1481 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
1482 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1487 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1492 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
1494 if ( fHasInitializers
) {
1495 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1496 // <rdar://problem/8543820> verify initializers are in first segment for dylibs
1497 if ( this->isDylib() && !fGoodFirstSegment
) {
1498 if ( context
.verboseInit
)
1499 dyld::log("dyld: ignoring all initializers in %s\n", this->getPath());
1502 uintptr_t textStart
= this->segActualLoadAddress(0);
1503 uintptr_t textEnd
= this->segActualEndAddress(0);
1505 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1506 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1507 const struct load_command
* cmd
= cmds
;
1508 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1509 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1510 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1511 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1512 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1513 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1514 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1515 if ( type
== S_MOD_INIT_FUNC_POINTERS
) {
1516 Initializer
* inits
= (Initializer
*)(sect
->addr
+ fSlide
);
1517 const uint32_t count
= sect
->size
/ sizeof(uintptr_t);
1518 for (uint32_t i
=0; i
< count
; ++i
) {
1519 Initializer func
= inits
[i
];
1520 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1521 // <rdar://problem/8543820> verify initializers are in first segment for dylibs
1522 if ( this->isDylib() && (((uintptr_t)func
>= textEnd
) || ((uintptr_t)func
< textStart
)) ) {
1523 if ( context
.verboseInit
)
1524 dyld::log("dyld: ignoring out of bounds initializer function %p in %s\n", func
, this->getPath());
1528 if ( context
.verboseInit
)
1529 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath());
1530 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
1531 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1538 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1548 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
)
1550 if ( fHasDOFSections
) {
1551 // walk load commands (mapped in at start of __TEXT segment)
1552 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1553 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1554 const struct load_command
* cmd
= cmds
;
1555 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1557 case LC_SEGMENT_COMMAND
:
1559 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1560 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1561 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1562 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1563 if ( (sect
->flags
& SECTION_TYPE
) == S_DTRACE_DOF
) {
1564 ImageLoader::DOFInfo info
;
1565 info
.dof
= (void*)(sect
->addr
+ fSlide
);
1566 info
.imageHeader
= this->machHeader();
1567 info
.imageShortName
= this->getShortName();
1568 dofs
.push_back(info
);
1574 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1580 bool ImageLoaderMachO::doInitialization(const LinkContext
& context
)
1582 CRSetCrashLogMessage2(this->getPath());
1584 // mach-o has -init and static initializers
1585 doImageInit(context
);
1586 doModInitFunctions(context
);
1588 CRSetCrashLogMessage2(NULL
);
1590 return (fHasDashInit
|| fHasInitializers
);
1593 bool ImageLoaderMachO::needsInitialization()
1595 return ( fHasDashInit
|| fHasInitializers
);
1599 bool ImageLoaderMachO::needsTermination()
1601 return fHasTerminators
;
1605 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
1607 if ( fHasTerminators
) {
1608 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1609 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1610 const struct load_command
* cmd
= cmds
;
1611 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1612 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1613 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1614 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1615 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1616 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1617 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1618 if ( type
== S_MOD_TERM_FUNC_POINTERS
) {
1619 Terminator
* terms
= (Terminator
*)(sect
->addr
+ fSlide
);
1620 const uint32_t count
= sect
->size
/ sizeof(uintptr_t);
1621 for (uint32_t i
=count
; i
> 0; --i
) {
1622 Terminator func
= terms
[i
-1];
1623 if ( context
.verboseInit
)
1624 dyld::log("dyld: calling termination function %p in %s\n", func
, this->getPath());
1630 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1636 void ImageLoaderMachO::printStatistics(unsigned int imageCount
, const InitializerTimingList
& timingInfo
)
1638 ImageLoader::printStatistics(imageCount
, timingInfo
);
1639 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs
);
1640 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs
);
1641 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions
);
1642 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing
);
1646 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext
& context
)
1648 // preflight and calculate slide if needed
1649 const bool inPIE
= (fgNextPIEDylibAddress
!= 0);
1651 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
1652 bool needsToSlide
= false;
1653 bool imageHasPreferredLoadAddress
= segHasPreferredLoadAddress(0);
1654 uintptr_t lowAddr
= (unsigned long)(-1);
1655 uintptr_t highAddr
= 0;
1656 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1657 const uintptr_t segLow
= segPreferredLoadAddress(i
);
1658 const uintptr_t segHigh
= (segLow
+ segSize(i
) + 4095) & -4096;
1659 if ( segLow
< lowAddr
)
1661 if ( segHigh
> highAddr
)
1664 if ( needsToSlide
|| !imageHasPreferredLoadAddress
|| inPIE
|| !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
1665 needsToSlide
= true;
1667 if ( needsToSlide
) {
1668 // find a chunk of address space to hold all segments
1669 uintptr_t addr
= reserveAnAddressRange(highAddr
-lowAddr
, context
);
1670 slide
= addr
- lowAddr
;
1673 else if ( ! this->segmentsCanSlide() ) {
1674 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1675 if ( strcmp(segName(i
), "__PAGEZERO") == 0 )
1677 if ( !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
1678 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i
), segPreferredLoadAddress(i
), segSize(i
));
1682 throw "mach-o does not support independently sliding segments";
1688 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
)
1690 vm_address_t addr
= 0;
1691 vm_size_t size
= length
;
1692 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
1693 if ( fgNextPIEDylibAddress
!= 0 ) {
1694 // add small (0-3 pages) random padding between dylibs
1695 addr
= fgNextPIEDylibAddress
+ (__stack_chk_guard
/fgNextPIEDylibAddress
& (sizeof(long)-1))*4096;
1696 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
1697 kern_return_t r
= vm_allocate(mach_task_self(), &addr
, size
, VM_FLAGS_FIXED
);
1698 if ( r
== KERN_SUCCESS
) {
1699 fgNextPIEDylibAddress
= addr
+ size
;
1702 fgNextPIEDylibAddress
= 0;
1704 kern_return_t r
= vm_allocate(mach_task_self(), &addr
, size
, VM_FLAGS_ANYWHERE
);
1705 if ( r
!= KERN_SUCCESS
)
1706 throw "out of address space";
1711 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start
, size_t length
)
1713 vm_address_t addr
= start
;
1714 vm_size_t size
= length
;
1715 kern_return_t r
= vm_allocate(mach_task_self(), &addr
, size
, false /*only this range*/);
1716 if ( r
!= KERN_SUCCESS
)
1723 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
1725 // find address range for image
1726 intptr_t slide
= this->assignSegmentAddresses(context
);
1727 if ( context
.verboseMapping
)
1728 dyld::log("dyld: Mapping %s\n", this->getPath());
1729 // <rdar://problem/8268602> verify that the first segment load command is for a r-x segment
1730 // that starts at begining of file and is larger than all load commands
1731 uintptr_t firstSegMappedStart
= segPreferredLoadAddress(0) + slide
;
1732 uintptr_t firstSegMappedEnd
= firstSegMappedStart
+ this->segSize(0);
1733 if ( (this->segLoadCommand(0)->initprot
== (VM_PROT_EXECUTE
|VM_PROT_READ
))
1734 && (this->segFileOffset(0) == 0)
1735 && (this->segFileSize(0) != 0)
1736 && (this->segSize(0) > ((macho_header
*)fMachOData
)->sizeofcmds
) ) {
1737 fGoodFirstSegment
= true;
1739 // map in all segments
1740 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1741 vm_offset_t fileOffset
= segFileOffset(i
) + offsetInFat
;
1742 vm_size_t size
= segFileSize(i
);
1743 uintptr_t requestedLoadAddress
= segPreferredLoadAddress(i
) + slide
;
1744 // <rdar://problem/8268602> verify other segments map after first
1745 if ( (i
!= 0) && (requestedLoadAddress
< firstSegMappedEnd
) )
1746 fGoodFirstSegment
= false;
1748 if ( !segUnaccessible(i
) ) {
1749 // If has text-relocs, don't set x-bit initially.
1750 // Instead set it later after text-relocs have been done.
1751 // The iPhone OS does not like it when you make executable code writable.
1752 if ( segExecutable(i
) && !(segHasRebaseFixUps(i
) && (slide
!= 0)) )
1753 protection
|= PROT_EXEC
;
1754 if ( segReadable(i
) )
1755 protection
|= PROT_READ
;
1756 if ( segWriteable(i
) )
1757 protection
|= PROT_WRITE
;
1760 // initially map __IMPORT segments R/W so dyld can update them
1761 if ( segIsReadOnlyImport(i
) )
1762 protection
|= PROT_WRITE
;
1764 // wholly zero-fill segments have nothing to mmap() in
1766 if ( (fileOffset
+size
) > fileLen
) {
1767 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
1768 segName(i
), (uint64_t)(fileOffset
+size
), fileLen
);
1770 void* loadAddress
= mmap((void*)requestedLoadAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, fileOffset
);
1771 if ( loadAddress
== ((void*)(-1)) ) {
1772 dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
1773 errno
, requestedLoadAddress
, (uintptr_t)size
, segName(i
), getPath());
1777 ++ImageLoader::fgTotalSegmentsMapped
;
1778 ImageLoader::fgTotalBytesMapped
+= size
;
1779 if ( context
.verboseMapping
)
1780 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i
), requestedLoadAddress
, requestedLoadAddress
+size
-1,
1781 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
1784 // update slide to reflect load location
1785 this->setSlide(slide
);
1788 void ImageLoaderMachO::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
)
1790 // find address range for image
1791 intptr_t slide
= this->assignSegmentAddresses(context
);
1792 if ( context
.verboseMapping
)
1793 dyld::log("dyld: Mapping memory %p\n", memoryImage
);
1794 // map in all segments
1795 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1796 vm_address_t loadAddress
= segPreferredLoadAddress(i
) + slide
;
1797 vm_address_t srcAddr
= (uintptr_t)memoryImage
+ segFileOffset(i
);
1798 vm_size_t size
= segFileSize(i
);
1799 kern_return_t r
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
);
1800 if ( r
!= KERN_SUCCESS
)
1801 throw "can't map segment";
1802 if ( context
.verboseMapping
)
1803 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i
), (uintptr_t)loadAddress
, (uintptr_t)loadAddress
+size
-1);
1805 // update slide to reflect load location
1806 this->setSlide(slide
);
1807 // set R/W permissions on all segments at slide location
1808 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1809 segProtect(i
, context
);
1814 void ImageLoaderMachO::segProtect(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
1816 vm_prot_t protection
= 0;
1817 if ( !segUnaccessible(segIndex
) ) {
1818 if ( segExecutable(segIndex
) )
1819 protection
|= PROT_EXEC
;
1820 if ( segReadable(segIndex
) )
1821 protection
|= PROT_READ
;
1822 if ( segWriteable(segIndex
) )
1823 protection
|= PROT_WRITE
;
1825 vm_address_t addr
= segActualLoadAddress(segIndex
);
1826 vm_size_t size
= segSize(segIndex
);
1827 const bool setCurrentPermissions
= false;
1828 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
1829 if ( r
!= KERN_SUCCESS
) {
1830 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
1831 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
1833 if ( context
.verboseMapping
) {
1834 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex
), (uintptr_t)addr
, (uintptr_t)addr
+size
-1,
1835 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
1839 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
1841 vm_address_t addr
= segActualLoadAddress(segIndex
);
1842 vm_size_t size
= segSize(segIndex
);
1843 const bool setCurrentPermissions
= false;
1844 vm_prot_t protection
= VM_PROT_WRITE
| VM_PROT_READ
;
1845 if ( segExecutable(segIndex
) && !segHasRebaseFixUps(segIndex
) )
1846 protection
|= VM_PROT_EXECUTE
;
1847 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
1848 if ( r
!= KERN_SUCCESS
) {
1849 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
1850 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
1852 if ( context
.verboseMapping
) {
1853 dyld::log("%18s at 0x%08lX->0x%08lX altered permissions to %c%c%c\n", segName(segIndex
), (uintptr_t)addr
, (uintptr_t)addr
+size
-1,
1854 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );