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 #ifndef LC_VERSION_MIN_TVOS
64 #define LC_VERSION_MIN_TVOS 0x2F
67 #ifndef LC_VERSION_MIN_WATCHOS
68 #define LC_VERSION_MIN_WATCHOS 0x30
72 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
74 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
75 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
76 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
77 struct macho_segment_command
: public segment_command_64
{};
78 struct macho_section
: public section_64
{};
79 struct macho_routines_command
: public routines_command_64
{};
81 #define LC_SEGMENT_COMMAND LC_SEGMENT
82 #define LC_ROUTINES_COMMAND LC_ROUTINES
83 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
84 struct macho_segment_command
: public segment_command
{};
85 struct macho_section
: public section
{};
86 struct macho_routines_command
: public routines_command
{};
89 uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs
= 0;
90 uint32_t ImageLoaderMachO::fgSymbolTrieSearchs
= 0;
93 ImageLoaderMachO::ImageLoaderMachO(const macho_header
* mh
, const char* path
, unsigned int segCount
,
94 uint32_t segOffsets
[], unsigned int libCount
)
95 : ImageLoader(path
, libCount
), fCoveredCodeLength(0), fMachOData((uint8_t*)mh
), fLinkEditBase(NULL
), fSlide(0),
96 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
97 fSegmentsCount(segCount
), fIsSplitSeg(false), fInSharedCache(false),
98 #if TEXT_RELOC_SUPPORT
99 fTextSegmentRebases(false),
100 fTextSegmentBinds(false),
103 fReadOnlyImportSegment(false),
105 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
106 fHasInitializers(false), fHasTerminators(false), fRegisteredAsRequiresCoalescing(false)
108 fIsSplitSeg
= ((mh
->flags
& MH_SPLIT_SEGS
) != 0);
110 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
111 // each SegmentMachO object in array at end of ImageLoaderMachO object
112 const uint32_t cmd_count
= mh
->ncmds
;
113 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
114 const struct load_command
* cmd
= cmds
;
115 for (uint32_t i
= 0, segIndex
=0; i
< cmd_count
; ++i
) {
116 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
117 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
118 // ignore zero-sized segments
119 if ( segCmd
->vmsize
!= 0 ) {
120 // record offset of load command
121 segOffsets
[segIndex
++] = (uint32_t)((uint8_t*)segCmd
- fMachOData
);
124 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
130 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
131 void ImageLoaderMachO::sniffLoadCommands(const macho_header
* mh
, const char* path
, bool inCache
, bool* compressed
,
132 unsigned int* segCount
, unsigned int* libCount
, const LinkContext
& context
,
133 const linkedit_data_command
** codeSigCmd
,
134 const encryption_info_command
** encryptCmd
)
142 const uint32_t cmd_count
= mh
->ncmds
;
143 const struct load_command
* const startCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
));
144 const struct load_command
* const endCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
) + mh
->sizeofcmds
);
145 const struct load_command
* cmd
= startCmds
;
146 bool foundLoadCommandSegment
= false;
147 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
148 uint32_t cmdLength
= cmd
->cmdsize
;
149 struct macho_segment_command
* segCmd
;
150 if ( cmdLength
< 8 ) {
151 dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s",
154 const struct load_command
* const nextCmd
= (const struct load_command
*)(((char*)cmd
)+cmdLength
);
155 if ( (nextCmd
> endCmds
) || (nextCmd
< cmd
) ) {
156 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
157 i
, cmdLength
, mh
->sizeofcmds
, path
);
161 case LC_DYLD_INFO_ONLY
:
164 case LC_SEGMENT_COMMAND
:
165 segCmd
= (struct macho_segment_command
*)cmd
;
166 #if __MAC_OS_X_VERSION_MIN_REQUIRED
167 // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS)
168 if ( (segCmd
->filesize
> segCmd
->vmsize
) && (segCmd
->vmsize
!= 0) )
170 if ( segCmd
->filesize
> segCmd
->vmsize
)
172 dyld::throwf("malformed mach-o image: segment load command %s filesize is larger than vmsize", segCmd
->segname
);
173 // ignore zero-sized segments
174 if ( segCmd
->vmsize
!= 0 )
176 if ( context
.codeSigningEnforced
) {
177 uintptr_t vmStart
= segCmd
->vmaddr
;
178 uintptr_t vmSize
= segCmd
->vmsize
;
179 uintptr_t vmEnd
= vmStart
+ vmSize
;
180 uintptr_t fileStart
= segCmd
->fileoff
;
181 uintptr_t fileSize
= segCmd
->filesize
;
182 if ( (intptr_t)(vmEnd
) < 0)
183 dyld::throwf("malformed mach-o image: segment load command %s vmsize too large", segCmd
->segname
);
184 if ( vmStart
> vmEnd
)
185 dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd
->segname
);
186 if ( vmSize
!= fileSize
) {
187 if ( (segCmd
->initprot
== 0) && (fileSize
!= 0) )
188 dyld::throwf("malformed mach-o image: unaccessable segment %s has filesize != 0", segCmd
->segname
);
189 else if ( vmSize
< fileSize
)
190 dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd
->segname
);
193 if ( (fileSize
!= 0) && (segCmd
->initprot
== (VM_PROT_READ
| VM_PROT_EXECUTE
)) ) {
194 if ( foundLoadCommandSegment
)
195 throw "load commands in multiple segments";
196 foundLoadCommandSegment
= true;
199 else if ( (fileStart
< mh
->sizeofcmds
) && (fileSize
!= 0) ) {
200 // <rdar://problem/7942521> all load commands must be in an executable segment
201 if ( (fileStart
!= 0) || (fileSize
< (mh
->sizeofcmds
+sizeof(macho_header
))) )
202 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd
->segname
);
203 if ( segCmd
->initprot
!= (VM_PROT_READ
| VM_PROT_EXECUTE
) )
204 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd
->segname
);
205 if ( foundLoadCommandSegment
)
206 throw "load commands in multiple segments";
207 foundLoadCommandSegment
= true;
210 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
211 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
212 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
213 if (!inCache
&& sect
->offset
!= 0 && ((sect
->offset
+ sect
->size
) > (segCmd
->fileoff
+ segCmd
->filesize
)))
214 dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect
->segname
, sect
->sectname
, path
, segCmd
->segname
);
218 case LC_SEGMENT_COMMAND_WRONG
:
219 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
222 case LC_LOAD_WEAK_DYLIB
:
223 case LC_REEXPORT_DYLIB
:
224 case LC_LOAD_UPWARD_DYLIB
:
227 case LC_CODE_SIGNATURE
:
228 *codeSigCmd
= (struct linkedit_data_command
*)cmd
; // only support one LC_CODE_SIGNATURE per image
230 case LC_ENCRYPTION_INFO
:
231 case LC_ENCRYPTION_INFO_64
:
232 *encryptCmd
= (struct encryption_info_command
*)cmd
; // only support one LC_ENCRYPTION_INFO[_64] per image
238 if ( context
.codeSigningEnforced
&& !foundLoadCommandSegment
)
239 throw "load commands not in a segment";
241 // <rdar://problem/13145644> verify every segment does not overlap another segment
242 if ( context
.codeSigningEnforced
) {
243 uintptr_t lastFileStart
= 0;
244 uintptr_t linkeditFileStart
= 0;
245 const struct load_command
* cmd1
= startCmds
;
246 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
247 if ( cmd1
->cmd
== LC_SEGMENT_COMMAND
) {
248 struct macho_segment_command
* segCmd1
= (struct macho_segment_command
*)cmd1
;
249 uintptr_t vmStart1
= segCmd1
->vmaddr
;
250 uintptr_t vmEnd1
= segCmd1
->vmaddr
+ segCmd1
->vmsize
;
251 uintptr_t fileStart1
= segCmd1
->fileoff
;
252 uintptr_t fileEnd1
= segCmd1
->fileoff
+ segCmd1
->filesize
;
254 if (fileStart1
> lastFileStart
)
255 lastFileStart
= fileStart1
;
257 if ( strcmp(&segCmd1
->segname
[0], "__LINKEDIT") == 0 ) {
258 linkeditFileStart
= fileStart1
;
261 const struct load_command
* cmd2
= startCmds
;
262 for (uint32_t j
= 0; j
< cmd_count
; ++j
) {
265 if ( cmd2
->cmd
== LC_SEGMENT_COMMAND
) {
266 struct macho_segment_command
* segCmd2
= (struct macho_segment_command
*)cmd2
;
267 uintptr_t vmStart2
= segCmd2
->vmaddr
;
268 uintptr_t vmEnd2
= segCmd2
->vmaddr
+ segCmd2
->vmsize
;
269 uintptr_t fileStart2
= segCmd2
->fileoff
;
270 uintptr_t fileEnd2
= segCmd2
->fileoff
+ segCmd2
->filesize
;
271 if ( ((vmStart2
<= vmStart1
) && (vmEnd2
> vmStart1
) && (vmEnd1
> vmStart1
))
272 || ((vmStart2
>= vmStart1
) && (vmStart2
< vmEnd1
) && (vmEnd2
> vmStart2
)) )
273 dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);
274 if ( ((fileStart2
<= fileStart1
) && (fileEnd2
> fileStart1
) && (fileEnd1
> fileStart1
))
275 || ((fileStart2
>= fileStart1
) && (fileStart2
< fileEnd1
) && (fileEnd2
> fileStart2
)) )
276 dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);
278 cmd2
= (const struct load_command
*)(((char*)cmd2
)+cmd2
->cmdsize
);
281 cmd1
= (const struct load_command
*)(((char*)cmd1
)+cmd1
->cmdsize
);
284 if (lastFileStart
!= linkeditFileStart
)
285 dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment");
288 // fSegmentsArrayCount is only 8-bits
289 if ( *segCount
> 255 )
290 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path
);
292 // fSegmentsArrayCount is only 8-bits
293 if ( *libCount
> 4095 )
294 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path
);
296 if ( needsAddedLibSystemDepency(*libCount
, mh
) )
302 // create image for main executable
303 ImageLoader
* ImageLoaderMachO::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
)
305 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
306 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
308 unsigned int segCount
;
309 unsigned int libCount
;
310 const linkedit_data_command
* codeSigCmd
;
311 const encryption_info_command
* encryptCmd
;
312 sniffLoadCommands(mh
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
313 // instantiate concrete class based on content of load commands
315 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
317 #if SUPPORT_CLASSIC_MACHO
318 return ImageLoaderMachOClassic::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
320 throw "missing LC_DYLD_INFO load command";
325 // create image by mapping in a mach-o file
326 ImageLoader
* ImageLoaderMachO::instantiateFromFile(const char* path
, int fd
, const uint8_t firstPage
[4096], uint64_t offsetInFat
,
327 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
330 const unsigned int dataSize
= sizeof(macho_header
) + ((macho_header
*)firstPage
)->sizeofcmds
;
331 uint8_t buffer
[dataSize
];
332 const uint8_t* fileData
= firstPage
;
333 if ( dataSize
> 4096 ) {
334 // only read more if cmds take up more space than first page
336 memcpy(buffer
, firstPage
, 4096);
337 pread(fd
, &buffer
[4096], dataSize
-4096, offsetInFat
+4096);
341 unsigned int segCount
;
342 unsigned int libCount
;
343 const linkedit_data_command
* codeSigCmd
;
344 const encryption_info_command
* encryptCmd
;
345 sniffLoadCommands((const macho_header
*)fileData
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
346 // instantiate concrete class based on content of load commands
348 return ImageLoaderMachOCompressed::instantiateFromFile(path
, fd
, fileData
, dataSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, encryptCmd
, context
);
350 #if SUPPORT_CLASSIC_MACHO
351 return ImageLoaderMachOClassic::instantiateFromFile(path
, fd
, fileData
, dataSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
);
353 throw "missing LC_DYLD_INFO load command";
357 // create image by using cached mach-o file
358 ImageLoader
* ImageLoaderMachO::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, const LinkContext
& context
)
360 // instantiate right concrete class
362 unsigned int segCount
;
363 unsigned int libCount
;
364 const linkedit_data_command
* codeSigCmd
;
365 const encryption_info_command
* encryptCmd
;
366 sniffLoadCommands(mh
, path
, true, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
367 // instantiate concrete class based on content of load commands
369 return ImageLoaderMachOCompressed::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
371 #if SUPPORT_CLASSIC_MACHO
372 return ImageLoaderMachOClassic::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
374 throw "missing LC_DYLD_INFO load command";
378 // create image by copying an in-memory mach-o file
379 ImageLoader
* ImageLoaderMachO::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
, const LinkContext
& context
)
382 unsigned int segCount
;
383 unsigned int libCount
;
384 const linkedit_data_command
* sigcmd
;
385 const encryption_info_command
* encryptCmd
;
386 sniffLoadCommands(mh
, moduleName
, false, &compressed
, &segCount
, &libCount
, context
, &sigcmd
, &encryptCmd
);
387 // instantiate concrete class based on content of load commands
389 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
391 #if SUPPORT_CLASSIC_MACHO
392 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
394 throw "missing LC_DYLD_INFO load command";
399 int ImageLoaderMachO::crashIfInvalidCodeSignature()
401 // Now that segments are mapped in, try reading from first executable segment.
402 // If code signing is enabled the kernel will validate the code signature
403 // when paging in, and kill the process if invalid.
404 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
405 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
406 // return read value to ensure compiler does not optimize away load
407 int* p
= (int*)segActualLoadAddress(i
);
415 void ImageLoaderMachO::parseLoadCmds(const LinkContext
& context
)
417 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
418 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
419 // set up pointer to __LINKEDIT segment
420 if ( strcmp(segName(i
),"__LINKEDIT") == 0 ) {
421 if ( context
.codeSigningEnforced
&& (segFileOffset(i
) > fCoveredCodeLength
))
422 dyld::throwf("cannot load '%s' (segment outside of code signature)", this->getShortName());
423 fLinkEditBase
= (uint8_t*)(segActualLoadAddress(i
) - segFileOffset(i
));
425 #if TEXT_RELOC_SUPPORT
426 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
427 if ( segExecutable(i
) ) {
428 if ( segHasRebaseFixUps(i
) && (fSlide
!= 0) )
429 fTextSegmentRebases
= true;
430 if ( segHasBindFixUps(i
) )
431 fTextSegmentBinds
= true;
435 if ( segIsReadOnlyImport(i
) )
436 fReadOnlyImportSegment
= true;
438 // some segment always starts at beginning of file and contains mach_header and load commands
439 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
440 fMachOData
= (uint8_t*)(segActualLoadAddress(i
));
444 // keep count of prebound images with weak exports
445 if ( this->participatesInCoalescing() ) {
446 ++fgImagesRequiringCoalescing
;
447 fRegisteredAsRequiresCoalescing
= true;
448 if ( this->hasCoalescedExports() )
449 ++fgImagesHasWeakDefinitions
;
452 // keep count of images used in shared cache
453 if ( fInSharedCache
)
454 ++fgImagesUsedFromSharedCache
;
456 // walk load commands (mapped in at start of __TEXT segment)
457 const dyld_info_command
* dyldInfo
= NULL
;
458 const macho_nlist
* symbolTable
= NULL
;
459 const char* symbolTableStrings
= NULL
;
460 const struct load_command
* firstUnknownCmd
= NULL
;
461 const struct version_min_command
* minOSVersionCmd
= NULL
;
462 const dysymtab_command
* dynSymbolTable
= NULL
;
463 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
464 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
465 const struct load_command
* cmd
= cmds
;
466 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
470 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
471 symbolTableStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
472 symbolTable
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
476 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
478 case LC_SUB_UMBRELLA
:
479 fHasSubUmbrella
= true;
481 case LC_SUB_FRAMEWORK
:
485 fHasSubLibraries
= true;
487 case LC_ROUTINES_COMMAND
:
491 case LC_DYLD_INFO_ONLY
:
492 dyldInfo
= (struct dyld_info_command
*)cmd
;
494 case LC_SEGMENT_COMMAND
:
496 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
497 const bool isTextSeg
= (strcmp(seg
->segname
, "__TEXT") == 0);
498 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
499 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
500 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
501 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
502 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
503 fHasInitializers
= true;
504 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
505 fHasTerminators
= true;
506 else if ( type
== S_DTRACE_DOF
)
507 fHasDOFSections
= true;
508 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__eh_frame") == 0) )
509 fEHFrameSectionOffset
= (uint32_t)((uint8_t*)sect
- fMachOData
);
510 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__unwind_info") == 0) )
511 fUnwindInfoSectionOffset
= (uint32_t)((uint8_t*)sect
- fMachOData
);
515 case LC_TWOLEVEL_HINTS
:
516 // no longer supported
520 fDylibIDOffset
= (uint32_t)((uint8_t*)cmd
- fMachOData
);
524 case LC_LOAD_WEAK_DYLIB
:
525 case LC_REEXPORT_DYLIB
:
526 case LC_LOAD_UPWARD_DYLIB
:
528 // do nothing, just prevent LC_REQ_DYLD exception from occuring
530 case LC_VERSION_MIN_MACOSX
:
531 case LC_VERSION_MIN_IPHONEOS
:
532 case LC_VERSION_MIN_TVOS
:
533 case LC_VERSION_MIN_WATCHOS
:
534 minOSVersionCmd
= (version_min_command
*)cmd
;
537 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 ) {
538 if ( firstUnknownCmd
== NULL
)
539 firstUnknownCmd
= cmd
;
543 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
545 if ( firstUnknownCmd
!= NULL
) {
546 if ( minOSVersionCmd
!= NULL
) {
547 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",
548 this->getShortName(),
549 minOSVersionCmd
->version
>> 16, ((minOSVersionCmd
->version
>> 8) & 0xff),
550 firstUnknownCmd
->cmd
);
553 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd
->cmd
);
558 if ( dyldInfo
!= NULL
)
559 this->setDyldInfo(dyldInfo
);
560 if ( symbolTable
!= NULL
)
561 this->setSymbolTableInfo(symbolTable
, symbolTableStrings
, dynSymbolTable
);
565 // don't do this work in destructor because we need object to be full subclass
566 // for UnmapSegments() to work
567 void ImageLoaderMachO::destroy()
569 // update count of images with weak exports
570 if ( fRegisteredAsRequiresCoalescing
) {
571 --fgImagesRequiringCoalescing
;
572 if ( this->hasCoalescedExports() )
573 --fgImagesHasWeakDefinitions
;
576 // keep count of images used in shared cache
577 if ( fInSharedCache
)
578 --fgImagesUsedFromSharedCache
;
580 // unmap image when done
585 unsigned int ImageLoaderMachO::segmentCount() const
587 return fSegmentsCount
;
591 const macho_segment_command
* ImageLoaderMachO::segLoadCommand(unsigned int segIndex
) const
593 uint32_t* lcOffsets
= this->segmentCommandOffsets();
594 uint32_t lcOffset
= lcOffsets
[segIndex
];
595 return (macho_segment_command
*)(&fMachOData
[lcOffset
]);
598 const char* ImageLoaderMachO::segName(unsigned int segIndex
) const
600 return segLoadCommand(segIndex
)->segname
;
604 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex
) const
606 return segLoadCommand(segIndex
)->vmsize
;
610 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex
) const
612 return segLoadCommand(segIndex
)->filesize
;
616 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex
)
618 return ( segWriteable(segIndex
) && (segSize(segIndex
) > segFileSize(segIndex
)) );
622 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex
) const
624 return segLoadCommand(segIndex
)->fileoff
;
628 bool ImageLoaderMachO::segReadable(unsigned int segIndex
) const
630 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_READ
) != 0);
634 bool ImageLoaderMachO::segWriteable(unsigned int segIndex
) const
636 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_WRITE
) != 0);
640 bool ImageLoaderMachO::segExecutable(unsigned int segIndex
) const
642 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_EXECUTE
) != 0);
646 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex
) const
648 return (segLoadCommand(segIndex
)->initprot
== 0);
651 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex
) const
653 return (segLoadCommand(segIndex
)->vmaddr
!= 0);
656 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex
) const
658 return segLoadCommand(segIndex
)->vmaddr
;
661 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex
) const
663 return segLoadCommand(segIndex
)->vmaddr
+ fSlide
;
667 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex
) const
669 return segActualLoadAddress(segIndex
) + segSize(segIndex
);
672 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex
) const
674 #if TEXT_RELOC_SUPPORT
675 // scan sections for fix-up bit
676 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
677 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
678 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
679 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
680 if ( (sect
->flags
& S_ATTR_LOC_RELOC
) != 0 )
687 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex
) const
689 #if TEXT_RELOC_SUPPORT
690 // scan sections for fix-up bit
691 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
692 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
693 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
694 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
695 if ( (sect
->flags
& S_ATTR_EXT_RELOC
) != 0 )
703 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex
) const
705 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
706 return ( (segCmd
->initprot
& VM_PROT_EXECUTE
)
707 && ((segCmd
->initprot
& VM_PROT_WRITE
) == 0)
708 && (strcmp(segCmd
->segname
, "__IMPORT") == 0) );
713 void ImageLoaderMachO::UnmapSegments()
715 // usually unmap image when done
716 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) {
717 // unmap TEXT segment last because it contains load command being inspected
718 unsigned int textSegmentIndex
= 0;
719 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
720 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
721 if ( strcmp(segName(i
), "__TEXT") == 0 ) {
722 textSegmentIndex
= i
;
726 --ImageLoader::fgTotalSegmentsMapped
;
727 ImageLoader::fgTotalBytesMapped
-= segSize(i
);
728 munmap((void*)segActualLoadAddress(i
), segSize(i
));
732 --ImageLoader::fgTotalSegmentsMapped
;
733 ImageLoader::fgTotalBytesMapped
-= segSize(textSegmentIndex
);
734 munmap((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
));
739 // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
740 void ImageLoaderMachO::preFetchDATA(int fd
, uint64_t offsetInFat
, const LinkContext
& context
)
742 if ( context
.linkingMainExecutable
) {
743 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
744 if ( segWriteable(i
) && (segFileSize(i
) > 0) ) {
745 // prefetch writable segment that have mmap'ed regions
747 advice
.ra_offset
= offsetInFat
+ segFileOffset(i
);
748 advice
.ra_count
= (int)segFileSize(i
);
749 // limit prefetch to 1MB (256 pages)
750 if ( advice
.ra_count
> 1024*1024 )
751 advice
.ra_count
= 1024*1024;
752 // don't prefetch single pages, let them fault in
753 fgTotalBytesPreFetched
+= advice
.ra_count
;
754 fcntl(fd
, F_RDADVISE
, &advice
);
755 if ( context
.verboseMapping
) {
756 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n",
757 segName(i
), segActualLoadAddress(i
), segActualLoadAddress(i
)+advice
.ra_count
-1);
765 bool ImageLoaderMachO::segmentsMustSlideTogether() const
770 bool ImageLoaderMachO::segmentsCanSlide() const
772 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
775 bool ImageLoaderMachO::isBundle() const
777 const macho_header
* mh
= (macho_header
*)fMachOData
;
778 return ( mh
->filetype
== MH_BUNDLE
);
781 bool ImageLoaderMachO::isDylib() const
783 const macho_header
* mh
= (macho_header
*)fMachOData
;
784 return ( mh
->filetype
== MH_DYLIB
);
787 bool ImageLoaderMachO::isExecutable() const
789 const macho_header
* mh
= (macho_header
*)fMachOData
;
790 return ( mh
->filetype
== MH_EXECUTE
);
793 bool ImageLoaderMachO::isPositionIndependentExecutable() const
795 const macho_header
* mh
= (macho_header
*)fMachOData
;
796 return ( (mh
->filetype
== MH_EXECUTE
) && ((mh
->flags
& MH_PIE
) != 0) );
800 bool ImageLoaderMachO::forceFlat() const
802 const macho_header
* mh
= (macho_header
*)fMachOData
;
803 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
806 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
808 const macho_header
* mh
= (macho_header
*)fMachOData
;
809 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
812 bool ImageLoaderMachO::isPrebindable() const
814 const macho_header
* mh
= (macho_header
*)fMachOData
;
815 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
818 bool ImageLoaderMachO::hasCoalescedExports() const
820 const macho_header
* mh
= (macho_header
*)fMachOData
;
821 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
824 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
826 const macho_header
* mh
= (macho_header
*)fMachOData
;
827 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
830 bool ImageLoaderMachO::participatesInCoalescing() const
832 const macho_header
* mh
= (macho_header
*)fMachOData
;
833 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
834 // is reduced and it can't coalesce with other images
835 if ( this->hasHiddenExports() )
837 return ( (mh
->flags
& (MH_WEAK_DEFINES
|MH_BINDS_TO_WEAK
)) != 0 );
842 void ImageLoaderMachO::setSlide(intptr_t slide
)
847 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command
* codeSigCmd
, int fd
, uint64_t offsetInFatFile
, const LinkContext
& context
)
849 // if dylib being loaded has no code signature load command
850 if ( codeSigCmd
== NULL
) {
851 #if __MAC_OS_X_VERSION_MIN_REQUIRED
852 bool codeSigningEnforced
= context
.codeSigningEnforced
;
853 if ( context
.mainExecutableCodeSigned
&& !codeSigningEnforced
) {
854 static bool codeSignEnforcementDynamicallyEnabled
= false;
855 if ( !codeSignEnforcementDynamicallyEnabled
) {
857 if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) {
858 if ( flags
& CS_ENFORCEMENT
) {
859 codeSignEnforcementDynamicallyEnabled
= true;
863 codeSigningEnforced
= codeSignEnforcementDynamicallyEnabled
;
865 // if we require dylibs to be code signed
866 if ( codeSigningEnforced
) {
867 // if there is a non-load command based code signature, use it
868 off_t offset
= (off_t
)offsetInFatFile
;
869 if ( fcntl(fd
, F_FINDSIGS
, &offset
, sizeof(offset
)) != -1 )
871 // otherwise gracefully return from dlopen()
872 dyld::throwf("required code signature missing for '%s'\n", this->getPath());
875 //Since we don't have a range for the signature we have to assume full coverage
876 fCoveredCodeLength
= UINT64_MAX
;
879 #if __MAC_OS_X_VERSION_MIN_REQUIRED
880 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools
881 if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9
) {
885 fsignatures_t siginfo
;
886 siginfo
.fs_file_start
=offsetInFatFile
; // start of mach-o slice in fat file
887 siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
); // start of CD in mach-o file
888 siginfo
.fs_blob_size
=codeSigCmd
->datasize
; // size of CD
889 int result
= fcntl(fd
, F_ADDFILESIGS_RETURN
, &siginfo
);
891 #if TARGET_IPHONE_SIMULATOR
892 // rdar://problem/18759224> check range covered by the code directory after loading
893 // Attempt to fallback only if we are in the simulator
895 if ( result
== -1 ) {
896 result
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
);
897 siginfo
.fs_file_start
= codeSigCmd
->dataoff
;
901 if ( result
== -1 ) {
902 if ( (errno
== EPERM
) || (errno
== EBADEXEC
) )
903 dyld::throwf("code signature invalid for '%s'\n", this->getPath());
904 if ( context
.verboseCodeSignatures
)
905 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno
);
906 siginfo
.fs_file_start
= UINT64_MAX
;
907 } else if ( context
.verboseCodeSignatures
) {
908 dyld::log("dyld: Registered code signature for %s\n", this->getPath());
910 fCoveredCodeLength
= siginfo
.fs_file_start
;
914 void ImageLoaderMachO::validateFirstPages(const struct linkedit_data_command
* codeSigCmd
, int fd
, const uint8_t *fileData
, size_t lenFileData
, off_t offsetInFat
, const LinkContext
& context
)
916 #if __MAC_OS_X_VERSION_MIN_REQUIRED
917 // rdar://problem/21839703> 15A226d: dyld crashes in mageLoaderMachO::validateFirstPages during dlopen() after encountering an mmap failure
918 // We need to ignore older code signatures because they will be bad.
919 if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9
) {
923 if (codeSigCmd
!= NULL
) {
924 if ( context
.verboseMapping
)
925 dyld::log("dyld: validate pages: %llu\n", (unsigned long long)offsetInFat
);
927 void *fdata
= xmmap(NULL
, lenFileData
, PROT_READ
| PROT_EXEC
, MAP_SHARED
, fd
, offsetInFat
);
928 if ( fdata
== MAP_FAILED
) {
929 if ( context
.processRequiresLibraryValidation
)
930 dyld::throwf("cannot load image with wrong team ID in process using Library Validation");
932 dyld::throwf("mmap() errno=%d validating first page of '%s'", errno
, getInstallPath());
934 if ( memcmp(fdata
, fileData
, lenFileData
) != 0 )
935 dyld::throwf("mmap() page compare failed for '%s'", getInstallPath());
936 munmap(fdata
, lenFileData
);
941 const char* ImageLoaderMachO::getInstallPath() const
943 if ( fDylibIDOffset
!= 0 ) {
944 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
945 return (char*)dylibID
+ dylibID
->dylib
.name
.offset
;
950 void ImageLoaderMachO::registerInterposing()
952 // mach-o files advertise interposing by having a __DATA __interpose section
953 struct InterposeData
{ uintptr_t replacement
; uintptr_t replacee
; };
954 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
955 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
956 const struct load_command
* cmd
= cmds
;
957 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
959 case LC_SEGMENT_COMMAND
:
961 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
962 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
963 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
964 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
965 if ( ((sect
->flags
& SECTION_TYPE
) == S_INTERPOSING
) || ((strcmp(sect
->sectname
, "__interpose") == 0) && (strcmp(seg
->segname
, "__DATA") == 0)) ) {
966 const InterposeData
* interposeArray
= (InterposeData
*)(sect
->addr
+ fSlide
);
967 const size_t count
= sect
->size
/ sizeof(InterposeData
);
968 for (size_t i
=0; i
< count
; ++i
) {
969 ImageLoader::InterposeTuple tuple
;
970 tuple
.replacement
= interposeArray
[i
].replacement
;
971 tuple
.neverImage
= this;
972 tuple
.onlyImage
= NULL
;
973 tuple
.replacee
= interposeArray
[i
].replacee
;
974 // <rdar://problem/7937695> verify that replacement is in this image
975 if ( this->containsAddress((void*)tuple
.replacement
) ) {
976 // chain to any existing interpositions
977 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it
!= fgInterposingTuples
.end(); it
++) {
978 if ( it
->replacee
== tuple
.replacee
) {
979 tuple
.replacee
= it
->replacement
;
982 ImageLoader::fgInterposingTuples
.push_back(tuple
);
990 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
994 uint32_t ImageLoaderMachO::sdkVersion() const
996 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
997 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
998 const struct load_command
* cmd
= cmds
;
999 const struct version_min_command
* versCmd
;
1000 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1001 switch ( cmd
->cmd
) {
1002 case LC_VERSION_MIN_MACOSX
:
1003 case LC_VERSION_MIN_IPHONEOS
:
1004 case LC_VERSION_MIN_TVOS
:
1005 case LC_VERSION_MIN_WATCHOS
:
1006 versCmd
= (version_min_command
*)cmd
;
1007 return versCmd
->sdk
;
1009 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1014 uint32_t ImageLoaderMachO::minOSVersion(const mach_header
* mh
)
1016 const uint32_t cmd_count
= mh
->ncmds
;
1017 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
));
1018 const struct load_command
* cmd
= cmds
;
1019 const struct version_min_command
* versCmd
;
1020 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1021 switch ( cmd
->cmd
) {
1022 case LC_VERSION_MIN_MACOSX
:
1023 case LC_VERSION_MIN_IPHONEOS
:
1024 case LC_VERSION_MIN_TVOS
:
1025 case LC_VERSION_MIN_WATCHOS
:
1026 versCmd
= (version_min_command
*)cmd
;
1027 return versCmd
->version
;
1029 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1034 uint32_t ImageLoaderMachO::minOSVersion() const
1036 return ImageLoaderMachO::minOSVersion(machHeader());
1040 void* ImageLoaderMachO::getThreadPC() const
1042 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1043 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1044 const struct load_command
* cmd
= cmds
;
1045 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1046 if ( cmd
->cmd
== LC_MAIN
) {
1047 entry_point_command
* mainCmd
= (entry_point_command
*)cmd
;
1048 void* entry
= (void*)(mainCmd
->entryoff
+ (char*)fMachOData
);
1049 // <rdar://problem/8543820&9228031> verify entry point is in image
1050 if ( this->containsAddress(entry
) )
1053 throw "LC_MAIN entryoff is out of range";
1055 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1061 void* ImageLoaderMachO::getMain() const
1063 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1064 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1065 const struct load_command
* cmd
= cmds
;
1066 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1071 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
1072 void* entry
= (void*)(registers
->eip
+ fSlide
);
1074 const x86_thread_state64_t
* registers
= (x86_thread_state64_t
*)(((char*)cmd
) + 16);
1075 void* entry
= (void*)(registers
->rip
+ fSlide
);
1077 const arm_thread_state_t
* registers
= (arm_thread_state_t
*)(((char*)cmd
) + 16);
1078 void* entry
= (void*)(registers
->__pc
+ fSlide
);
1080 const arm_thread_state64_t
* registers
= (arm_thread_state64_t
*)(((char*)cmd
) + 16);
1081 void* entry
= (void*)(registers
->__pc
+ fSlide
);
1083 #warning need processor specific code
1085 // <rdar://problem/8543820&9228031> verify entry point is in image
1086 if ( this->containsAddress(entry
) ) {
1092 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1094 throw "no valid entry point";
1097 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount
, const macho_header
* mh
)
1099 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
1103 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
1104 if ( mh
->filetype
== MH_EXECUTE
)
1107 bool isNonOSdylib
= false;
1108 const uint32_t cmd_count
= mh
->ncmds
;
1109 const struct load_command
* const cmds
= (struct load_command
*)((uint8_t*)mh
+sizeof(macho_header
));
1110 const struct load_command
* cmd
= cmds
;
1111 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1114 case LC_LOAD_WEAK_DYLIB
:
1115 case LC_REEXPORT_DYLIB
:
1116 case LC_LOAD_UPWARD_DYLIB
:
1120 const dylib_command
* dylibID
= (dylib_command
*)cmd
;
1121 const char* installPath
= (char*)cmd
+ dylibID
->dylib
.name
.offset
;
1122 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents
1123 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
1124 // <rdar://problem/6497528> rosetta circular dependency spew
1125 isNonOSdylib
= ( (strncmp(installPath
, "/usr/lib/", 9) != 0) && (strncmp(installPath
, "/usr/libexec/oah/Shims", 9) != 0) );
1129 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1131 return isNonOSdylib
;
1135 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[])
1137 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) {
1138 DependentLibraryInfo
* lib
= &libs
[0];
1139 lib
->name
= "/usr/lib/libSystem.B.dylib";
1140 lib
->info
.checksum
= 0;
1141 lib
->info
.minVersion
= 0;
1142 lib
->info
.maxVersion
= 0;
1143 lib
->required
= false;
1144 lib
->reExported
= false;
1145 lib
->upward
= false;
1149 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1150 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1151 const struct load_command
* cmd
= cmds
;
1152 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1155 case LC_LOAD_WEAK_DYLIB
:
1156 case LC_REEXPORT_DYLIB
:
1157 case LC_LOAD_UPWARD_DYLIB
:
1159 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
1160 DependentLibraryInfo
* lib
= &libs
[index
++];
1161 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
1162 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1163 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
1164 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
1165 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
1166 lib
->required
= (cmd
->cmd
!= LC_LOAD_WEAK_DYLIB
);
1167 lib
->reExported
= (cmd
->cmd
== LC_REEXPORT_DYLIB
);
1168 lib
->upward
= (cmd
->cmd
== LC_LOAD_UPWARD_DYLIB
);
1172 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1177 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo()
1180 if ( fDylibIDOffset
!= 0 ) {
1181 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
1182 info
.minVersion
= dylibID
->dylib
.compatibility_version
;
1183 info
.maxVersion
= dylibID
->dylib
.current_version
;
1184 info
.checksum
= dylibID
->dylib
.timestamp
;
1187 info
.minVersion
= 0;
1188 info
.maxVersion
= 0;
1194 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const
1196 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1197 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1198 const struct load_command
* cmd
= cmds
;
1199 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1202 const char* pathToAdd
= NULL
;
1203 const char* path
= (char*)cmd
+ ((struct rpath_command
*)cmd
)->path
.offset
;
1204 if ( (strncmp(path
, "@loader_path", 12) == 0) && ((path
[12] == '/') || (path
[12] == '\0')) ) {
1205 if ( context
.processIsRestricted
&& !context
.processRequiresLibraryValidation
&& (context
.mainExecutable
== this) ) {
1206 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path
, this->getPath());
1209 char resolvedPath
[PATH_MAX
];
1210 if ( realpath(this->getPath(), resolvedPath
) != NULL
) {
1211 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1212 strcpy(newRealPath
, resolvedPath
);
1213 char* addPoint
= strrchr(newRealPath
,'/');
1214 if ( addPoint
!= NULL
) {
1215 strcpy(addPoint
, &path
[12]);
1216 pathToAdd
= strdup(newRealPath
);
1220 else if ( (strncmp(path
, "@executable_path", 16) == 0) && ((path
[16] == '/') || (path
[16] == '\0')) ) {
1221 if ( context
.processIsRestricted
&& !context
.processRequiresLibraryValidation
) {
1222 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path
, this->getPath());
1225 char resolvedPath
[PATH_MAX
];
1226 if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL
) {
1227 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1228 strcpy(newRealPath
, resolvedPath
);
1229 char* addPoint
= strrchr(newRealPath
,'/');
1230 if ( addPoint
!= NULL
) {
1231 strcpy(addPoint
, &path
[16]);
1232 pathToAdd
= strdup(newRealPath
);
1236 else if ( (path
[0] != '/') && context
.processIsRestricted
&& !context
.processRequiresLibraryValidation
) {
1237 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path
, this->getPath());
1240 else if ( (path
[0] == '/') && (context
.rootPaths
!= NULL
) ) {
1241 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
1242 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
1244 for(const char** rp
= context
.rootPaths
; *rp
!= NULL
; ++rp
) {
1245 char newPath
[PATH_MAX
];
1246 strlcpy(newPath
, *rp
, PATH_MAX
);
1247 strlcat(newPath
, path
, PATH_MAX
);
1248 struct stat stat_buf
;
1249 if ( stat(newPath
, &stat_buf
) != -1 ) {
1250 //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
1251 pathToAdd
= strdup(newPath
);
1257 // make copy so that all elements of 'paths' can be freed
1258 pathToAdd
= strdup(path
);
1262 // make copy so that all elements of 'paths' can be freed
1263 pathToAdd
= strdup(path
);
1265 if ( pathToAdd
!= NULL
)
1266 paths
.push_back(pathToAdd
);
1269 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1274 bool ImageLoaderMachO::getUUID(uuid_t uuid
) const
1276 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1277 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1278 const struct load_command
* cmd
= cmds
;
1279 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1282 uuid_command
* uc
= (uuid_command
*)cmd
;
1283 memcpy(uuid
, uc
->uuid
, 16);
1286 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1292 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1294 // if prebound and loaded at prebound address, then no need to rebase
1295 if ( this->usablePrebinding(context
) ) {
1296 // skip rebasing because prebinding is valid
1297 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1301 // print why prebinding was not used
1302 if ( context
.verbosePrebinding
) {
1303 if ( !this->isPrebindable() ) {
1304 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1306 else if ( fSlide
!= 0 ) {
1307 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1309 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1310 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1312 else if ( !this->usesTwoLevelNameSpace() ){
1313 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1316 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1320 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1322 #if PREBOUND_IMAGE_SUPPORT
1323 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1324 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1325 if ( this->isPrebindable() && !fInSharedCache
)
1326 this->resetPreboundLazyPointers(context
);
1329 // if loaded at preferred address, no rebasing necessary
1330 if ( this->fSlide
== 0 )
1333 #if TEXT_RELOC_SUPPORT
1334 // if there are __TEXT fixups, temporarily make __TEXT writable
1335 if ( fTextSegmentRebases
)
1336 this->makeTextSegmentWritable(context
, true);
1339 // do actual rebasing
1340 this->rebase(context
);
1342 #if TEXT_RELOC_SUPPORT
1343 // if there were __TEXT fixups, restore write protection
1344 if ( fTextSegmentRebases
)
1345 this->makeTextSegmentWritable(context
, false);
1350 #if TEXT_RELOC_SUPPORT
1351 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext
& context
, bool writeable
)
1353 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1354 if ( segExecutable(i
) ) {
1356 segMakeWritable(i
, context
);
1359 #if !__i386__ && !__x86_64__
1360 // some processors require range to be invalidated before it is made executable
1361 sys_icache_invalidate((void*)segActualLoadAddress(i
), segSize(textSegmentIndex
));
1363 segProtect(i
, context
);
1371 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, bool searchReExports
, const ImageLoader
** foundIn
) const
1373 // look in this image first
1374 const ImageLoader::Symbol
* result
= this->findExportedSymbol(name
, foundIn
);
1375 if ( result
!= NULL
)
1378 if ( searchReExports
) {
1379 for(unsigned int i
=0; i
< libraryCount(); ++i
){
1380 if ( libReExported(i
) ) {
1381 ImageLoader
* image
= libImage(i
);
1382 if ( image
!= NULL
) {
1383 const Symbol
* result
= image
->findExportedSymbol(name
, searchReExports
, foundIn
);
1384 if ( result
!= NULL
)
1397 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
1398 const ImageLoader
* requestor
, bool runResolver
) const
1400 return this->getSymbolAddress(sym
, requestor
, context
, runResolver
);
1403 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol
* sym
, const ImageLoader
* requestor
,
1404 const LinkContext
& context
, bool runResolver
) const
1406 uintptr_t result
= exportedSymbolAddress(context
, sym
, requestor
, runResolver
);
1407 // check for interposing overrides
1408 result
= interposedAddress(context
, result
, requestor
);
1412 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1414 if ( exportedSymbolIsWeakDefintion(sym
) )
1415 return kWeakDefinition
;
1417 return kNoDefinitionOptions
;
1420 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1422 return exportedSymbolName(sym
);
1425 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1427 return exportedSymbolCount();
1431 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1433 return exportedSymbolIndexed(index
);
1437 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1439 return importedSymbolCount();
1443 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1445 return importedSymbolIndexed(index
);
1449 ImageLoader::ReferenceFlags
ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1451 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1456 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1458 return importedSymbolName(sym
);
1462 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
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_SEGMENT_COMMAND
:
1471 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1472 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1473 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1474 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1475 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1476 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1477 *length
= sect
->size
;
1484 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1491 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections
* info
)
1493 info
->mh
= this->machHeader();
1494 info
->dwarf_section
= 0;
1495 info
->dwarf_section_length
= 0;
1496 info
->compact_unwind_section
= 0;
1497 info
->compact_unwind_section_length
= 0;
1498 if ( fEHFrameSectionOffset
!= 0 ) {
1499 const macho_section
* sect
= (macho_section
*)&fMachOData
[fEHFrameSectionOffset
];
1500 info
->dwarf_section
= (void*)(sect
->addr
+ fSlide
);
1501 info
->dwarf_section_length
= sect
->size
;
1503 if ( fUnwindInfoSectionOffset
!= 0 ) {
1504 const macho_section
* sect
= (macho_section
*)&fMachOData
[fUnwindInfoSectionOffset
];
1505 info
->compact_unwind_section
= (void*)(sect
->addr
+ fSlide
);
1506 info
->compact_unwind_section_length
= sect
->size
;
1511 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1513 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1514 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1515 const struct load_command
* cmd
= cmds
;
1516 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1517 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1519 case LC_SEGMENT_COMMAND
:
1521 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1522 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1523 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1524 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1525 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1526 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1527 if ( segmentName
!= NULL
)
1528 *segmentName
= sect
->segname
;
1529 if ( sectionName
!= NULL
)
1530 *sectionName
= sect
->sectname
;
1531 if ( sectionOffset
!= NULL
)
1532 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1540 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1546 void __attribute__((noreturn
)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext
& context
, const char* symbol
,
1547 const char* referencedFrom
, const char* fromVersMismatch
,
1548 const char* expectedIn
)
1550 // record values for possible use by CrashReporter or Finder
1551 (*context
.setErrorStrings
)(dyld_error_kind_symbol_missing
, referencedFrom
, expectedIn
, symbol
);
1552 dyld::throwf("Symbol not found: %s\n Referenced from: %s%s\n Expected in: %s\n",
1553 symbol
, referencedFrom
, fromVersMismatch
, expectedIn
);
1556 const mach_header
* ImageLoaderMachO::machHeader() const
1558 return (mach_header
*)fMachOData
;
1561 uintptr_t ImageLoaderMachO::getSlide() const
1566 // hmm. maybe this should be up in ImageLoader??
1567 const void* ImageLoaderMachO::getEnd() const
1569 uintptr_t lastAddress
= 0;
1570 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1571 uintptr_t segEnd
= segActualEndAddress(i
);
1572 if ( strcmp(segName(i
), "__UNIXSTACK") != 0 ) {
1573 if ( segEnd
> lastAddress
)
1574 lastAddress
= segEnd
;
1577 return (const void*)lastAddress
;
1581 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext
& context
, uintptr_t location
, uintptr_t value
,
1582 const ImageLoader
* targetImage
, uint8_t type
, const char* symbolName
,
1583 intptr_t addend
, const char* msg
)
1586 if ( context
.verboseBind
) {
1588 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1589 msg
, this->getShortName(), (uintptr_t)location
,
1590 ((targetImage
!= NULL
) ? targetImage
->getShortName() : "<weak_import-missing>"),
1591 symbolName
, (uintptr_t)location
, value
, addend
);
1593 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1594 msg
, this->getShortName(), (uintptr_t)location
,
1595 ((targetImage
!= NULL
) ? targetImage
->getShortName() : "<weak>import-missing>"),
1596 symbolName
, (uintptr_t)location
, value
);
1599 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
1603 uintptr_t* locationToFix
= (uintptr_t*)location
;
1605 uintptr_t newValue
= value
+addend
;
1608 case BIND_TYPE_POINTER
:
1609 // test first so we don't needless dirty pages
1610 if ( *locationToFix
!= newValue
)
1611 *locationToFix
= newValue
;
1613 case BIND_TYPE_TEXT_ABSOLUTE32
:
1614 loc32
= (uint32_t*)locationToFix
;
1615 value32
= (uint32_t)newValue
;
1616 if ( *loc32
!= value32
)
1619 case BIND_TYPE_TEXT_PCREL32
:
1620 loc32
= (uint32_t*)locationToFix
;
1621 value32
= (uint32_t)(newValue
- (((uintptr_t)locationToFix
) + 4));
1622 if ( *loc32
!= value32
)
1626 dyld::throwf("bad bind type %d", type
);
1629 // update statistics
1630 ++fgTotalBindFixups
;
1639 #if SUPPORT_OLD_CRT_INITIALIZATION
1640 // first 16 bytes of "start" in crt1.o
1642 static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
1647 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper
1648 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
1649 // the following only exist in main executables built for 10.5 or later
1653 // These are defined in dyldStartup.s
1654 extern "C" void stub_binding_helper();
1657 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
1659 const macho_header
* mh
= (macho_header
*)fMachOData
;
1660 const uint32_t cmd_count
= mh
->ncmds
;
1661 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1662 const struct load_command
* cmd
;
1663 // There used to be some optimizations to skip this section scan, but we need to handle the
1664 // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
1665 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
1668 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1669 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1670 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1671 if ( strncmp(seg
->segname
, "__DATA", 6) == 0 ) {
1672 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1673 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1674 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1675 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) {
1676 struct DATAdyld
* dd
= (struct DATAdyld
*)(sect
->addr
+ fSlide
);
1677 #if !__arm64__ && !__ARM_ARCH_7K__
1678 if ( sect
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
1679 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
1680 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
1682 #endif // !__arm64__
1683 if ( sect
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
1684 if ( dd
->dyldFuncLookup
!= (void*)&_dyld_func_lookup
)
1685 dd
->dyldFuncLookup
= (void*)&_dyld_func_lookup
;
1687 if ( mh
->filetype
== MH_EXECUTE
) {
1688 // there are two ways to get the program variables
1689 if ( (sect
->size
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh
== mh
) ) {
1690 // some really old binaries have space for vars, but it is zero filled
1691 // main executable has 10.5 style __dyld section that has program variable pointers
1692 context
.setNewProgramVars(dd
->vars
);
1695 // main executable is pre-10.5 and requires the symbols names to be looked up
1696 this->lookupProgramVars(context
);
1697 #if SUPPORT_OLD_CRT_INITIALIZATION
1698 // If the first 16 bytes of the entry point's instructions do not
1699 // match what crt1.o supplies, then the program has a custom entry point.
1700 // This means it might be doing something that needs to be executed before
1701 // initializers are run.
1702 if ( memcmp(this->getMain(), sStandardEntryPointInstructions
, 16) != 0 ) {
1703 if ( context
.verboseInit
)
1704 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
1705 context
.setRunInitialzersOldWay();
1710 else if ( mh
->filetype
== MH_DYLIB
) {
1711 const char* installPath
= this->getInstallPath();
1712 if ( (installPath
!= NULL
) && (strncmp(installPath
, "/usr/lib/", 9) == 0) ) {
1713 if ( sect
->size
> offsetof(DATAdyld
, vars
) ) {
1714 // use ProgramVars from libdyld.dylib but tweak mh field to correct value
1715 dd
->vars
.mh
= context
.mainExecutable
->machHeader();
1716 context
.setNewProgramVars(dd
->vars
);
1721 else if ( (strcmp(sect
->sectname
, "__program_vars" ) == 0) && (mh
->filetype
== MH_EXECUTE
) ) {
1722 // this is a Mac OS X 10.6 or later main executable
1723 struct ProgramVars
* pv
= (struct ProgramVars
*)(sect
->addr
+ fSlide
);
1724 context
.setNewProgramVars(*pv
);
1729 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1735 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const
1737 ProgramVars vars
= context
.programVars
;
1738 const ImageLoader::Symbol
* sym
;
1740 // get mach header directly
1741 vars
.mh
= (macho_header
*)fMachOData
;
1744 sym
= this->findExportedSymbol("_NXArgc", false, NULL
);
1746 vars
.NXArgcPtr
= (int*)this->getExportedSymbolAddress(sym
, context
, this, false);
1749 sym
= this->findExportedSymbol("_NXArgv", false, NULL
);
1751 vars
.NXArgvPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false);
1754 sym
= this->findExportedSymbol("_environ", false, NULL
);
1756 vars
.environPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false);
1758 // lookup __progname
1759 sym
= this->findExportedSymbol("___progname", false, NULL
);
1761 vars
.__prognamePtr
= (const char**)this->getExportedSymbolAddress(sym
, context
, this, false);
1763 context
.setNewProgramVars(vars
);
1767 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
1769 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
1770 if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache
)
1771 && this->usesTwoLevelNameSpace()
1772 && this->allDependentLibrariesAsWhenPreBound() ) {
1773 // allow environment variables to disable prebinding
1774 if ( context
.bindFlat
)
1776 switch ( context
.prebindUsage
) {
1777 case kUseAllPrebinding
:
1779 case kUseSplitSegPrebinding
:
1780 return this->fIsSplitSeg
;
1781 case kUseAllButAppPredbinding
:
1782 return (this != context
.mainExecutable
);
1783 case kUseNoPrebinding
:
1791 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
1793 if ( fHasDashInit
) {
1794 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1795 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1796 const struct load_command
* cmd
= cmds
;
1797 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1799 case LC_ROUTINES_COMMAND
:
1800 Initializer func
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address
+ fSlide
);
1801 // <rdar://problem/8543820&9228031> verify initializers are in image
1802 if ( ! this->containsAddress((void*)func
) ) {
1803 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
1805 if ( context
.verboseInit
)
1806 dyld::log("dyld: calling -init function %p in %s\n", func
, this->getPath());
1807 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
1810 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1815 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
1817 if ( fHasInitializers
) {
1818 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1819 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1820 const struct load_command
* cmd
= cmds
;
1821 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1822 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1823 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1824 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1825 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1826 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1827 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1828 if ( type
== S_MOD_INIT_FUNC_POINTERS
) {
1829 Initializer
* inits
= (Initializer
*)(sect
->addr
+ fSlide
);
1830 const size_t count
= sect
->size
/ sizeof(uintptr_t);
1831 for (size_t i
=0; i
< count
; ++i
) {
1832 Initializer func
= inits
[i
];
1833 // <rdar://problem/8543820&9228031> verify initializers are in image
1834 if ( ! this->containsAddress((void*)func
) ) {
1835 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
1837 if ( context
.verboseInit
)
1838 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath());
1839 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
1844 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1854 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
)
1856 if ( fHasDOFSections
) {
1857 // walk load commands (mapped in at start of __TEXT segment)
1858 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1859 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1860 const struct load_command
* cmd
= cmds
;
1861 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1863 case LC_SEGMENT_COMMAND
:
1865 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1866 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1867 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1868 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1869 if ( (sect
->flags
& SECTION_TYPE
) == S_DTRACE_DOF
) {
1870 ImageLoader::DOFInfo info
;
1871 info
.dof
= (void*)(sect
->addr
+ fSlide
);
1872 info
.imageHeader
= this->machHeader();
1873 info
.imageShortName
= this->getShortName();
1874 dofs
.push_back(info
);
1880 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1886 bool ImageLoaderMachO::doInitialization(const LinkContext
& context
)
1888 CRSetCrashLogMessage2(this->getPath());
1890 // mach-o has -init and static initializers
1891 doImageInit(context
);
1892 doModInitFunctions(context
);
1894 CRSetCrashLogMessage2(NULL
);
1896 return (fHasDashInit
|| fHasInitializers
);
1899 bool ImageLoaderMachO::needsInitialization()
1901 return ( fHasDashInit
|| fHasInitializers
);
1905 bool ImageLoaderMachO::needsTermination()
1907 return fHasTerminators
;
1911 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
1913 if ( fHasTerminators
) {
1914 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1915 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1916 const struct load_command
* cmd
= cmds
;
1917 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1918 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1919 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1920 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1921 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1922 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1923 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
1924 if ( type
== S_MOD_TERM_FUNC_POINTERS
) {
1925 Terminator
* terms
= (Terminator
*)(sect
->addr
+ fSlide
);
1926 const size_t count
= sect
->size
/ sizeof(uintptr_t);
1927 for (size_t i
=count
; i
> 0; --i
) {
1928 Terminator func
= terms
[i
-1];
1929 // <rdar://problem/8543820&9228031> verify terminators are in image
1930 if ( ! this->containsAddress((void*)func
) ) {
1931 dyld::throwf("termination function %p not in mapped image for %s\n", func
, this->getPath());
1933 if ( context
.verboseInit
)
1934 dyld::log("dyld: calling termination function %p in %s\n", func
, this->getPath());
1940 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1946 void ImageLoaderMachO::printStatistics(unsigned int imageCount
, const InitializerTimingList
& timingInfo
)
1948 ImageLoader::printStatistics(imageCount
, timingInfo
);
1949 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs
);
1950 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs
);
1951 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions
);
1952 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing
);
1956 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext
& context
)
1958 // preflight and calculate slide if needed
1959 const bool inPIE
= (fgNextPIEDylibAddress
!= 0);
1961 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
1962 bool needsToSlide
= false;
1963 bool imageHasPreferredLoadAddress
= segHasPreferredLoadAddress(0);
1964 uintptr_t lowAddr
= (unsigned long)(-1);
1965 uintptr_t highAddr
= 0;
1966 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1967 const uintptr_t segLow
= segPreferredLoadAddress(i
);
1968 const uintptr_t segHigh
= dyld_page_round(segLow
+ segSize(i
));
1969 if ( segLow
< highAddr
) {
1970 if ( dyld_page_size
> 4096 )
1971 dyld::throwf("can't map segments into 16KB pages");
1973 dyld::throwf("overlapping segments");
1975 if ( segLow
< lowAddr
)
1977 if ( segHigh
> highAddr
)
1980 if ( needsToSlide
|| !imageHasPreferredLoadAddress
|| inPIE
|| !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
1981 needsToSlide
= true;
1983 if ( needsToSlide
) {
1984 // find a chunk of address space to hold all segments
1985 uintptr_t addr
= reserveAnAddressRange(highAddr
-lowAddr
, context
);
1986 slide
= addr
- lowAddr
;
1989 else if ( ! this->segmentsCanSlide() ) {
1990 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1991 if ( strcmp(segName(i
), "__PAGEZERO") == 0 )
1993 if ( !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
1994 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i
), segPreferredLoadAddress(i
), segSize(i
));
1998 throw "mach-o does not support independently sliding segments";
2004 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
)
2006 vm_address_t addr
= 0;
2007 vm_size_t size
= length
;
2008 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
2009 if ( fgNextPIEDylibAddress
!= 0 ) {
2010 // add small (0-3 pages) random padding between dylibs
2011 addr
= fgNextPIEDylibAddress
+ (__stack_chk_guard
/fgNextPIEDylibAddress
& (sizeof(long)-1))*dyld_page_size
;
2012 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
2013 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2014 if ( r
== KERN_SUCCESS
) {
2015 fgNextPIEDylibAddress
= addr
+ size
;
2018 fgNextPIEDylibAddress
= 0;
2020 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2021 if ( r
!= KERN_SUCCESS
)
2022 throw "out of address space";
2027 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start
, size_t length
)
2029 vm_address_t addr
= start
;
2030 vm_size_t size
= length
;
2031 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2032 if ( r
!= KERN_SUCCESS
)
2039 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
2041 // find address range for image
2042 intptr_t slide
= this->assignSegmentAddresses(context
);
2043 if ( context
.verboseMapping
) {
2044 if ( offsetInFat
!= 0 )
2045 dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat
);
2047 dyld::log("dyld: Mapping %s\n", this->getPath());
2049 // map in all segments
2050 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2051 vm_offset_t fileOffset
= segFileOffset(i
) + offsetInFat
;
2052 vm_size_t size
= segFileSize(i
);
2053 uintptr_t requestedLoadAddress
= segPreferredLoadAddress(i
) + slide
;
2055 if ( !segUnaccessible(i
) ) {
2056 // If has text-relocs, don't set x-bit initially.
2057 // Instead set it later after text-relocs have been done.
2058 if ( segExecutable(i
) && !(segHasRebaseFixUps(i
) && (slide
!= 0)) )
2059 protection
|= PROT_EXEC
;
2060 if ( segReadable(i
) )
2061 protection
|= PROT_READ
;
2062 if ( segWriteable(i
) )
2063 protection
|= PROT_WRITE
;
2066 // initially map __IMPORT segments R/W so dyld can update them
2067 if ( segIsReadOnlyImport(i
) )
2068 protection
|= PROT_WRITE
;
2070 // wholly zero-fill segments have nothing to mmap() in
2072 if ( (fileOffset
+size
) > fileLen
) {
2073 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
2074 segName(i
), (uint64_t)(fileOffset
+size
), fileLen
);
2076 void* loadAddress
= xmmap((void*)requestedLoadAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, fileOffset
);
2077 if ( loadAddress
== ((void*)(-1)) ) {
2078 dyld::throwf("mmap() error %d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
2079 errno
, requestedLoadAddress
, (uintptr_t)size
, segName(i
), getPath());
2083 ++ImageLoader::fgTotalSegmentsMapped
;
2084 ImageLoader::fgTotalBytesMapped
+= size
;
2085 if ( context
.verboseMapping
)
2086 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i
), requestedLoadAddress
, requestedLoadAddress
+size
-1,
2087 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2090 // update slide to reflect load location
2091 this->setSlide(slide
);
2094 void ImageLoaderMachO::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
)
2096 // find address range for image
2097 intptr_t slide
= this->assignSegmentAddresses(context
);
2098 if ( context
.verboseMapping
)
2099 dyld::log("dyld: Mapping memory %p\n", memoryImage
);
2100 // map in all segments
2101 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2102 vm_address_t loadAddress
= segPreferredLoadAddress(i
) + slide
;
2103 vm_address_t srcAddr
= (uintptr_t)memoryImage
+ segFileOffset(i
);
2104 vm_size_t size
= segFileSize(i
);
2105 kern_return_t r
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
);
2106 if ( r
!= KERN_SUCCESS
)
2107 throw "can't map segment";
2108 if ( context
.verboseMapping
)
2109 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i
), (uintptr_t)loadAddress
, (uintptr_t)loadAddress
+size
-1);
2111 // update slide to reflect load location
2112 this->setSlide(slide
);
2113 // set R/W permissions on all segments at slide location
2114 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2115 segProtect(i
, context
);
2120 void ImageLoaderMachO::segProtect(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
2122 vm_prot_t protection
= 0;
2123 if ( !segUnaccessible(segIndex
) ) {
2124 if ( segExecutable(segIndex
) )
2125 protection
|= PROT_EXEC
;
2126 if ( segReadable(segIndex
) )
2127 protection
|= PROT_READ
;
2128 if ( segWriteable(segIndex
) )
2129 protection
|= PROT_WRITE
;
2131 vm_address_t addr
= segActualLoadAddress(segIndex
);
2132 vm_size_t size
= segSize(segIndex
);
2133 const bool setCurrentPermissions
= false;
2134 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
2135 if ( r
!= KERN_SUCCESS
) {
2136 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2137 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
2139 if ( context
.verboseMapping
) {
2140 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,
2141 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2145 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
2147 vm_address_t addr
= segActualLoadAddress(segIndex
);
2148 vm_size_t size
= segSize(segIndex
);
2149 const bool setCurrentPermissions
= false;
2150 vm_prot_t protection
= VM_PROT_WRITE
| VM_PROT_READ
;
2151 if ( segExecutable(segIndex
) && !segHasRebaseFixUps(segIndex
) )
2152 protection
|= VM_PROT_EXECUTE
;
2153 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
2154 if ( r
!= KERN_SUCCESS
) {
2155 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2156 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
2158 if ( context
.verboseMapping
) {
2159 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,
2160 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );