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 <sys/syscall.h>
44 #include <libkern/OSAtomic.h>
45 #include <libkern/OSCacheControl.h>
47 #include <System/sys/codesign.h>
49 #include "ImageLoaderMachO.h"
50 #include "ImageLoaderMachOCompressed.h"
51 #if SUPPORT_CLASSIC_MACHO
52 #include "ImageLoaderMachOClassic.h"
54 #include "mach-o/dyld_images.h"
56 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs
57 extern "C" long __stack_chk_guard
;
59 #ifndef LC_LOAD_UPWARD_DYLIB
60 #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
63 // 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 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
68 struct macho_segment_command
: public segment_command_64
{};
69 struct macho_section
: public section_64
{};
70 struct macho_routines_command
: public routines_command_64
{};
72 #define LC_SEGMENT_COMMAND LC_SEGMENT
73 #define LC_ROUTINES_COMMAND LC_ROUTINES
74 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
75 struct macho_segment_command
: public segment_command
{};
76 struct macho_section
: public section
{};
77 struct macho_routines_command
: public routines_command
{};
80 uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs
= 0;
81 uint32_t ImageLoaderMachO::fgSymbolTrieSearchs
= 0;
84 ImageLoaderMachO::ImageLoaderMachO(const macho_header
* mh
, const char* path
, unsigned int segCount
,
85 uint32_t segOffsets
[], unsigned int libCount
)
86 : ImageLoader(path
, libCount
), fMachOData((uint8_t*)mh
), fLinkEditBase(NULL
), fSlide(0),
87 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
88 fSegmentsCount(segCount
), fIsSplitSeg(false), fInSharedCache(false),
89 #if TEXT_RELOC_SUPPORT
90 fTextSegmentRebases(false),
91 fTextSegmentBinds(false),
94 fReadOnlyImportSegment(false),
96 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
97 fHasInitializers(false), fHasTerminators(false), fRegisteredAsRequiresCoalescing(false)
99 fIsSplitSeg
= ((mh
->flags
& MH_SPLIT_SEGS
) != 0);
101 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
102 // each SegmentMachO object in array at end of ImageLoaderMachO object
103 const uint32_t cmd_count
= mh
->ncmds
;
104 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
105 const struct load_command
* cmd
= cmds
;
106 for (uint32_t i
= 0, segIndex
=0; i
< cmd_count
; ++i
) {
107 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
108 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
109 // ignore zero-sized segments
110 if ( segCmd
->vmsize
!= 0 ) {
111 // record offset of load command
112 segOffsets
[segIndex
++] = (uint8_t*)segCmd
- fMachOData
;
115 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
121 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
122 void ImageLoaderMachO::sniffLoadCommands(const macho_header
* mh
, const char* path
, bool* compressed
,
123 unsigned int* segCount
, unsigned int* libCount
, const LinkContext
& context
,
124 const linkedit_data_command
** codeSigCmd
)
130 struct macho_segment_command
* segCmd
;
131 bool foundLoadCommandSegment
= false;
132 uint32_t loadCommandSegmentIndex
= 0xFFFFFFFF;
133 uintptr_t loadCommandSegmentVMStart
= 0;
134 uintptr_t loadCommandSegmentVMEnd
= 0;
136 const uint32_t cmd_count
= mh
->ncmds
;
137 const struct load_command
* const startCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
));
138 const struct load_command
* const endCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
) + mh
->sizeofcmds
);
139 const struct load_command
* cmd
= startCmds
;
140 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
143 case LC_DYLD_INFO_ONLY
:
146 case LC_SEGMENT_COMMAND
:
147 segCmd
= (struct macho_segment_command
*)cmd
;
148 // ignore zero-sized segments
149 if ( segCmd
->vmsize
!= 0 )
151 // <rdar://problem/7942521> all load commands must be in an executable segment
152 if ( context
.codeSigningEnforced
&& (segCmd
->fileoff
< mh
->sizeofcmds
) && (segCmd
->filesize
!= 0) ) {
153 if ( (segCmd
->fileoff
!= 0) || (segCmd
->filesize
< (mh
->sizeofcmds
+sizeof(macho_header
))) )
154 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd
->segname
);
155 if ( segCmd
->initprot
!= (VM_PROT_READ
| VM_PROT_EXECUTE
) )
156 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd
->segname
);
157 if ( foundLoadCommandSegment
)
158 throw "load commands in multiple segments";
159 foundLoadCommandSegment
= true;
160 loadCommandSegmentIndex
= i
;
161 loadCommandSegmentVMStart
= segCmd
->vmaddr
;
162 loadCommandSegmentVMEnd
= segCmd
->vmaddr
+ segCmd
->vmsize
;
165 case LC_SEGMENT_COMMAND_WRONG
:
166 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
169 case LC_LOAD_WEAK_DYLIB
:
170 case LC_REEXPORT_DYLIB
:
171 case LC_LOAD_UPWARD_DYLIB
:
174 case LC_CODE_SIGNATURE
:
175 *codeSigCmd
= (struct linkedit_data_command
*)cmd
; // only support one LC_CODE_SIGNATURE per image
178 uint32_t cmdLength
= cmd
->cmdsize
;
179 cmd
= (const struct load_command
*)(((char*)cmd
)+cmdLength
);
180 if ( (cmd
> endCmds
) || (cmd
< startCmds
) ) {
181 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
182 i
, cmdLength
, mh
->sizeofcmds
, path
);
186 if ( context
.codeSigningEnforced
&& !foundLoadCommandSegment
)
187 throw "load commands not in a segment";
188 // <rdar://problem/13145644> verify another segment does not over-map load commands
190 if ( context
.codeSigningEnforced
) {
191 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
193 case LC_SEGMENT_COMMAND
:
194 if ( i
!= loadCommandSegmentIndex
) {
195 segCmd
= (struct macho_segment_command
*)cmd
;
196 uintptr_t start
= segCmd
->vmaddr
;
197 uintptr_t end
= segCmd
->vmaddr
+ segCmd
->vmsize
;
198 if ( ((start
<= loadCommandSegmentVMStart
) && (end
> loadCommandSegmentVMStart
))
199 || ((start
>= loadCommandSegmentVMStart
) && (start
< loadCommandSegmentVMEnd
)) )
200 dyld::throwf("malformed mach-o image: segment %s overlaps load commands", segCmd
->segname
);
204 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
208 // fSegmentsArrayCount is only 8-bits
209 if ( *segCount
> 255 )
210 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path
);
212 // fSegmentsArrayCount is only 8-bits
213 if ( *libCount
> 4095 )
214 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path
);
216 if ( needsAddedLibSystemDepency(*libCount
, mh
) )
222 // create image for main executable
223 ImageLoader
* ImageLoaderMachO::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
)
225 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
226 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
228 unsigned int segCount
;
229 unsigned int libCount
;
230 const linkedit_data_command
* codeSigCmd
;
231 sniffLoadCommands(mh
, path
, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
);
232 // instantiate concrete class based on content of load commands
234 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
236 #if SUPPORT_CLASSIC_MACHO
237 return ImageLoaderMachOClassic::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
239 throw "missing LC_DYLD_INFO load command";
244 // create image by mapping in a mach-o file
245 ImageLoader
* ImageLoaderMachO::instantiateFromFile(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,
246 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
249 const unsigned int dataSize
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
;
250 uint8_t buffer
[dataSize
];
251 const uint8_t* fileData
= firstPage
;
252 if ( dataSize
> 4096 ) {
253 // only read more if cmds take up more space than first page
255 memcpy(buffer
, firstPage
, 4096);
256 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096);
260 unsigned int segCount
;
261 unsigned int libCount
;
262 const linkedit_data_command
* codeSigCmd
;
263 sniffLoadCommands((const macho_header
*)fileData
, path
, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
);
264 // instantiate concrete class based on content of load commands
266 return ImageLoaderMachOCompressed::instantiateFromFile(path
, fd
, fileData
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
);
268 #if SUPPORT_CLASSIC_MACHO
269 return ImageLoaderMachOClassic::instantiateFromFile(path
, fd
, fileData
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
);
271 throw "missing LC_DYLD_INFO load command";
275 // create image by using cached mach-o file
276 ImageLoader
* ImageLoaderMachO::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, const LinkContext
& context
)
278 // instantiate right concrete class
280 unsigned int segCount
;
281 unsigned int libCount
;
282 const linkedit_data_command
* codeSigCmd
;
283 sniffLoadCommands(mh
, path
, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
);
284 // instantiate concrete class based on content of load commands
286 return ImageLoaderMachOCompressed::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
288 #if SUPPORT_CLASSIC_MACHO
289 return ImageLoaderMachOClassic::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
291 throw "missing LC_DYLD_INFO load command";
295 // create image by copying an in-memory mach-o file
296 ImageLoader
* ImageLoaderMachO::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
, const LinkContext
& context
)
299 unsigned int segCount
;
300 unsigned int libCount
;
301 const linkedit_data_command
* sigcmd
;
302 sniffLoadCommands(mh
, moduleName
, &compressed
, &segCount
, &libCount
, context
, &sigcmd
);
303 // instantiate concrete class based on content of load commands
305 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
307 #if SUPPORT_CLASSIC_MACHO
308 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
310 throw "missing LC_DYLD_INFO load command";
315 int ImageLoaderMachO::crashIfInvalidCodeSignature()
317 // Now that segments are mapped in, try reading from first executable segment.
318 // If code signing is enabled the kernel will validate the code signature
319 // when paging in, and kill the process if invalid.
320 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
321 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
322 // return read value to ensure compiler does not optimize away load
323 int* p
= (int*)segActualLoadAddress(i
);
331 void ImageLoaderMachO::parseLoadCmds()
333 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
334 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
335 // set up pointer to __LINKEDIT segment
336 if ( strcmp(segName(i
),"__LINKEDIT") == 0 )
337 fLinkEditBase
= (uint8_t*)(segActualLoadAddress(i
) - segFileOffset(i
));
338 #if TEXT_RELOC_SUPPORT
339 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
340 if ( strcmp(segName(i
),"__TEXT") == 0 ) {
341 if ( segHasRebaseFixUps(i
) && (fSlide
!= 0) )
342 fTextSegmentRebases
= true;
343 if ( segHasBindFixUps(i
) )
344 fTextSegmentBinds
= true;
348 if ( segIsReadOnlyImport(i
) )
349 fReadOnlyImportSegment
= true;
351 // some segment always starts at beginning of file and contains mach_header and load commands
352 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
353 fMachOData
= (uint8_t*)(segActualLoadAddress(i
));
357 // keep count of prebound images with weak exports
358 if ( this->participatesInCoalescing() ) {
359 ++fgImagesRequiringCoalescing
;
360 fRegisteredAsRequiresCoalescing
= true;
361 if ( this->hasCoalescedExports() )
362 ++fgImagesHasWeakDefinitions
;
365 // keep count of images used in shared cache
366 if ( fInSharedCache
)
367 ++fgImagesUsedFromSharedCache
;
369 // walk load commands (mapped in at start of __TEXT segment)
370 const dyld_info_command
* dyldInfo
= NULL
;
371 const macho_nlist
* symbolTable
= NULL
;
372 const char* symbolTableStrings
= NULL
;
373 const struct load_command
* firstUnknownCmd
= NULL
;
374 const struct version_min_command
* minOSVersionCmd
= NULL
;
375 const dysymtab_command
* dynSymbolTable
= NULL
;
376 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
377 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
378 const struct load_command
* cmd
= cmds
;
379 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
383 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
384 symbolTableStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
385 symbolTable
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
389 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
391 case LC_SUB_UMBRELLA
:
392 fHasSubUmbrella
= true;
394 case LC_SUB_FRAMEWORK
:
398 fHasSubLibraries
= true;
400 case LC_ROUTINES_COMMAND
:
404 case LC_DYLD_INFO_ONLY
:
405 dyldInfo
= (struct dyld_info_command
*)cmd
;
407 case LC_SEGMENT_COMMAND
:
409 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
410 const bool isTextSeg
= (strcmp(seg
->segname
, "__TEXT") == 0);
411 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
412 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
413 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
414 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
415 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
416 fHasInitializers
= true;
417 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
418 fHasTerminators
= true;
419 else if ( type
== S_DTRACE_DOF
)
420 fHasDOFSections
= true;
421 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__eh_frame") == 0) )
422 fEHFrameSectionOffset
= (uint8_t*)sect
- fMachOData
;
423 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__unwind_info") == 0) )
424 fUnwindInfoSectionOffset
= (uint8_t*)sect
- fMachOData
;;
428 case LC_TWOLEVEL_HINTS
:
429 // no longer supported
433 fDylibIDOffset
= (uint8_t*)cmd
- fMachOData
;
437 case LC_LOAD_WEAK_DYLIB
:
438 case LC_REEXPORT_DYLIB
:
439 case LC_LOAD_UPWARD_DYLIB
:
441 // do nothing, just prevent LC_REQ_DYLD exception from occuring
443 case LC_VERSION_MIN_MACOSX
:
444 case LC_VERSION_MIN_IPHONEOS
:
445 minOSVersionCmd
= (version_min_command
*)cmd
;
448 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 ) {
449 if ( firstUnknownCmd
== NULL
)
450 firstUnknownCmd
= cmd
;
454 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
456 if ( firstUnknownCmd
!= NULL
) {
457 if ( minOSVersionCmd
!= NULL
) {
458 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",
459 this->getShortName(),
460 minOSVersionCmd
->version
>> 16, ((minOSVersionCmd
->version
>> 8) & 0xff),
461 firstUnknownCmd
->cmd
);
464 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd
->cmd
);
469 if ( dyldInfo
!= NULL
)
470 this->setDyldInfo(dyldInfo
);
471 if ( symbolTable
!= NULL
)
472 this->setSymbolTableInfo(symbolTable
, symbolTableStrings
, dynSymbolTable
);
476 // don't do this work in destructor because we need object to be full subclass
477 // for UnmapSegments() to work
478 void ImageLoaderMachO::destroy()
480 // update count of images with weak exports
481 if ( fRegisteredAsRequiresCoalescing
) {
482 --fgImagesRequiringCoalescing
;
483 if ( this->hasCoalescedExports() )
484 --fgImagesHasWeakDefinitions
;
487 // keep count of images used in shared cache
488 if ( fInSharedCache
)
489 --fgImagesUsedFromSharedCache
;
491 // unmap image when done
496 unsigned int ImageLoaderMachO::segmentCount() const
498 return fSegmentsCount
;
502 const macho_segment_command
* ImageLoaderMachO::segLoadCommand(unsigned int segIndex
) const
504 uint32_t* lcOffsets
= this->segmentCommandOffsets();
505 uint32_t lcOffset
= lcOffsets
[segIndex
];
506 return (macho_segment_command
*)(&fMachOData
[lcOffset
]);
509 const char* ImageLoaderMachO::segName(unsigned int segIndex
) const
511 return segLoadCommand(segIndex
)->segname
;
515 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex
) const
517 return segLoadCommand(segIndex
)->vmsize
;
521 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex
) const
523 return segLoadCommand(segIndex
)->filesize
;
527 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex
)
529 return ( segWriteable(segIndex
) && (segSize(segIndex
) > segFileSize(segIndex
)) );
533 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex
) const
535 return segLoadCommand(segIndex
)->fileoff
;
539 bool ImageLoaderMachO::segReadable(unsigned int segIndex
) const
541 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_READ
) != 0);
545 bool ImageLoaderMachO::segWriteable(unsigned int segIndex
) const
547 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_WRITE
) != 0);
551 bool ImageLoaderMachO::segExecutable(unsigned int segIndex
) const
553 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_EXECUTE
) != 0);
557 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex
) const
559 return (segLoadCommand(segIndex
)->initprot
== 0);
562 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex
) const
564 return (segLoadCommand(segIndex
)->vmaddr
!= 0);
567 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex
) const
569 return segLoadCommand(segIndex
)->vmaddr
;
572 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex
) const
574 return segLoadCommand(segIndex
)->vmaddr
+ fSlide
;
578 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex
) const
580 return segActualLoadAddress(segIndex
) + segSize(segIndex
);
583 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex
) const
585 // scan sections for fix-up bit
586 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
587 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
588 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
589 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
590 if ( (sect
->flags
& S_ATTR_LOC_RELOC
) != 0 )
596 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex
) const
598 // scan sections for fix-up bit
599 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
600 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
601 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
602 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
603 if ( (sect
->flags
& S_ATTR_EXT_RELOC
) != 0 )
610 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex
) const
612 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
613 return ( (segCmd
->initprot
& VM_PROT_EXECUTE
)
614 && ((segCmd
->initprot
& VM_PROT_WRITE
) == 0)
615 && (strcmp(segCmd
->segname
, "__IMPORT") == 0) );
620 void ImageLoaderMachO::UnmapSegments()
622 // usually unmap image when done
623 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) {
624 // unmap TEXT segment last because it contains load command being inspected
625 unsigned int textSegmentIndex
= 0;
626 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
627 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
628 if ( strcmp(segName(i
), "__TEXT") == 0 ) {
629 textSegmentIndex
= i
;
633 --ImageLoader::fgTotalSegmentsMapped
;
634 ImageLoader::fgTotalBytesMapped
-= segSize(i
);
635 munmap((void*)segActualLoadAddress(i
), segSize(i
));
639 --ImageLoader::fgTotalSegmentsMapped
;
640 ImageLoader::fgTotalBytesMapped
-= segSize(textSegmentIndex
);
641 munmap((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
));
646 // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
647 void ImageLoaderMachO::preFetchDATA(int fd
, uint64_t offsetInFat
, const LinkContext
& context
)
649 if ( context
.linkingMainExecutable
) {
650 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
651 if ( segWriteable(i
) && (segFileSize(i
) > 0) ) {
652 // prefetch writable segment that have mmap'ed regions
654 advice
.ra_offset
= offsetInFat
+ segFileOffset(i
);
655 advice
.ra_count
= segFileSize(i
);
656 // limit prefetch to 1MB (256 pages)
657 if ( advice
.ra_count
> 1024*1024 )
658 advice
.ra_count
= 1024*1024;
659 // don't prefetch single pages, let them fault in
660 fgTotalBytesPreFetched
+= advice
.ra_count
;
661 fcntl(fd
, F_RDADVISE
, &advice
);
662 if ( context
.verboseMapping
) {
663 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n",
664 segName(i
), segActualLoadAddress(i
), segActualLoadAddress(i
)+advice
.ra_count
-1);
672 bool ImageLoaderMachO::segmentsMustSlideTogether() const
677 bool ImageLoaderMachO::segmentsCanSlide() const
679 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
682 bool ImageLoaderMachO::isBundle() const
684 const macho_header
* mh
= (macho_header
*)fMachOData
;
685 return ( mh
->filetype
== MH_BUNDLE
);
688 bool ImageLoaderMachO::isDylib() const
690 const macho_header
* mh
= (macho_header
*)fMachOData
;
691 return ( mh
->filetype
== MH_DYLIB
);
694 bool ImageLoaderMachO::isExecutable() const
696 const macho_header
* mh
= (macho_header
*)fMachOData
;
697 return ( mh
->filetype
== MH_EXECUTE
);
700 bool ImageLoaderMachO::isPositionIndependentExecutable() const
702 const macho_header
* mh
= (macho_header
*)fMachOData
;
703 return ( (mh
->filetype
== MH_EXECUTE
) && ((mh
->flags
& MH_PIE
) != 0) );
707 bool ImageLoaderMachO::forceFlat() const
709 const macho_header
* mh
= (macho_header
*)fMachOData
;
710 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
713 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
715 const macho_header
* mh
= (macho_header
*)fMachOData
;
716 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
719 bool ImageLoaderMachO::isPrebindable() const
721 const macho_header
* mh
= (macho_header
*)fMachOData
;
722 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
725 bool ImageLoaderMachO::hasCoalescedExports() const
727 const macho_header
* mh
= (macho_header
*)fMachOData
;
728 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
731 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
733 const macho_header
* mh
= (macho_header
*)fMachOData
;
734 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
737 bool ImageLoaderMachO::participatesInCoalescing() const
739 const macho_header
* mh
= (macho_header
*)fMachOData
;
740 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
741 // is reduced and it can't coalesce with other images
742 if ( this->hasHiddenExports() )
744 return ( (mh
->flags
& (MH_WEAK_DEFINES
|MH_BINDS_TO_WEAK
)) != 0 );
749 void ImageLoaderMachO::setSlide(intptr_t slide
)
754 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command
* codeSigCmd
, int fd
, uint64_t offsetInFatFile
, const LinkContext
& context
)
756 // if dylib being loaded has no code signature load command
757 if ( codeSigCmd
== NULL
) {
758 #if __MAC_OS_X_VERSION_MIN_REQUIRED
759 bool codeSigningEnforced
= context
.codeSigningEnforced
;
760 if ( context
.mainExecutableCodeSigned
&& !codeSigningEnforced
) {
761 static bool codeSignEnforcementDynamicallyEnabled
= false;
762 if ( !codeSignEnforcementDynamicallyEnabled
) {
764 if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) {
765 if ( flags
& CS_ENFORCEMENT
) {
766 codeSignEnforcementDynamicallyEnabled
= true;
770 codeSigningEnforced
= codeSignEnforcementDynamicallyEnabled
;
772 // if we require dylibs to be code signed
773 if ( codeSigningEnforced
) {
774 // if there is a non-load command based code signature, use it
775 off_t offset
= (off_t
)offsetInFatFile
;
776 if ( fcntl(fd
, F_FINDSIGS
, &offset
, sizeof(offset
)) != -1 )
778 // otherwise gracefully return from dlopen()
779 dyld::throwf("required code signature missing for '%s'\n", this->getPath());
784 #if __MAC_OS_X_VERSION_MIN_REQUIRED
785 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools
786 if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9
) {
790 fsignatures_t siginfo
;
791 siginfo
.fs_file_start
=offsetInFatFile
; // start of mach-o slice in fat file
792 siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
); // start of CD in mach-o file
793 siginfo
.fs_blob_size
=codeSigCmd
->datasize
; // size of CD
794 int result
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
);
795 if ( result
== -1 ) {
796 if ( (errno
== EPERM
) || (errno
== EBADEXEC
) )
797 dyld::throwf("code signature invalid for '%s'\n", this->getPath());
798 if ( context
.verboseCodeSignatures
)
799 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno
);
801 dyld::log("dyld: Registered code signature for %s\n", this->getPath());
807 const char* ImageLoaderMachO::getInstallPath() const
809 if ( fDylibIDOffset
!= 0 ) {
810 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
811 return (char*)dylibID
+ dylibID
->dylib
.name
.offset
;
816 void ImageLoaderMachO::registerInterposing()
818 // mach-o files advertise interposing by having a __DATA __interpose section
819 struct InterposeData
{ uintptr_t replacement
; uintptr_t replacee
; };
820 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
821 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
822 const struct load_command
* cmd
= cmds
;
823 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
825 case LC_SEGMENT_COMMAND
:
827 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
828 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
829 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
830 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
831 if ( ((sect
->flags
& SECTION_TYPE
) == S_INTERPOSING
) || ((strcmp(sect
->sectname
, "__interpose") == 0) && (strcmp(seg
->segname
, "__DATA") == 0)) ) {
832 const InterposeData
* interposeArray
= (InterposeData
*)(sect
->addr
+ fSlide
);
833 const unsigned int count
= sect
->size
/ sizeof(InterposeData
);
834 for (uint32_t i
=0; i
< count
; ++i
) {
835 ImageLoader::InterposeTuple tuple
;
836 tuple
.replacement
= interposeArray
[i
].replacement
;
837 tuple
.replacementImage
= this;
838 tuple
.replacee
= interposeArray
[i
].replacee
;
839 // <rdar://problem/7937695> verify that replacement is in this image
840 if ( this->containsAddress((void*)tuple
.replacement
) ) {
841 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it
!= fgInterposingTuples
.end(); it
++) {
842 if ( it
->replacee
== tuple
.replacee
) {
843 tuple
.replacee
= it
->replacement
;
846 ImageLoader::fgInterposingTuples
.push_back(tuple
);
854 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
858 uint32_t ImageLoaderMachO::sdkVersion() const
860 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
861 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
862 const struct load_command
* cmd
= cmds
;
863 const struct version_min_command
* versCmd
;
864 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
865 switch ( cmd
->cmd
) {
866 case LC_VERSION_MIN_MACOSX
:
867 case LC_VERSION_MIN_IPHONEOS
:
868 versCmd
= (version_min_command
*)cmd
;
871 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
876 void* ImageLoaderMachO::getThreadPC() const
878 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
879 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
880 const struct load_command
* cmd
= cmds
;
881 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
882 if ( cmd
->cmd
== LC_MAIN
) {
883 entry_point_command
* mainCmd
= (entry_point_command
*)cmd
;
884 void* entry
= (void*)(mainCmd
->entryoff
+ (char*)fMachOData
);
885 // <rdar://problem/8543820&9228031> verify entry point is in image
886 if ( this->containsAddress(entry
) )
889 throw "LC_MAIN entryoff is out of range";
891 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
897 void* ImageLoaderMachO::getMain() const
899 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
900 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
901 const struct load_command
* cmd
= cmds
;
902 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
907 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
908 void* entry
= (void*)(registers
->eip
+ fSlide
);
910 const x86_thread_state64_t
* registers
= (x86_thread_state64_t
*)(((char*)cmd
) + 16);
911 void* entry
= (void*)(registers
->rip
+ fSlide
);
913 const arm_thread_state_t
* registers
= (arm_thread_state_t
*)(((char*)cmd
) + 16);
914 void* entry
= (void*)(registers
->__pc
+ fSlide
);
916 #warning need processor specific code
918 // <rdar://problem/8543820&9228031> verify entry point is in image
919 if ( this->containsAddress(entry
) ) {
925 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
927 throw "no valid entry point";
930 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount
, const macho_header
* mh
)
932 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
936 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
937 if ( mh
->filetype
== MH_EXECUTE
)
940 bool isNonOSdylib
= false;
941 const uint32_t cmd_count
= mh
->ncmds
;
942 const struct load_command
* const cmds
= (struct load_command
*)((uint8_t*)mh
+sizeof(macho_header
));
943 const struct load_command
* cmd
= cmds
;
944 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
947 case LC_LOAD_WEAK_DYLIB
:
948 case LC_REEXPORT_DYLIB
:
949 case LC_LOAD_UPWARD_DYLIB
:
953 const dylib_command
* dylibID
= (dylib_command
*)cmd
;
954 const char* installPath
= (char*)cmd
+ dylibID
->dylib
.name
.offset
;
955 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents
956 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
957 // <rdar://problem/6497528> rosetta circular dependency spew
958 isNonOSdylib
= ( (strncmp(installPath
, "/usr/lib/", 9) != 0) && (strncmp(installPath
, "/usr/libexec/oah/Shims", 9) != 0) );
962 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
968 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[])
970 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) {
971 DependentLibraryInfo
* lib
= &libs
[0];
972 lib
->name
= "/usr/lib/libSystem.B.dylib";
973 lib
->info
.checksum
= 0;
974 lib
->info
.minVersion
= 0;
975 lib
->info
.maxVersion
= 0;
976 lib
->required
= false;
977 lib
->reExported
= false;
982 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
983 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
984 const struct load_command
* cmd
= cmds
;
985 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
988 case LC_LOAD_WEAK_DYLIB
:
989 case LC_REEXPORT_DYLIB
:
990 case LC_LOAD_UPWARD_DYLIB
:
992 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
993 DependentLibraryInfo
* lib
= &libs
[index
++];
994 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
995 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
996 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
997 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
998 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
999 lib
->required
= (cmd
->cmd
!= LC_LOAD_WEAK_DYLIB
);
1000 lib
->reExported
= (cmd
->cmd
== LC_REEXPORT_DYLIB
);
1001 lib
->upward
= (cmd
->cmd
== LC_LOAD_UPWARD_DYLIB
);
1005 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1010 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo()
1013 if ( fDylibIDOffset
!= 0 ) {
1014 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
1015 info
.minVersion
= dylibID
->dylib
.compatibility_version
;
1016 info
.maxVersion
= dylibID
->dylib
.current_version
;
1017 info
.checksum
= dylibID
->dylib
.timestamp
;
1020 info
.minVersion
= 0;
1021 info
.maxVersion
= 0;
1027 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const
1029 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1030 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1031 const struct load_command
* cmd
= cmds
;
1032 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1035 const char* pathToAdd
= NULL
;
1036 const char* path
= (char*)cmd
+ ((struct rpath_command
*)cmd
)->path
.offset
;
1037 if ( strncmp(path
, "@loader_path/", 13) == 0 ) {
1038 if ( context
.processIsRestricted
&& (context
.mainExecutable
== this) ) {
1039 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path
, this->getPath());
1042 char resolvedPath
[PATH_MAX
];
1043 if ( realpath(this->getPath(), resolvedPath
) != NULL
) {
1044 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1045 strcpy(newRealPath
, resolvedPath
);
1046 char* addPoint
= strrchr(newRealPath
,'/');
1047 if ( addPoint
!= NULL
)
1048 strcpy(&addPoint
[1], &path
[13]);
1050 strcpy(newRealPath
, &path
[13]);
1051 pathToAdd
= strdup(newRealPath
);
1054 else if ( strncmp(path
, "@executable_path/", 17) == 0 ) {
1055 if ( context
.processIsRestricted
) {
1056 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path
, this->getPath());
1059 char resolvedPath
[PATH_MAX
];
1060 if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL
) {
1061 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1062 strcpy(newRealPath
, resolvedPath
);
1063 char* addPoint
= strrchr(newRealPath
,'/');
1064 if ( addPoint
!= NULL
)
1065 strcpy(&addPoint
[1], &path
[17]);
1067 strcpy(newRealPath
, &path
[17]);
1068 pathToAdd
= strdup(newRealPath
);
1071 else if ( (path
[0] != '/') && context
.processIsRestricted
) {
1072 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path
, this->getPath());
1075 else if ( (path
[0] == '/') && (context
.rootPaths
!= NULL
) ) {
1076 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
1077 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
1079 for(const char** rp
= context
.rootPaths
; *rp
!= NULL
; ++rp
) {
1080 char newPath
[PATH_MAX
];
1081 strlcpy(newPath
, *rp
, PATH_MAX
);
1082 strlcat(newPath
, path
, PATH_MAX
);
1083 struct stat stat_buf
;
1084 if ( stat(newPath
, &stat_buf
) != -1 ) {
1085 //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
1086 pathToAdd
= strdup(newPath
);
1092 // make copy so that all elements of 'paths' can be freed
1093 pathToAdd
= strdup(path
);
1097 // make copy so that all elements of 'paths' can be freed
1098 pathToAdd
= strdup(path
);
1100 if ( pathToAdd
!= NULL
)
1101 paths
.push_back(pathToAdd
);
1104 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1108 bool ImageLoaderMachO::getUUID(uuid_t uuid
) const
1110 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1111 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1112 const struct load_command
* cmd
= cmds
;
1113 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1116 uuid_command
* uc
= (uuid_command
*)cmd
;
1117 memcpy(uuid
, uc
->uuid
, 16);
1120 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1126 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1128 // if prebound and loaded at prebound address, then no need to rebase
1129 if ( this->usablePrebinding(context
) ) {
1130 // skip rebasing because prebinding is valid
1131 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1135 // print why prebinding was not used
1136 if ( context
.verbosePrebinding
) {
1137 if ( !this->isPrebindable() ) {
1138 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1140 else if ( fSlide
!= 0 ) {
1141 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1143 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1144 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1146 else if ( !this->usesTwoLevelNameSpace() ){
1147 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1150 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1154 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1156 #if PREBOUND_IMAGE_SUPPORT
1157 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1158 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1159 if ( this->isPrebindable() && !fInSharedCache
)
1160 this->resetPreboundLazyPointers(context
);
1163 // if loaded at preferred address, no rebasing necessary
1164 if ( this->fSlide
== 0 )
1167 #if TEXT_RELOC_SUPPORT
1168 // if there are __TEXT fixups, temporarily make __TEXT writable
1169 if ( fTextSegmentRebases
)
1170 this->makeTextSegmentWritable(context
, true);
1173 // do actual rebasing
1174 this->rebase(context
);
1176 #if TEXT_RELOC_SUPPORT
1177 // if there were __TEXT fixups, restore write protection
1178 if ( fTextSegmentRebases
)
1179 this->makeTextSegmentWritable(context
, false);
1184 #if TEXT_RELOC_SUPPORT
1185 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext
& context
, bool writeable
)
1187 int textSegmentIndex
= 0;
1188 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1189 if ( strcmp(segName(i
), "__TEXT") == 0 ) {
1190 textSegmentIndex
= i
;
1196 segMakeWritable(textSegmentIndex
, context
);
1199 #if !__i386__ && !__x86_64__
1200 // some processors require range to be invalidated before it is made executable
1201 sys_icache_invalidate((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
));
1203 segProtect(textSegmentIndex
, context
);
1208 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, bool searchReExports
, const ImageLoader
** foundIn
) const
1210 // look in this image first
1211 const ImageLoader::Symbol
* result
= this->findExportedSymbol(name
, foundIn
);
1212 if ( result
!= NULL
)
1215 if ( searchReExports
) {
1216 for(unsigned int i
=0; i
< libraryCount(); ++i
){
1217 if ( libReExported(i
) ) {
1218 ImageLoader
* image
= libImage(i
);
1219 if ( image
!= NULL
) {
1220 const Symbol
* result
= image
->findExportedSymbol(name
, searchReExports
, foundIn
);
1221 if ( result
!= NULL
)
1234 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
1235 const ImageLoader
* requestor
, bool runResolver
) const
1237 return this->getSymbolAddress(sym
, requestor
, context
, runResolver
);
1240 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol
* sym
, const ImageLoader
* requestor
,
1241 const LinkContext
& context
, bool runResolver
) const
1243 uintptr_t result
= exportedSymbolAddress(context
, sym
, requestor
, runResolver
);
1244 // check for interposing overrides
1245 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it
!= fgInterposingTuples
.end(); it
++) {
1246 // replace all references to 'replacee' with 'replacement'
1247 if ( (result
== it
->replacee
) && (requestor
!= it
->replacementImage
) ) {
1248 if ( context
.verboseInterposing
) {
1249 dyld::log("dyld interposing: replace 0x%lX with 0x%lX in %s\n",
1250 it
->replacee
, it
->replacement
, this->getPath());
1252 result
= it
->replacement
;
1258 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1260 if ( exportedSymbolIsWeakDefintion(sym
) )
1261 return kWeakDefinition
;
1263 return kNoDefinitionOptions
;
1266 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1268 return exportedSymbolName(sym
);
1271 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1273 return exportedSymbolCount();
1277 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1279 return exportedSymbolIndexed(index
);
1283 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1285 return importedSymbolCount();
1289 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1291 return importedSymbolIndexed(index
);
1295 ImageLoader::ReferenceFlags
ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1297 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1302 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1304 return importedSymbolName(sym
);
1308 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1310 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1311 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1312 const struct load_command
* cmd
= cmds
;
1313 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1315 case LC_SEGMENT_COMMAND
:
1317 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1318 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1319 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1320 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1321 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1322 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1323 *length
= sect
->size
;
1330 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1337 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections
* info
)
1339 info
->mh
= this->machHeader();
1340 info
->dwarf_section
= 0;
1341 info
->dwarf_section_length
= 0;
1342 info
->compact_unwind_section
= 0;
1343 info
->compact_unwind_section_length
= 0;
1344 if ( fEHFrameSectionOffset
!= 0 ) {
1345 const macho_section
* sect
= (macho_section
*)&fMachOData
[fEHFrameSectionOffset
];
1346 info
->dwarf_section
= (void*)(sect
->addr
+ fSlide
);
1347 info
->dwarf_section_length
= sect
->size
;
1349 if ( fUnwindInfoSectionOffset
!= 0 ) {
1350 const macho_section
* sect
= (macho_section
*)&fMachOData
[fUnwindInfoSectionOffset
];
1351 info
->compact_unwind_section
= (void*)(sect
->addr
+ fSlide
);
1352 info
->compact_unwind_section_length
= sect
->size
;
1357 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1359 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1360 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1361 const struct load_command
* cmd
= cmds
;
1362 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1363 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1365 case LC_SEGMENT_COMMAND
:
1367 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1368 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1369 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1370 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1371 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1372 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1373 if ( segmentName
!= NULL
)
1374 *segmentName
= sect
->segname
;
1375 if ( sectionName
!= NULL
)
1376 *sectionName
= sect
->sectname
;
1377 if ( sectionOffset
!= NULL
)
1378 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1386 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1392 void __attribute__((noreturn
)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext
& context
, const char* symbol
,
1393 const char* referencedFrom
, const char* expectedIn
)
1395 // record values for possible use by CrashReporter or Finder
1396 (*context
.setErrorStrings
)(dyld_error_kind_symbol_missing
, referencedFrom
, expectedIn
, symbol
);
1397 dyld::throwf("Symbol not found: %s\n Referenced from: %s\n Expected in: %s\n", symbol
, referencedFrom
, expectedIn
);
1400 const mach_header
* ImageLoaderMachO::machHeader() const
1402 return (mach_header
*)fMachOData
;
1405 uintptr_t ImageLoaderMachO::getSlide() const
1410 // hmm. maybe this should be up in ImageLoader??
1411 const void* ImageLoaderMachO::getEnd() const
1413 uintptr_t lastAddress
= 0;
1414 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1415 uintptr_t segEnd
= segActualEndAddress(i
);
1416 if ( strcmp(segName(i
), "__UNIXSTACK") != 0 ) {
1417 if ( segEnd
> lastAddress
)
1418 lastAddress
= segEnd
;
1421 return (const void*)lastAddress
;
1425 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext
& context
, uintptr_t location
, uintptr_t value
,
1426 const ImageLoader
* targetImage
, uint8_t type
, const char* symbolName
,
1427 intptr_t addend
, const char* msg
)
1430 if ( context
.verboseBind
) {
1432 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1433 msg
, this->getShortName(), (uintptr_t)location
,
1434 ((targetImage
!= NULL
) ? targetImage
->getShortName() : "<weak_import-missing>"),
1435 symbolName
, (uintptr_t)location
, value
, addend
);
1437 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1438 msg
, this->getShortName(), (uintptr_t)location
,
1439 ((targetImage
!= NULL
) ? targetImage
->getShortName() : "<weak>import-missing>"),
1440 symbolName
, (uintptr_t)location
, value
);
1443 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
1447 uintptr_t* locationToFix
= (uintptr_t*)location
;
1449 uintptr_t newValue
= value
+addend
;
1452 case BIND_TYPE_POINTER
:
1453 // test first so we don't needless dirty pages
1454 if ( *locationToFix
!= newValue
)
1455 *locationToFix
= newValue
;
1457 case BIND_TYPE_TEXT_ABSOLUTE32
:
1458 loc32
= (uint32_t*)locationToFix
;
1459 value32
= (uint32_t)newValue
;
1460 if ( *loc32
!= value32
)
1463 case BIND_TYPE_TEXT_PCREL32
:
1464 loc32
= (uint32_t*)locationToFix
;
1465 value32
= (uint32_t)newValue
- (((uintptr_t)locationToFix
) + 4);
1466 if ( *loc32
!= value32
)
1470 dyld::throwf("bad bind type %d", type
);
1473 // update statistics
1474 ++fgTotalBindFixups
;
1483 #if SUPPORT_OLD_CRT_INITIALIZATION
1484 // first 16 bytes of "start" in crt1.o
1486 static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
1491 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper_interface
1492 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
1493 // the following only exist in main executables built for 10.5 or later
1497 // These are defined in dyldStartup.s
1498 extern "C" void stub_binding_helper();
1499 extern "C" bool dyld_func_lookup(const char* name
, uintptr_t* address
);
1502 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
1504 const macho_header
* mh
= (macho_header
*)fMachOData
;
1505 const uint32_t cmd_count
= mh
->ncmds
;
1506 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1507 const struct load_command
* cmd
;
1508 // There used to be some optimizations to skip this section scan, but we need to handle the
1509 // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
1510 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
1513 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1514 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1515 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1516 if ( strcmp(seg
->segname
, "__DATA") == 0 ) {
1517 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1518 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1519 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1520 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) {
1521 struct DATAdyld
* dd
= (struct DATAdyld
*)(sect
->addr
+ fSlide
);
1522 if ( sect
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
1523 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
1524 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
1526 if ( sect
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
1527 if ( dd
->dyldFuncLookup
!= (void*)&dyld_func_lookup
)
1528 dd
->dyldFuncLookup
= (void*)&dyld_func_lookup
;
1530 if ( mh
->filetype
== MH_EXECUTE
) {
1531 // there are two ways to get the program variables
1532 if ( (sect
->size
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh
== mh
) ) {
1533 // some really old binaries have space for vars, but it is zero filled
1534 // main executable has 10.5 style __dyld section that has program variable pointers
1535 context
.setNewProgramVars(dd
->vars
);
1538 // main executable is pre-10.5 and requires the symbols names to be looked up
1539 this->lookupProgramVars(context
);
1540 #if SUPPORT_OLD_CRT_INITIALIZATION
1541 // If the first 16 bytes of the entry point's instructions do not
1542 // match what crt1.o supplies, then the program has a custom entry point.
1543 // This means it might be doing something that needs to be executed before
1544 // initializers are run.
1545 if ( memcmp(this->getMain(), sStandardEntryPointInstructions
, 16) != 0 ) {
1546 if ( context
.verboseInit
)
1547 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
1548 context
.setRunInitialzersOldWay();
1553 else if ( mh
->filetype
== MH_DYLIB
) {
1554 const char* installPath
= this->getInstallPath();
1555 if ( (installPath
!= NULL
) && (strncmp(installPath
, "/usr/lib/", 9) == 0) ) {
1556 if ( sect
->size
> offsetof(DATAdyld
, vars
) ) {
1557 // use ProgramVars from libdyld.dylib but tweak mh field to correct value
1558 dd
->vars
.mh
= context
.mainExecutable
->machHeader();
1559 context
.setNewProgramVars(dd
->vars
);
1564 else if ( (strcmp(sect
->sectname
, "__program_vars" ) == 0) && (mh
->filetype
== MH_EXECUTE
) ) {
1565 // this is a Mac OS X 10.6 or later main executable
1566 struct ProgramVars
* pv
= (struct ProgramVars
*)(sect
->addr
+ fSlide
);
1567 context
.setNewProgramVars(*pv
);
1572 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1578 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const
1580 ProgramVars vars
= context
.programVars
;
1581 const ImageLoader::Symbol
* sym
;
1583 // get mach header directly
1584 vars
.mh
= (macho_header
*)fMachOData
;
1587 sym
= this->findExportedSymbol("_NXArgc", false, NULL
);
1589 vars
.NXArgcPtr
= (int*)this->getExportedSymbolAddress(sym
, context
, this, false);
1592 sym
= this->findExportedSymbol("_NXArgv", false, NULL
);
1594 vars
.NXArgvPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false);
1597 sym
= this->findExportedSymbol("_environ", false, NULL
);
1599 vars
.environPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false);
1601 // lookup __progname
1602 sym
= this->findExportedSymbol("___progname", false, NULL
);
1604 vars
.__prognamePtr
= (const char**)this->getExportedSymbolAddress(sym
, context
, this, false);
1606 context
.setNewProgramVars(vars
);
1610 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
1612 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
1613 if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache
)
1614 && this->usesTwoLevelNameSpace()
1615 && this->allDependentLibrariesAsWhenPreBound() ) {
1616 // allow environment variables to disable prebinding
1617 if ( context
.bindFlat
)
1619 switch ( context
.prebindUsage
) {
1620 case kUseAllPrebinding
:
1622 case kUseSplitSegPrebinding
:
1623 return this->fIsSplitSeg
;
1624 case kUseAllButAppPredbinding
:
1625 return (this != context
.mainExecutable
);
1626 case kUseNoPrebinding
:
1634 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
1636 if ( fHasDashInit
) {
1637 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1638 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1639 const struct load_command
* cmd
= cmds
;
1640 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1642 case LC_ROUTINES_COMMAND
:
1643 Initializer func
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address
+ fSlide
);
1644 // <rdar://problem/8543820&9228031> verify initializers are in image
1645 if ( ! this->containsAddress((void*)func
) ) {
1646 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
1648 if ( context
.verboseInit
)
1649 dyld::log("dyld: calling -init function %p in %s\n", func
, this->getPath());
1650 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
1653 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1658 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
1660 if ( fHasInitializers
) {
1661 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1662 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1663 const struct load_command
* cmd
= cmds
;
1664 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1665 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1666 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1667 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1668 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1669 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1670 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1671 if ( type
== S_MOD_INIT_FUNC_POINTERS
) {
1672 Initializer
* inits
= (Initializer
*)(sect
->addr
+ fSlide
);
1673 const uint32_t count
= sect
->size
/ sizeof(uintptr_t);
1674 for (uint32_t i
=0; i
< count
; ++i
) {
1675 Initializer func
= inits
[i
];
1676 // <rdar://problem/8543820&9228031> verify initializers are in image
1677 if ( ! this->containsAddress((void*)func
) ) {
1678 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
1680 if ( context
.verboseInit
)
1681 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath());
1682 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
1687 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1697 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
)
1699 if ( fHasDOFSections
) {
1700 // walk load commands (mapped in at start of __TEXT segment)
1701 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1702 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1703 const struct load_command
* cmd
= cmds
;
1704 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1706 case LC_SEGMENT_COMMAND
:
1708 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1709 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1710 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1711 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1712 if ( (sect
->flags
& SECTION_TYPE
) == S_DTRACE_DOF
) {
1713 ImageLoader::DOFInfo info
;
1714 info
.dof
= (void*)(sect
->addr
+ fSlide
);
1715 info
.imageHeader
= this->machHeader();
1716 info
.imageShortName
= this->getShortName();
1717 dofs
.push_back(info
);
1723 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1729 bool ImageLoaderMachO::doInitialization(const LinkContext
& context
)
1731 CRSetCrashLogMessage2(this->getPath());
1733 // mach-o has -init and static initializers
1734 doImageInit(context
);
1735 doModInitFunctions(context
);
1737 CRSetCrashLogMessage2(NULL
);
1739 return (fHasDashInit
|| fHasInitializers
);
1742 bool ImageLoaderMachO::needsInitialization()
1744 return ( fHasDashInit
|| fHasInitializers
);
1748 bool ImageLoaderMachO::needsTermination()
1750 return fHasTerminators
;
1754 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
1756 if ( fHasTerminators
) {
1757 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1758 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1759 const struct load_command
* cmd
= cmds
;
1760 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1761 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1762 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1763 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1764 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1765 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1766 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1767 if ( type
== S_MOD_TERM_FUNC_POINTERS
) {
1768 Terminator
* terms
= (Terminator
*)(sect
->addr
+ fSlide
);
1769 const uint32_t count
= sect
->size
/ sizeof(uintptr_t);
1770 for (uint32_t i
=count
; i
> 0; --i
) {
1771 Terminator func
= terms
[i
-1];
1772 // <rdar://problem/8543820&9228031> verify terminators are in image
1773 if ( ! this->containsAddress((void*)func
) ) {
1774 dyld::throwf("termination function %p not in mapped image for %s\n", func
, this->getPath());
1776 if ( context
.verboseInit
)
1777 dyld::log("dyld: calling termination function %p in %s\n", func
, this->getPath());
1783 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1789 void ImageLoaderMachO::printStatistics(unsigned int imageCount
, const InitializerTimingList
& timingInfo
)
1791 ImageLoader::printStatistics(imageCount
, timingInfo
);
1792 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs
);
1793 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs
);
1794 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions
);
1795 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing
);
1799 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext
& context
)
1801 // preflight and calculate slide if needed
1802 const bool inPIE
= (fgNextPIEDylibAddress
!= 0);
1804 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
1805 bool needsToSlide
= false;
1806 bool imageHasPreferredLoadAddress
= segHasPreferredLoadAddress(0);
1807 uintptr_t lowAddr
= (unsigned long)(-1);
1808 uintptr_t highAddr
= 0;
1809 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1810 const uintptr_t segLow
= segPreferredLoadAddress(i
);
1811 const uintptr_t segHigh
= (segLow
+ segSize(i
) + 4095) & -4096;
1812 if ( segLow
< lowAddr
)
1814 if ( segHigh
> highAddr
)
1817 if ( needsToSlide
|| !imageHasPreferredLoadAddress
|| inPIE
|| !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
1818 needsToSlide
= true;
1820 if ( needsToSlide
) {
1821 // find a chunk of address space to hold all segments
1822 uintptr_t addr
= reserveAnAddressRange(highAddr
-lowAddr
, context
);
1823 slide
= addr
- lowAddr
;
1826 else if ( ! this->segmentsCanSlide() ) {
1827 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1828 if ( strcmp(segName(i
), "__PAGEZERO") == 0 )
1830 if ( !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
1831 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i
), segPreferredLoadAddress(i
), segSize(i
));
1835 throw "mach-o does not support independently sliding segments";
1841 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
)
1843 vm_address_t addr
= 0;
1844 vm_size_t size
= length
;
1845 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
1846 if ( fgNextPIEDylibAddress
!= 0 ) {
1847 // add small (0-3 pages) random padding between dylibs
1848 addr
= fgNextPIEDylibAddress
+ (__stack_chk_guard
/fgNextPIEDylibAddress
& (sizeof(long)-1))*4096;
1849 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
1850 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
1851 if ( r
== KERN_SUCCESS
) {
1852 fgNextPIEDylibAddress
= addr
+ size
;
1855 fgNextPIEDylibAddress
= 0;
1857 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
1858 if ( r
!= KERN_SUCCESS
)
1859 throw "out of address space";
1864 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start
, size_t length
)
1866 vm_address_t addr
= start
;
1867 vm_size_t size
= length
;
1868 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
1869 if ( r
!= KERN_SUCCESS
)
1876 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
1878 // find address range for image
1879 intptr_t slide
= this->assignSegmentAddresses(context
);
1880 if ( context
.verboseMapping
)
1881 dyld::log("dyld: Mapping %s\n", this->getPath());
1882 // map in all segments
1883 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1884 vm_offset_t fileOffset
= segFileOffset(i
) + offsetInFat
;
1885 vm_size_t size
= segFileSize(i
);
1886 uintptr_t requestedLoadAddress
= segPreferredLoadAddress(i
) + slide
;
1888 if ( !segUnaccessible(i
) ) {
1889 // If has text-relocs, don't set x-bit initially.
1890 // Instead set it later after text-relocs have been done.
1891 // The iPhone OS does not like it when you make executable code writable.
1892 if ( segExecutable(i
) && !(segHasRebaseFixUps(i
) && (slide
!= 0)) )
1893 protection
|= PROT_EXEC
;
1894 if ( segReadable(i
) )
1895 protection
|= PROT_READ
;
1896 if ( segWriteable(i
) )
1897 protection
|= PROT_WRITE
;
1900 // initially map __IMPORT segments R/W so dyld can update them
1901 if ( segIsReadOnlyImport(i
) )
1902 protection
|= PROT_WRITE
;
1904 // wholly zero-fill segments have nothing to mmap() in
1906 if ( (fileOffset
+size
) > fileLen
) {
1907 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
1908 segName(i
), (uint64_t)(fileOffset
+size
), fileLen
);
1910 void* loadAddress
= xmmap((void*)requestedLoadAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, fileOffset
);
1911 if ( loadAddress
== ((void*)(-1)) ) {
1912 dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
1913 errno
, requestedLoadAddress
, (uintptr_t)size
, segName(i
), getPath());
1917 ++ImageLoader::fgTotalSegmentsMapped
;
1918 ImageLoader::fgTotalBytesMapped
+= size
;
1919 if ( context
.verboseMapping
)
1920 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i
), requestedLoadAddress
, requestedLoadAddress
+size
-1,
1921 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
1924 // update slide to reflect load location
1925 this->setSlide(slide
);
1928 void ImageLoaderMachO::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
)
1930 // find address range for image
1931 intptr_t slide
= this->assignSegmentAddresses(context
);
1932 if ( context
.verboseMapping
)
1933 dyld::log("dyld: Mapping memory %p\n", memoryImage
);
1934 // map in all segments
1935 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1936 vm_address_t loadAddress
= segPreferredLoadAddress(i
) + slide
;
1937 vm_address_t srcAddr
= (uintptr_t)memoryImage
+ segFileOffset(i
);
1938 vm_size_t size
= segFileSize(i
);
1939 kern_return_t r
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
);
1940 if ( r
!= KERN_SUCCESS
)
1941 throw "can't map segment";
1942 if ( context
.verboseMapping
)
1943 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i
), (uintptr_t)loadAddress
, (uintptr_t)loadAddress
+size
-1);
1945 // update slide to reflect load location
1946 this->setSlide(slide
);
1947 // set R/W permissions on all segments at slide location
1948 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1949 segProtect(i
, context
);
1954 void ImageLoaderMachO::segProtect(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
1956 vm_prot_t protection
= 0;
1957 if ( !segUnaccessible(segIndex
) ) {
1958 if ( segExecutable(segIndex
) )
1959 protection
|= PROT_EXEC
;
1960 if ( segReadable(segIndex
) )
1961 protection
|= PROT_READ
;
1962 if ( segWriteable(segIndex
) )
1963 protection
|= PROT_WRITE
;
1965 vm_address_t addr
= segActualLoadAddress(segIndex
);
1966 vm_size_t size
= segSize(segIndex
);
1967 const bool setCurrentPermissions
= false;
1968 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
1969 if ( r
!= KERN_SUCCESS
) {
1970 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
1971 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
1973 if ( context
.verboseMapping
) {
1974 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,
1975 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
1979 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
1981 vm_address_t addr
= segActualLoadAddress(segIndex
);
1982 vm_size_t size
= segSize(segIndex
);
1983 const bool setCurrentPermissions
= false;
1984 vm_prot_t protection
= VM_PROT_WRITE
| VM_PROT_READ
;
1985 if ( segExecutable(segIndex
) && !segHasRebaseFixUps(segIndex
) )
1986 protection
|= VM_PROT_EXECUTE
;
1987 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
1988 if ( r
!= KERN_SUCCESS
) {
1989 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
1990 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
1992 if ( context
.verboseMapping
) {
1993 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,
1994 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );