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 <mach-o/dyld_images.h>
43 #include <sys/sysctl.h>
44 #include <sys/syscall.h>
45 #include <libkern/OSAtomic.h>
46 #include <libkern/OSCacheControl.h>
48 #include <System/sys/codesign.h>
50 #if __has_feature(ptrauth_calls)
54 #include "ImageLoaderMachO.h"
55 #include "ImageLoaderMachOCompressed.h"
56 #if SUPPORT_CLASSIC_MACHO
57 #include "ImageLoaderMachOClassic.h"
62 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs
63 extern "C" long __stack_chk_guard
;
65 #define LIBSYSTEM_DYLIB_PATH "/usr/lib/libSystem.B.dylib"
66 #define LIBDYLD_DYLIB_PATH "/usr/lib/system/libdyld.dylib"
68 #define DRIVERKIT_LIBSYSTEM_DYLIB_PATH "/System/DriverKit/usr/lib/libSystem.dylib"
69 #define DRIVERKIT_LIBDYLD_DYLIB_PATH "/System/DriverKit/usr/lib/system/libdyld.dylib"
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;
92 ImageLoaderMachO::ImageLoaderMachO(const macho_header
* mh
, const char* path
, unsigned int segCount
,
93 uint32_t segOffsets
[], unsigned int libCount
)
94 : ImageLoader(path
, libCount
), fCoveredCodeLength(0), fMachOData((uint8_t*)mh
), fLinkEditBase(NULL
), fSlide(0),
95 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
96 fSegmentsCount(segCount
), fIsSplitSeg(false), fInSharedCache(false),
97 #if TEXT_RELOC_SUPPORT
98 fTextSegmentRebases(false),
99 fTextSegmentBinds(false),
101 fReadOnlyDataSegment(false),
104 fReadOnlyImportSegment(false),
106 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
107 fHasInitializers(false), fHasTerminators(false), fNotifyObjC(false), fRetainForObjC(false), fRegisteredAsRequiresCoalescing(false), fOverrideOfCacheImageNum(0)
109 fIsSplitSeg
= ((mh
->flags
& MH_SPLIT_SEGS
) != 0);
111 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
112 // each SegmentMachO object in array at end of ImageLoaderMachO object
113 const uint32_t cmd_count
= mh
->ncmds
;
114 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
115 const struct load_command
* cmd
= cmds
;
116 for (uint32_t i
= 0, segIndex
=0; i
< cmd_count
; ++i
) {
117 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
118 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
119 // ignore zero-sized segments
120 if ( segCmd
->vmsize
!= 0 ) {
121 // record offset of load command
122 segOffsets
[segIndex
++] = (uint32_t)((uint8_t*)segCmd
- fMachOData
);
125 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
131 static uintptr_t pageAlign(uintptr_t value
)
133 return (value
+ 4095) & (-4096);
137 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
138 void ImageLoaderMachO::sniffLoadCommands(const macho_header
* mh
, const char* path
, bool inCache
, bool* compressed
,
139 unsigned int* segCount
, unsigned int* libCount
, const LinkContext
& context
,
140 const linkedit_data_command
** codeSigCmd
,
141 const encryption_info_command
** encryptCmd
)
149 const uint32_t cmd_count
= mh
->ncmds
;
150 const uint32_t sizeofcmds
= mh
->sizeofcmds
;
151 if ( cmd_count
> (sizeofcmds
/sizeof(load_command
)) )
152 dyld::throwf("malformed mach-o: ncmds (%u) too large to fit in sizeofcmds (%u)", cmd_count
, sizeofcmds
);
153 const struct load_command
* const startCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
));
154 const struct load_command
* const endCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
) + sizeofcmds
);
155 const struct load_command
* cmd
= startCmds
;
156 bool foundLoadCommandSegment
= false;
157 const macho_segment_command
* linkeditSegCmd
= NULL
;
158 const macho_segment_command
* startOfFileSegCmd
= NULL
;
159 const dyld_info_command
* dyldInfoCmd
= NULL
;
160 const linkedit_data_command
* chainedFixupsCmd
= NULL
;
161 const linkedit_data_command
* exportsTrieCmd
= NULL
;
162 const symtab_command
* symTabCmd
= NULL
;
163 const dysymtab_command
* dynSymbTabCmd
= NULL
;
164 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
165 uint32_t cmdLength
= cmd
->cmdsize
;
166 const macho_segment_command
* segCmd
;
167 const dylib_command
* dylibCmd
;
168 if ( cmdLength
< 8 ) {
169 dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s",
172 const struct load_command
* const nextCmd
= (const struct load_command
*)(((char*)cmd
)+cmdLength
);
173 if ( (nextCmd
> endCmds
) || (nextCmd
< cmd
) ) {
174 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
175 i
, cmdLength
, mh
->sizeofcmds
, path
);
179 case LC_DYLD_INFO_ONLY
:
180 if ( cmd
->cmdsize
!= sizeof(dyld_info_command
) )
181 throw "malformed mach-o image: LC_DYLD_INFO size wrong";
182 dyldInfoCmd
= (struct dyld_info_command
*)cmd
;
185 case LC_DYLD_CHAINED_FIXUPS
:
186 if ( cmd
->cmdsize
!= sizeof(linkedit_data_command
) )
187 throw "malformed mach-o image: LC_DYLD_CHAINED_FIXUPS size wrong";
188 chainedFixupsCmd
= (struct linkedit_data_command
*)cmd
;
191 case LC_DYLD_EXPORTS_TRIE
:
192 if ( cmd
->cmdsize
!= sizeof(linkedit_data_command
) )
193 throw "malformed mach-o image: LC_DYLD_EXPORTS_TRIE size wrong";
194 exportsTrieCmd
= (struct linkedit_data_command
*)cmd
;
196 case LC_SEGMENT_COMMAND
:
197 segCmd
= (struct macho_segment_command
*)cmd
;
199 // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS)
200 if ( ((segCmd
->filesize
) > pageAlign(segCmd
->vmsize
)) && (segCmd
->vmsize
!= 0) )
202 // <rdar://problem/19986776> dyld should support non-allocatable __LLVM segment
203 if ( (segCmd
->filesize
> segCmd
->vmsize
) && ((segCmd
->vmsize
!= 0) || ((segCmd
->flags
& SG_NORELOC
) == 0)) )
205 dyld::throwf("malformed mach-o image: segment load command %s filesize (0x%0lX) is larger than vmsize (0x%0lX)", segCmd
->segname
, (long)segCmd
->filesize
, (long)segCmd
->vmsize
);
206 if ( cmd
->cmdsize
< sizeof(macho_segment_command
) )
207 throw "malformed mach-o image: LC_SEGMENT size too small";
208 if ( cmd
->cmdsize
!= (sizeof(macho_segment_command
) + segCmd
->nsects
* sizeof(macho_section
)) )
209 throw "malformed mach-o image: LC_SEGMENT size wrong for number of sections";
210 // ignore zero-sized segments
211 if ( segCmd
->vmsize
!= 0 )
213 if ( strcmp(segCmd
->segname
, "__LINKEDIT") == 0 ) {
214 #if TARGET_OS_SIMULATOR
215 // Note: should check on all platforms that __LINKEDIT is read-only, but <rdar://problem/22637626&22525618>
216 if ( segCmd
->initprot
!= VM_PROT_READ
)
217 throw "malformed mach-o image: __LINKEDIT segment does not have read-only permissions";
219 if ( segCmd
->fileoff
== 0 )
220 throw "malformed mach-o image: __LINKEDIT has fileoff==0 which overlaps mach_header";
221 if ( linkeditSegCmd
!= NULL
)
222 throw "malformed mach-o image: multiple __LINKEDIT segments";
223 linkeditSegCmd
= segCmd
;
226 if ( segCmd
->initprot
& 0xFFFFFFF8 )
227 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in initprot", segCmd
->segname
, segCmd
->initprot
);
228 if ( segCmd
->maxprot
& 0xFFFFFFF8 )
229 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in maxprot", segCmd
->segname
, segCmd
->maxprot
);
230 if ( (segCmd
->initprot
!= 0) && ((segCmd
->initprot
& VM_PROT_READ
) == 0) )
231 dyld::throwf("malformed mach-o image: %s segment is not mapped readable", segCmd
->segname
);
233 if ( (segCmd
->fileoff
== 0) && (segCmd
->filesize
!= 0) ) {
234 if ( (segCmd
->initprot
& VM_PROT_READ
) == 0 )
235 dyld::throwf("malformed mach-o image: %s segment maps start of file but is not readable", segCmd
->segname
);
236 if ( (segCmd
->initprot
& VM_PROT_WRITE
) == VM_PROT_WRITE
) {
237 if ( context
.strictMachORequired
)
238 dyld::throwf("malformed mach-o image: %s segment maps start of file but is writable", segCmd
->segname
);
240 if ( segCmd
->filesize
< (sizeof(macho_header
) + mh
->sizeofcmds
) )
241 dyld::throwf("malformed mach-o image: %s segment does not map all of load commands", segCmd
->segname
);
242 if ( startOfFileSegCmd
!= NULL
)
243 dyld::throwf("malformed mach-o image: multiple segments map start of file: %s %s", startOfFileSegCmd
->segname
, segCmd
->segname
);
244 startOfFileSegCmd
= segCmd
;
246 if ( context
.strictMachORequired
) {
247 uintptr_t vmStart
= segCmd
->vmaddr
;
248 uintptr_t vmSize
= segCmd
->vmsize
;
249 uintptr_t vmEnd
= vmStart
+ vmSize
;
250 uintptr_t fileStart
= segCmd
->fileoff
;
251 uintptr_t fileSize
= segCmd
->filesize
;
252 if ( (intptr_t)(vmSize
) < 0 )
253 dyld::throwf("malformed mach-o image: segment load command %s vmsize too large in %s", segCmd
->segname
, path
);
254 if ( vmStart
> vmEnd
)
255 dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd
->segname
);
256 if ( vmSize
!= fileSize
) {
257 if ( segCmd
->initprot
== 0 ) {
258 // allow: fileSize == 0 && initprot == 0 e.g. __PAGEZERO
259 // allow: vmSize == 0 && initprot == 0 e.g. __LLVM
260 if ( (fileSize
!= 0) && (vmSize
!= 0) )
261 dyld::throwf("malformed mach-o image: unaccessable segment %s has non-zero filesize and vmsize", segCmd
->segname
);
264 // allow: vmSize > fileSize && initprot != X e.g. __DATA
265 if ( vmSize
< fileSize
) {
266 dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd
->segname
);
268 if ( segCmd
->initprot
& VM_PROT_EXECUTE
) {
269 dyld::throwf("malformed mach-o image: segment %s has vmsize != filesize and is executable", segCmd
->segname
);
274 if ( (fileSize
!= 0) && (segCmd
->initprot
== (VM_PROT_READ
| VM_PROT_EXECUTE
)) ) {
275 if ( foundLoadCommandSegment
)
276 throw "load commands in multiple segments";
277 foundLoadCommandSegment
= true;
280 else if ( (fileStart
< mh
->sizeofcmds
) && (fileSize
!= 0) ) {
281 // <rdar://problem/7942521> all load commands must be in an executable segment
282 if ( (fileStart
!= 0) || (fileSize
< (mh
->sizeofcmds
+sizeof(macho_header
))) )
283 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd
->segname
);
284 if ( segCmd
->initprot
!= (VM_PROT_READ
| VM_PROT_EXECUTE
) )
285 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd
->segname
);
286 if ( foundLoadCommandSegment
)
287 throw "load commands in multiple segments";
288 foundLoadCommandSegment
= true;
291 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
292 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
293 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
294 if (!inCache
&& sect
->offset
!= 0 && ((sect
->offset
+ sect
->size
) > (segCmd
->fileoff
+ segCmd
->filesize
)))
295 dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect
->segname
, sect
->sectname
, path
, segCmd
->segname
);
299 case LC_SEGMENT_COMMAND_WRONG
:
300 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
303 case LC_LOAD_WEAK_DYLIB
:
304 case LC_REEXPORT_DYLIB
:
305 case LC_LOAD_UPWARD_DYLIB
:
308 [[clang::fallthrough]];
310 dylibCmd
= (dylib_command
*)cmd
;
311 if ( dylibCmd
->dylib
.name
.offset
> cmdLength
)
312 dyld::throwf("malformed mach-o image: dylib load command #%d has offset (%u) outside its size (%u)", i
, dylibCmd
->dylib
.name
.offset
, cmdLength
);
313 if ( (dylibCmd
->dylib
.name
.offset
+ strlen((char*)dylibCmd
+ dylibCmd
->dylib
.name
.offset
) + 1) > cmdLength
)
314 dyld::throwf("malformed mach-o image: dylib load command #%d string extends beyond end of load command", i
);
316 case LC_CODE_SIGNATURE
:
317 if ( cmd
->cmdsize
!= sizeof(linkedit_data_command
) )
318 throw "malformed mach-o image: LC_CODE_SIGNATURE size wrong";
319 // <rdar://problem/22799652> only support one LC_CODE_SIGNATURE per image
320 if ( *codeSigCmd
!= NULL
)
321 throw "malformed mach-o image: multiple LC_CODE_SIGNATURE load commands";
322 *codeSigCmd
= (struct linkedit_data_command
*)cmd
;
324 case LC_ENCRYPTION_INFO
:
325 if ( cmd
->cmdsize
!= sizeof(encryption_info_command
) )
326 throw "malformed mach-o image: LC_ENCRYPTION_INFO size wrong";
327 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO per image
328 if ( *encryptCmd
!= NULL
)
329 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO load commands";
330 *encryptCmd
= (encryption_info_command
*)cmd
;
332 case LC_ENCRYPTION_INFO_64
:
333 if ( cmd
->cmdsize
!= sizeof(encryption_info_command_64
) )
334 throw "malformed mach-o image: LC_ENCRYPTION_INFO_64 size wrong";
335 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO_64 per image
336 if ( *encryptCmd
!= NULL
)
337 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO_64 load commands";
338 *encryptCmd
= (encryption_info_command
*)cmd
;
341 if ( cmd
->cmdsize
!= sizeof(symtab_command
) )
342 throw "malformed mach-o image: LC_SYMTAB size wrong";
343 symTabCmd
= (symtab_command
*)cmd
;
346 if ( cmd
->cmdsize
!= sizeof(dysymtab_command
) )
347 throw "malformed mach-o image: LC_DYSYMTAB size wrong";
348 dynSymbTabCmd
= (dysymtab_command
*)cmd
;
351 // <rdar://problem/26797345> error when loading iOS Simulator mach-o binary into macOS process
352 case LC_VERSION_MIN_WATCHOS
:
353 case LC_VERSION_MIN_TVOS
:
354 case LC_VERSION_MIN_IPHONEOS
:
355 if ( !context
.iOSonMac
)
356 throw "mach-o, but built for simulator (not macOS)";
363 if ( context
.strictMachORequired
&& !foundLoadCommandSegment
)
364 throw "load commands not in a segment";
365 if ( linkeditSegCmd
== NULL
)
366 throw "malformed mach-o image: missing __LINKEDIT segment";
367 if ( !inCache
&& (startOfFileSegCmd
== NULL
) )
368 throw "malformed mach-o image: missing __TEXT segment that maps start of file";
369 // <rdar://problem/13145644> verify every segment does not overlap another segment
370 if ( context
.strictMachORequired
) {
371 uintptr_t lastFileStart
= 0;
372 uintptr_t linkeditFileStart
= 0;
373 const struct load_command
* cmd1
= startCmds
;
374 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
375 if ( cmd1
->cmd
== LC_SEGMENT_COMMAND
) {
376 struct macho_segment_command
* segCmd1
= (struct macho_segment_command
*)cmd1
;
377 uintptr_t vmStart1
= segCmd1
->vmaddr
;
378 uintptr_t vmEnd1
= segCmd1
->vmaddr
+ segCmd1
->vmsize
;
379 uintptr_t fileStart1
= segCmd1
->fileoff
;
380 uintptr_t fileEnd1
= segCmd1
->fileoff
+ segCmd1
->filesize
;
382 if (fileStart1
> lastFileStart
)
383 lastFileStart
= fileStart1
;
385 if ( strcmp(&segCmd1
->segname
[0], "__LINKEDIT") == 0 ) {
386 linkeditFileStart
= fileStart1
;
389 const struct load_command
* cmd2
= startCmds
;
390 for (uint32_t j
= 0; j
< cmd_count
; ++j
) {
393 if ( cmd2
->cmd
== LC_SEGMENT_COMMAND
) {
394 struct macho_segment_command
* segCmd2
= (struct macho_segment_command
*)cmd2
;
395 uintptr_t vmStart2
= segCmd2
->vmaddr
;
396 uintptr_t vmEnd2
= segCmd2
->vmaddr
+ segCmd2
->vmsize
;
397 uintptr_t fileStart2
= segCmd2
->fileoff
;
398 uintptr_t fileEnd2
= segCmd2
->fileoff
+ segCmd2
->filesize
;
399 if ( ((vmStart2
<= vmStart1
) && (vmEnd2
> vmStart1
) && (vmEnd1
> vmStart1
))
400 || ((vmStart2
>= vmStart1
) && (vmStart2
< vmEnd1
) && (vmEnd2
> vmStart2
)) )
401 dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);
402 if ( ((fileStart2
<= fileStart1
) && (fileEnd2
> fileStart1
) && (fileEnd1
> fileStart1
))
403 || ((fileStart2
>= fileStart1
) && (fileStart2
< fileEnd1
) && (fileEnd2
> fileStart2
)) )
404 dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);
406 cmd2
= (const struct load_command
*)(((char*)cmd2
)+cmd2
->cmdsize
);
409 cmd1
= (const struct load_command
*)(((char*)cmd1
)+cmd1
->cmdsize
);
412 if (lastFileStart
!= linkeditFileStart
)
413 dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment");
416 // validate linkedit content
417 if ( (dyldInfoCmd
== NULL
) && (chainedFixupsCmd
== NULL
) && (symTabCmd
== NULL
) )
418 throw "malformed mach-o image: missing LC_SYMTAB, LC_DYLD_INFO, or LC_DYLD_CHAINED_FIXUPS";
419 if ( dynSymbTabCmd
== NULL
)
420 throw "malformed mach-o image: missing LC_DYSYMTAB";
422 uint32_t linkeditFileOffsetStart
= (uint32_t)linkeditSegCmd
->fileoff
;
423 uint32_t linkeditFileOffsetEnd
= (uint32_t)linkeditSegCmd
->fileoff
+ (uint32_t)linkeditSegCmd
->filesize
;
425 if ( !inCache
&& (dyldInfoCmd
!= NULL
) && context
.strictMachORequired
) {
426 // validate all LC_DYLD_INFO chunks fit in LINKEDIT and don't overlap
427 uint32_t offset
= linkeditFileOffsetStart
;
428 if ( dyldInfoCmd
->rebase_size
!= 0 ) {
429 if ( dyldInfoCmd
->rebase_size
& 0x80000000 )
430 throw "malformed mach-o image: dyld rebase info size overflow";
431 if ( dyldInfoCmd
->rebase_off
< offset
)
432 throw "malformed mach-o image: dyld rebase info underruns __LINKEDIT";
433 offset
= dyldInfoCmd
->rebase_off
+ dyldInfoCmd
->rebase_size
;
434 if ( offset
> linkeditFileOffsetEnd
)
435 throw "malformed mach-o image: dyld rebase info overruns __LINKEDIT";
437 if ( dyldInfoCmd
->bind_size
!= 0 ) {
438 if ( dyldInfoCmd
->bind_size
& 0x80000000 )
439 throw "malformed mach-o image: dyld bind info size overflow";
440 if ( dyldInfoCmd
->bind_off
< offset
)
441 throw "malformed mach-o image: dyld bind info overlaps rebase info";
442 offset
= dyldInfoCmd
->bind_off
+ dyldInfoCmd
->bind_size
;
443 if ( offset
> linkeditFileOffsetEnd
)
444 throw "malformed mach-o image: dyld bind info overruns __LINKEDIT";
446 if ( dyldInfoCmd
->weak_bind_size
!= 0 ) {
447 if ( dyldInfoCmd
->weak_bind_size
& 0x80000000 )
448 throw "malformed mach-o image: dyld weak bind info size overflow";
449 if ( dyldInfoCmd
->weak_bind_off
< offset
)
450 throw "malformed mach-o image: dyld weak bind info overlaps bind info";
451 offset
= dyldInfoCmd
->weak_bind_off
+ dyldInfoCmd
->weak_bind_size
;
452 if ( offset
> linkeditFileOffsetEnd
)
453 throw "malformed mach-o image: dyld weak bind info overruns __LINKEDIT";
455 if ( dyldInfoCmd
->lazy_bind_size
!= 0 ) {
456 if ( dyldInfoCmd
->lazy_bind_size
& 0x80000000 )
457 throw "malformed mach-o image: dyld lazy bind info size overflow";
458 if ( dyldInfoCmd
->lazy_bind_off
< offset
)
459 throw "malformed mach-o image: dyld lazy bind info overlaps weak bind info";
460 offset
= dyldInfoCmd
->lazy_bind_off
+ dyldInfoCmd
->lazy_bind_size
;
461 if ( offset
> linkeditFileOffsetEnd
)
462 throw "malformed mach-o image: dyld lazy bind info overruns __LINKEDIT";
464 if ( dyldInfoCmd
->export_size
!= 0 ) {
465 if ( dyldInfoCmd
->export_size
& 0x80000000 )
466 throw "malformed mach-o image: dyld export info size overflow";
467 if ( dyldInfoCmd
->export_off
< offset
)
468 throw "malformed mach-o image: dyld export info overlaps lazy bind info";
469 offset
= dyldInfoCmd
->export_off
+ dyldInfoCmd
->export_size
;
470 if ( offset
> linkeditFileOffsetEnd
)
471 throw "malformed mach-o image: dyld export info overruns __LINKEDIT";
475 if ( !inCache
&& (chainedFixupsCmd
!= NULL
) && context
.strictMachORequired
) {
476 // validate all LC_DYLD_CHAINED_FIXUPS chunks fit in LINKEDIT and don't overlap
477 if ( chainedFixupsCmd
->dataoff
< linkeditFileOffsetStart
)
478 throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT";
479 if ( (chainedFixupsCmd
->dataoff
+ chainedFixupsCmd
->datasize
) > linkeditFileOffsetEnd
)
480 throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT";
483 if ( !inCache
&& (exportsTrieCmd
!= NULL
) && context
.strictMachORequired
) {
484 // validate all LC_DYLD_EXPORTS_TRIE chunks fit in LINKEDIT and don't overlap
485 if ( exportsTrieCmd
->dataoff
< linkeditFileOffsetStart
)
486 throw "malformed mach-o image: dyld chained fixups info underruns __LINKEDIT";
487 if ( (exportsTrieCmd
->dataoff
+ exportsTrieCmd
->datasize
) > linkeditFileOffsetEnd
)
488 throw "malformed mach-o image: dyld chained fixups info overruns __LINKEDIT";
491 if ( symTabCmd
!= NULL
) {
492 // validate symbol table fits in LINKEDIT
493 if ( (symTabCmd
->nsyms
> 0) && (symTabCmd
->symoff
< linkeditFileOffsetStart
) )
494 throw "malformed mach-o image: symbol table underruns __LINKEDIT";
495 if ( symTabCmd
->nsyms
> 0x10000000 )
496 throw "malformed mach-o image: symbol table too large";
497 uint32_t symbolsSize
= symTabCmd
->nsyms
* sizeof(macho_nlist
);
498 if ( symbolsSize
> linkeditSegCmd
->filesize
)
499 throw "malformed mach-o image: symbol table overruns __LINKEDIT";
500 if ( symTabCmd
->symoff
+ symbolsSize
< symTabCmd
->symoff
)
501 throw "malformed mach-o image: symbol table size wraps";
502 if ( symTabCmd
->symoff
+ symbolsSize
> symTabCmd
->stroff
)
503 throw "malformed mach-o image: symbol table overlaps symbol strings";
504 if ( symTabCmd
->stroff
+ symTabCmd
->strsize
< symTabCmd
->stroff
)
505 throw "malformed mach-o image: symbol string size wraps";
506 if ( symTabCmd
->stroff
+ symTabCmd
->strsize
> linkeditFileOffsetEnd
) {
507 // <rdar://problem/24220313> let old apps overflow as long as it stays within mapped page
508 if ( context
.strictMachORequired
|| (symTabCmd
->stroff
+ symTabCmd
->strsize
> ((linkeditFileOffsetEnd
+ 4095) & (-4096))) )
509 throw "malformed mach-o image: symbol strings overrun __LINKEDIT";
512 if ( (symTabCmd
->symoff
% sizeof(void*)) != 0 ) {
513 // <rdar://53723577> allow old malformed plugins in new app
514 if ( sdkVersion((mach_header
*)mh
) >= DYLD_PACKED_VERSION(10,15,0) )
515 throw "malformed mach-o image: mis-aligned symbol table __LINKEDIT";
518 // validate indirect symbol table
519 if ( dynSymbTabCmd
->nindirectsyms
!= 0 ) {
520 if ( dynSymbTabCmd
->indirectsymoff
< linkeditFileOffsetStart
)
521 throw "malformed mach-o image: indirect symbol table underruns __LINKEDIT";
522 if ( dynSymbTabCmd
->nindirectsyms
> 0x10000000 )
523 throw "malformed mach-o image: indirect symbol table too large";
524 uint32_t indirectTableSize
= dynSymbTabCmd
->nindirectsyms
* sizeof(uint32_t);
525 if ( indirectTableSize
> linkeditSegCmd
->filesize
)
526 throw "malformed mach-o image: indirect symbol table overruns __LINKEDIT";
527 if ( dynSymbTabCmd
->indirectsymoff
+ indirectTableSize
< dynSymbTabCmd
->indirectsymoff
)
528 throw "malformed mach-o image: indirect symbol table size wraps";
529 if ( context
.strictMachORequired
&& (dynSymbTabCmd
->indirectsymoff
+ indirectTableSize
> symTabCmd
->stroff
) )
530 throw "malformed mach-o image: indirect symbol table overruns string pool";
532 if ( (dynSymbTabCmd
->nlocalsym
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->ilocalsym
> symTabCmd
->nsyms
) )
533 throw "malformed mach-o image: indirect symbol table local symbol count exceeds total symbols";
534 if ( dynSymbTabCmd
->ilocalsym
+ dynSymbTabCmd
->nlocalsym
< dynSymbTabCmd
->ilocalsym
)
535 throw "malformed mach-o image: indirect symbol table local symbol count wraps";
536 if ( (dynSymbTabCmd
->nextdefsym
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->iextdefsym
> symTabCmd
->nsyms
) )
537 throw "malformed mach-o image: indirect symbol table extern symbol count exceeds total symbols";
538 if ( dynSymbTabCmd
->iextdefsym
+ dynSymbTabCmd
->nextdefsym
< dynSymbTabCmd
->iextdefsym
)
539 throw "malformed mach-o image: indirect symbol table extern symbol count wraps";
540 if ( (dynSymbTabCmd
->nundefsym
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->iundefsym
> symTabCmd
->nsyms
) )
541 throw "malformed mach-o image: indirect symbol table undefined symbol count exceeds total symbols";
542 if ( dynSymbTabCmd
->iundefsym
+ dynSymbTabCmd
->nundefsym
< dynSymbTabCmd
->iundefsym
)
543 throw "malformed mach-o image: indirect symbol table undefined symbol count wraps";
547 // fSegmentsArrayCount is only 8-bits
548 if ( *segCount
> 255 )
549 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path
);
551 // fSegmentsArrayCount is only 8-bits
552 if ( *libCount
> 4095 )
553 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path
);
555 if ( needsAddedLibSystemDepency(*libCount
, mh
) )
558 // dylibs that use LC_DYLD_CHAINED_FIXUPS have that load command removed when put in the dyld cache
559 if ( !*compressed
&& (mh
->flags
& MH_DYLIB_IN_CACHE
) )
565 // create image for main executable
566 ImageLoader
* ImageLoaderMachO::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
)
568 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
569 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
571 unsigned int segCount
;
572 unsigned int libCount
;
573 const linkedit_data_command
* codeSigCmd
;
574 const encryption_info_command
* encryptCmd
;
575 sniffLoadCommands(mh
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
576 // instantiate concrete class based on content of load commands
578 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
580 #if SUPPORT_CLASSIC_MACHO
581 return ImageLoaderMachOClassic::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
583 throw "missing LC_DYLD_INFO load command";
588 // create image by mapping in a mach-o file
589 ImageLoader
* ImageLoaderMachO::instantiateFromFile(const char* path
, int fd
, const uint8_t firstPages
[], size_t firstPagesSize
, uint64_t offsetInFat
,
590 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
593 unsigned int segCount
;
594 unsigned int libCount
;
595 const linkedit_data_command
* codeSigCmd
;
596 const encryption_info_command
* encryptCmd
;
597 sniffLoadCommands((const macho_header
*)firstPages
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
598 // instantiate concrete class based on content of load commands
600 return ImageLoaderMachOCompressed::instantiateFromFile(path
, fd
, firstPages
, firstPagesSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, encryptCmd
, context
);
602 #if SUPPORT_CLASSIC_MACHO
603 return ImageLoaderMachOClassic::instantiateFromFile(path
, fd
, firstPages
, firstPagesSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
);
605 throw "missing LC_DYLD_INFO load command";
609 // create image by using cached mach-o file
610 ImageLoader
* ImageLoaderMachO::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, const LinkContext
& context
)
612 // instantiate right concrete class
614 unsigned int segCount
;
615 unsigned int libCount
;
616 const linkedit_data_command
* codeSigCmd
;
617 const encryption_info_command
* encryptCmd
;
618 sniffLoadCommands(mh
, path
, true, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
619 // instantiate concrete class based on content of load commands
621 return ImageLoaderMachOCompressed::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
623 #if SUPPORT_CLASSIC_MACHO
624 return ImageLoaderMachOClassic::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
626 throw "missing LC_DYLD_INFO load command";
630 // create image by copying an in-memory mach-o file
631 ImageLoader
* ImageLoaderMachO::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
, const LinkContext
& context
)
634 unsigned int segCount
;
635 unsigned int libCount
;
636 const linkedit_data_command
* sigcmd
;
637 const encryption_info_command
* encryptCmd
;
638 sniffLoadCommands(mh
, moduleName
, false, &compressed
, &segCount
, &libCount
, context
, &sigcmd
, &encryptCmd
);
639 // instantiate concrete class based on content of load commands
641 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
643 #if SUPPORT_CLASSIC_MACHO
644 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
646 throw "missing LC_DYLD_INFO load command";
651 int ImageLoaderMachO::crashIfInvalidCodeSignature()
653 // Now that segments are mapped in, try reading from first executable segment.
654 // If code signing is enabled the kernel will validate the code signature
655 // when paging in, and kill the process if invalid.
656 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
657 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
658 // return read value to ensure compiler does not optimize away load
659 int* p
= (int*)segActualLoadAddress(i
);
667 void ImageLoaderMachO::parseLoadCmds(const LinkContext
& context
)
669 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
670 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
671 // set up pointer to __LINKEDIT segment
672 if ( strcmp(segName(i
),"__LINKEDIT") == 0 ) {
674 // <rdar://problem/42419336> historically, macOS never did this check
675 if ( segFileOffset(i
) > fCoveredCodeLength
)
676 dyld::throwf("cannot load '%s' (segment outside of code signature)", this->getShortName());
678 fLinkEditBase
= (uint8_t*)(segActualLoadAddress(i
) - segFileOffset(i
));
680 #if TEXT_RELOC_SUPPORT
681 // __TEXT segment always starts at beginning of file and contains mach_header and load commands
682 if ( segExecutable(i
) ) {
683 if ( segHasRebaseFixUps(i
) && (fSlide
!= 0) )
684 fTextSegmentRebases
= true;
685 if ( segHasBindFixUps(i
) )
686 fTextSegmentBinds
= true;
689 if ( segIsReadOnlyData(i
) )
690 fReadOnlyDataSegment
= true;
693 if ( segIsReadOnlyImport(i
) )
694 fReadOnlyImportSegment
= true;
696 // some segment always starts at beginning of file and contains mach_header and load commands
697 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
698 fMachOData
= (uint8_t*)(segActualLoadAddress(i
));
702 // keep count of prebound images with weak exports
703 if ( this->participatesInCoalescing() ) {
704 ++fgImagesRequiringCoalescing
;
705 fRegisteredAsRequiresCoalescing
= true;
706 if ( this->hasCoalescedExports() )
707 ++fgImagesHasWeakDefinitions
;
710 // keep count of images used in shared cache
711 if ( fInSharedCache
)
712 ++fgImagesUsedFromSharedCache
;
714 // walk load commands (mapped in at start of __TEXT segment)
715 const dyld_info_command
* dyldInfo
= NULL
;
716 const linkedit_data_command
* chainedFixupsCmd
= NULL
;
717 const linkedit_data_command
* exportsTrieCmd
= NULL
;
718 const macho_nlist
* symbolTable
= NULL
;
719 const char* symbolTableStrings
= NULL
;
720 const struct load_command
* firstUnknownCmd
= NULL
;
721 const struct version_min_command
* minOSVersionCmd
= NULL
;
722 const dysymtab_command
* dynSymbolTable
= NULL
;
723 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
724 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
725 const struct load_command
* cmd
= cmds
;
726 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
730 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
731 symbolTableStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
732 symbolTable
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
736 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
738 case LC_SUB_UMBRELLA
:
739 fHasSubUmbrella
= true;
741 case LC_SUB_FRAMEWORK
:
745 fHasSubLibraries
= true;
747 case LC_ROUTINES_COMMAND
:
751 case LC_DYLD_INFO_ONLY
:
752 dyldInfo
= (struct dyld_info_command
*)cmd
;
754 case LC_DYLD_CHAINED_FIXUPS
:
755 chainedFixupsCmd
= (struct linkedit_data_command
*)cmd
;
757 case LC_DYLD_EXPORTS_TRIE
:
758 exportsTrieCmd
= (struct linkedit_data_command
*)cmd
;
760 case LC_SEGMENT_COMMAND
:
762 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
763 const bool isTextSeg
= (strcmp(seg
->segname
, "__TEXT") == 0);
764 #if __i386__ && TARGET_OS_OSX
765 const bool isObjCSeg
= (strcmp(seg
->segname
, "__OBJC") == 0);
769 const bool isDataSeg
= (strncmp(seg
->segname
, "__DATA", 6) == 0);
771 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
772 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
773 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
774 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
775 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
776 fHasInitializers
= true;
777 else if ( type
== S_INIT_FUNC_OFFSETS
)
778 fHasInitializers
= true;
779 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
780 fHasTerminators
= true;
781 else if ( type
== S_DTRACE_DOF
)
782 fHasDOFSections
= true;
783 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__eh_frame") == 0) )
784 fEHFrameSectionOffset
= (uint32_t)((uint8_t*)sect
- fMachOData
);
785 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__unwind_info") == 0) )
786 fUnwindInfoSectionOffset
= (uint32_t)((uint8_t*)sect
- fMachOData
);
788 #if __i386__ && TARGET_OS_OSX
789 else if ( isObjCSeg
) {
790 if ( strcmp(sect
->sectname
, "__image_info") == 0 ) {
791 const uint32_t* imageInfo
= (uint32_t*)(sect
->addr
+ fSlide
);
792 uint32_t flags
= imageInfo
[1];
793 if ( (flags
& 4) && (((macho_header
*)fMachOData
)->filetype
!= MH_EXECUTE
) )
794 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
796 else if ( ((macho_header
*)fMachOData
)->filetype
== MH_DYLIB
) {
797 fRetainForObjC
= true;
801 else if ( isDataSeg
&& (strncmp(sect
->sectname
, "__objc_imageinfo", 16) == 0) ) {
803 const uint32_t* imageInfo
= (uint32_t*)(sect
->addr
+ fSlide
);
804 uint32_t flags
= imageInfo
[1];
805 if ( (flags
& 4) && (((macho_header
*)fMachOData
)->filetype
!= MH_EXECUTE
) )
806 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
810 else if ( isDataSeg
&& (strncmp(sect
->sectname
, "__objc_", 7) == 0) && (((macho_header
*)fMachOData
)->filetype
== MH_DYLIB
) )
811 fRetainForObjC
= true;
816 case LC_TWOLEVEL_HINTS
:
817 // no longer supported
821 fDylibIDOffset
= (uint32_t)((uint8_t*)cmd
- fMachOData
);
825 case LC_LOAD_WEAK_DYLIB
:
826 case LC_REEXPORT_DYLIB
:
827 case LC_LOAD_UPWARD_DYLIB
:
830 case LC_VERSION_MIN_MACOSX
:
831 case LC_VERSION_MIN_IPHONEOS
:
832 case LC_VERSION_MIN_TVOS
:
833 case LC_VERSION_MIN_WATCHOS
:
834 minOSVersionCmd
= (version_min_command
*)cmd
;
837 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 ) {
838 if ( firstUnknownCmd
== NULL
)
839 firstUnknownCmd
= cmd
;
843 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
845 if ( firstUnknownCmd
!= NULL
) {
846 if ( minOSVersionCmd
!= NULL
) {
847 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",
848 this->getShortName(),
849 minOSVersionCmd
->version
>> 16, ((minOSVersionCmd
->version
>> 8) & 0xff),
850 firstUnknownCmd
->cmd
);
853 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd
->cmd
);
858 if ( dyldInfo
!= NULL
)
859 this->setDyldInfo(dyldInfo
);
860 if ( chainedFixupsCmd
!= NULL
)
861 this->setChainedFixups(chainedFixupsCmd
);
862 if ( exportsTrieCmd
!= NULL
)
863 this->setExportsTrie(exportsTrieCmd
);
865 if ( symbolTable
!= NULL
)
866 this->setSymbolTableInfo(symbolTable
, symbolTableStrings
, dynSymbolTable
);
869 // don't do this work in destructor because we need object to be full subclass
870 // for UnmapSegments() to work
871 void ImageLoaderMachO::destroy()
873 // update count of images with weak exports
874 if ( fRegisteredAsRequiresCoalescing
) {
875 --fgImagesRequiringCoalescing
;
876 if ( this->hasCoalescedExports() )
877 --fgImagesHasWeakDefinitions
;
880 // keep count of images used in shared cache
881 if ( fInSharedCache
)
882 --fgImagesUsedFromSharedCache
;
884 // unmap image when done
889 unsigned int ImageLoaderMachO::segmentCount() const
891 return fSegmentsCount
;
895 const macho_segment_command
* ImageLoaderMachO::segLoadCommand(unsigned int segIndex
) const
897 uint32_t* lcOffsets
= this->segmentCommandOffsets();
898 uint32_t lcOffset
= lcOffsets
[segIndex
];
899 return (macho_segment_command
*)(&fMachOData
[lcOffset
]);
902 const char* ImageLoaderMachO::segName(unsigned int segIndex
) const
904 return segLoadCommand(segIndex
)->segname
;
908 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex
) const
910 return segLoadCommand(segIndex
)->vmsize
;
914 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex
) const
916 return segLoadCommand(segIndex
)->filesize
;
920 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex
)
922 return ( segWriteable(segIndex
) && (segSize(segIndex
) > segFileSize(segIndex
)) );
926 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex
) const
928 return segLoadCommand(segIndex
)->fileoff
;
932 bool ImageLoaderMachO::segReadable(unsigned int segIndex
) const
934 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_READ
) != 0);
938 bool ImageLoaderMachO::segWriteable(unsigned int segIndex
) const
940 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_WRITE
) != 0);
944 bool ImageLoaderMachO::segExecutable(unsigned int segIndex
) const
946 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_EXECUTE
) != 0);
950 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex
) const
952 return (segLoadCommand(segIndex
)->initprot
== 0);
955 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex
) const
957 return (segLoadCommand(segIndex
)->vmaddr
!= 0);
960 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex
) const
962 return segLoadCommand(segIndex
)->vmaddr
;
965 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex
) const
967 return segLoadCommand(segIndex
)->vmaddr
+ fSlide
;
971 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex
) const
973 return segActualLoadAddress(segIndex
) + segSize(segIndex
);
976 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex
) const
978 #if TEXT_RELOC_SUPPORT
979 // scan sections for fix-up bit
980 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
981 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
982 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
983 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
984 if ( (sect
->flags
& S_ATTR_LOC_RELOC
) != 0 )
991 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex
) const
993 #if TEXT_RELOC_SUPPORT
994 // scan sections for fix-up bit
995 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
996 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
997 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
998 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
999 if ( (sect
->flags
& S_ATTR_EXT_RELOC
) != 0 )
1007 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex
) const
1009 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
1010 return ( (segCmd
->initprot
& VM_PROT_EXECUTE
)
1011 && ((segCmd
->initprot
& VM_PROT_WRITE
) == 0)
1012 && (strcmp(segCmd
->segname
, "__IMPORT") == 0) );
1016 bool ImageLoaderMachO::segIsReadOnlyData(unsigned int segIndex
) const
1018 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
1019 return ( (segCmd
->initprot
& VM_PROT_WRITE
)
1020 && ((segCmd
->initprot
& VM_PROT_EXECUTE
) == 0)
1021 && (segCmd
->flags
& SG_READ_ONLY
) );
1024 void ImageLoaderMachO::UnmapSegments()
1026 // usually unmap image when done
1027 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) {
1028 // unmap TEXT segment last because it contains load command being inspected
1029 unsigned int textSegmentIndex
= 0;
1030 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1031 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
1032 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
1033 textSegmentIndex
= i
;
1037 --ImageLoader::fgTotalSegmentsMapped
;
1038 ImageLoader::fgTotalBytesMapped
-= segSize(i
);
1039 munmap((void*)segActualLoadAddress(i
), segSize(i
));
1043 --ImageLoader::fgTotalSegmentsMapped
;
1044 ImageLoader::fgTotalBytesMapped
-= segSize(textSegmentIndex
);
1045 munmap((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
));
1050 bool ImageLoaderMachO::segmentsMustSlideTogether() const
1055 bool ImageLoaderMachO::segmentsCanSlide() const
1057 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
1060 bool ImageLoaderMachO::isBundle() const
1062 const macho_header
* mh
= (macho_header
*)fMachOData
;
1063 return ( mh
->filetype
== MH_BUNDLE
);
1066 bool ImageLoaderMachO::isDylib() const
1068 const macho_header
* mh
= (macho_header
*)fMachOData
;
1069 return ( mh
->filetype
== MH_DYLIB
);
1072 bool ImageLoaderMachO::isExecutable() const
1074 const macho_header
* mh
= (macho_header
*)fMachOData
;
1075 return ( mh
->filetype
== MH_EXECUTE
);
1078 bool ImageLoaderMachO::isPositionIndependentExecutable() const
1080 const macho_header
* mh
= (macho_header
*)fMachOData
;
1081 return ( (mh
->filetype
== MH_EXECUTE
) && ((mh
->flags
& MH_PIE
) != 0) );
1085 bool ImageLoaderMachO::forceFlat() const
1087 const macho_header
* mh
= (macho_header
*)fMachOData
;
1088 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
1091 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
1093 const macho_header
* mh
= (macho_header
*)fMachOData
;
1094 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
1097 bool ImageLoaderMachO::isPrebindable() const
1099 const macho_header
* mh
= (macho_header
*)fMachOData
;
1100 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
1103 bool ImageLoaderMachO::hasCoalescedExports() const
1105 const macho_header
* mh
= (macho_header
*)fMachOData
;
1106 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
1109 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
1111 const macho_header
* mh
= (macho_header
*)fMachOData
;
1112 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
1115 bool ImageLoaderMachO::participatesInCoalescing() const
1117 const macho_header
* mh
= (macho_header
*)fMachOData
;
1118 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
1119 // is reduced and it can't coalesce with other images
1120 if ( this->hasHiddenExports() )
1122 return ( (mh
->flags
& (MH_WEAK_DEFINES
|MH_BINDS_TO_WEAK
)) != 0 );
1127 void ImageLoaderMachO::setSlide(intptr_t slide
)
1132 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command
* codeSigCmd
, int fd
, uint64_t offsetInFatFile
, const LinkContext
& context
)
1134 dyld3::ScopedTimer(DBG_DYLD_TIMING_ATTACH_CODESIGNATURE
, 0, 0, 0);
1135 // if dylib being loaded has no code signature load command
1136 if ( codeSigCmd
== NULL
) {
1137 disableCoverageCheck();
1141 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools
1142 if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) {
1143 disableCoverageCheck();
1148 fsignatures_t siginfo
;
1149 siginfo
.fs_file_start
=offsetInFatFile
; // start of mach-o slice in fat file
1150 siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
); // start of CD in mach-o file
1151 siginfo
.fs_blob_size
=codeSigCmd
->datasize
; // size of CD
1152 int result
= fcntl(fd
, F_ADDFILESIGS_RETURN
, &siginfo
);
1154 #if TARGET_OS_SIMULATOR
1155 // rdar://problem/18759224> check range covered by the code directory after loading
1156 // Attempt to fallback only if we are in the simulator
1158 if ( result
== -1 ) {
1159 result
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
);
1160 siginfo
.fs_file_start
= codeSigCmd
->dataoff
;
1164 if ( result
== -1 ) {
1165 if ( (errno
== EPERM
) || (errno
== EBADEXEC
) )
1166 dyld::throwf("code signature invalid for '%s'\n", this->getPath());
1167 if ( context
.verboseCodeSignatures
)
1168 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno
);
1169 siginfo
.fs_file_start
= UINT64_MAX
;
1170 } else if ( context
.verboseCodeSignatures
) {
1171 dyld::log("dyld: Registered code signature for %s\n", this->getPath());
1173 fCoveredCodeLength
= siginfo
.fs_file_start
;
1178 char messageBuffer
[512];
1179 messageBuffer
[0] = '\0';
1180 checkInfo
.lv_file_start
= offsetInFatFile
;
1181 checkInfo
.lv_error_message_size
= sizeof(messageBuffer
);
1182 checkInfo
.lv_error_message
= messageBuffer
;
1183 int res
= fcntl(fd
, F_CHECK_LV
, &checkInfo
);
1185 dyld::throwf("code signature in (%s) not valid for use in process using Library Validation: %s", this->getPath(), messageBuffer
);
1190 void ImageLoaderMachO::validateFirstPages(const struct linkedit_data_command
* codeSigCmd
, int fd
, const uint8_t *fileData
, size_t lenFileData
, off_t offsetInFat
, const LinkContext
& context
)
1193 // rdar://problem/21839703> 15A226d: dyld crashes in mageLoaderMachO::validateFirstPages during dlopen() after encountering an mmap failure
1194 // We need to ignore older code signatures because they will be bad.
1195 if ( this->sdkVersion() < DYLD_PACKED_VERSION(10,9,0) ) {
1199 if (codeSigCmd
!= NULL
) {
1200 void *fdata
= xmmap(NULL
, lenFileData
, PROT_READ
, MAP_SHARED
, fd
, offsetInFat
);
1201 if ( fdata
== MAP_FAILED
) {
1202 int errnoCopy
= errno
;
1203 if ( errnoCopy
== EPERM
) {
1204 if ( dyld::sandboxBlockedMmap(getPath()) )
1205 dyld::throwf("file system sandbox blocked mmap() of '%s'", getPath());
1207 dyld::throwf("code signing blocked mmap() of '%s'", getPath());
1210 dyld::throwf("mmap() errno=%d validating first page of '%s'", errnoCopy
, getPath());
1212 if ( memcmp(fdata
, fileData
, lenFileData
) != 0 )
1213 dyld::throwf("mmap() page compare failed for '%s'", getPath());
1214 munmap(fdata
, lenFileData
);
1219 const char* ImageLoaderMachO::getInstallPath() const
1221 if ( fDylibIDOffset
!= 0 ) {
1222 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
1223 return (char*)dylibID
+ dylibID
->dylib
.name
.offset
;
1228 void ImageLoaderMachO::registerInterposing(const LinkContext
& context
)
1230 // mach-o files advertise interposing by having a __DATA __interpose section
1231 struct InterposeData
{ uintptr_t replacement
; uintptr_t replacee
; };
1232 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1233 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1234 const struct load_command
* cmd
= cmds
;
1235 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1237 case LC_SEGMENT_COMMAND
:
1239 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1240 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1241 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1242 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1243 if ( ((sect
->flags
& SECTION_TYPE
) == S_INTERPOSING
) || ((strcmp(sect
->sectname
, "__interpose") == 0) && (strcmp(seg
->segname
, "__DATA") == 0)) ) {
1244 // <rdar://problem/23929217> Ensure section is within segment
1245 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
1246 dyld::throwf("interpose section has malformed address range for %s\n", this->getPath());
1247 const InterposeData
* interposeArray
= (InterposeData
*)(sect
->addr
+ fSlide
);
1248 const size_t count
= sect
->size
/ sizeof(InterposeData
);
1249 for (size_t j
=0; j
< count
; ++j
) {
1250 ImageLoader::InterposeTuple tuple
;
1251 tuple
.replacement
= interposeArray
[j
].replacement
;
1252 tuple
.neverImage
= this;
1253 tuple
.onlyImage
= NULL
;
1254 tuple
.replacee
= interposeArray
[j
].replacee
;
1255 // <rdar://problem/25686570> ignore interposing on a weak function that does not exist
1256 if ( tuple
.replacee
== 0 )
1258 // <rdar://problem/7937695> verify that replacement is in this image
1259 if ( this->containsAddress((void*)tuple
.replacement
) ) {
1260 // chain to any existing interpositions
1261 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it
!= fgInterposingTuples
.end(); it
++) {
1262 if ( it
->replacee
== tuple
.replacee
) {
1263 tuple
.replacee
= it
->replacement
;
1266 ImageLoader::fgInterposingTuples
.push_back(tuple
);
1274 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1278 uint32_t ImageLoaderMachO::sdkVersion(const mach_header
* mh
)
1280 const uint32_t cmd_count
= mh
->ncmds
;
1281 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
));
1282 const struct load_command
* cmd
= cmds
;
1283 const struct version_min_command
* versCmd
;
1284 const struct build_version_command
* buildVersCmd
;
1285 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1286 switch ( cmd
->cmd
) {
1287 case LC_VERSION_MIN_MACOSX
:
1288 case LC_VERSION_MIN_IPHONEOS
:
1289 case LC_VERSION_MIN_TVOS
:
1290 case LC_VERSION_MIN_WATCHOS
:
1291 versCmd
= (version_min_command
*)cmd
;
1292 return versCmd
->sdk
;
1293 case LC_BUILD_VERSION
:
1294 buildVersCmd
= (build_version_command
*)cmd
;
1295 return buildVersCmd
->sdk
;
1297 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1302 uint32_t ImageLoaderMachO::sdkVersion() const
1304 return ImageLoaderMachO::sdkVersion(machHeader());
1307 uint32_t ImageLoaderMachO::minOSVersion(const mach_header
* mh
)
1309 const uint32_t cmd_count
= mh
->ncmds
;
1310 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
));
1311 const struct load_command
* cmd
= cmds
;
1312 const struct version_min_command
* versCmd
;
1313 const struct build_version_command
* buildVersCmd
;
1314 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1315 switch ( cmd
->cmd
) {
1316 case LC_VERSION_MIN_MACOSX
:
1317 case LC_VERSION_MIN_IPHONEOS
:
1318 case LC_VERSION_MIN_TVOS
:
1319 case LC_VERSION_MIN_WATCHOS
:
1320 versCmd
= (version_min_command
*)cmd
;
1321 return versCmd
->version
;
1322 case LC_BUILD_VERSION
:
1323 buildVersCmd
= (build_version_command
*)cmd
;
1324 return buildVersCmd
->minos
;
1326 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1331 uint32_t ImageLoaderMachO::minOSVersion() const
1333 return ImageLoaderMachO::minOSVersion(machHeader());
1337 void* ImageLoaderMachO::getEntryFromLC_MAIN() const
1339 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1340 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1341 const struct load_command
* cmd
= cmds
;
1342 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1343 if ( cmd
->cmd
== LC_MAIN
) {
1344 entry_point_command
* mainCmd
= (entry_point_command
*)cmd
;
1345 void* entry
= (void*)(mainCmd
->entryoff
+ (char*)fMachOData
);
1346 // <rdar://problem/8543820&9228031> verify entry point is in image
1347 if ( this->containsAddress(entry
) ) {
1348 #if __has_feature(ptrauth_calls)
1349 // start() calls the result pointer as a function pointer so we need to sign it.
1350 return __builtin_ptrauth_sign_unauthenticated(entry
, 0, 0);
1355 throw "LC_MAIN entryoff is out of range";
1357 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1363 void* ImageLoaderMachO::getEntryFromLC_UNIXTHREAD() const
1365 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1366 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1367 const struct load_command
* cmd
= cmds
;
1368 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1369 if ( cmd
->cmd
== LC_UNIXTHREAD
) {
1371 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
1372 void* entry
= (void*)(registers
->eip
+ fSlide
);
1373 // <rdar://problem/8543820&9228031> verify entry point is in image
1374 if ( this->containsAddress(entry
) )
1377 const x86_thread_state64_t
* registers
= (x86_thread_state64_t
*)(((char*)cmd
) + 16);
1378 void* entry
= (void*)(registers
->rip
+ fSlide
);
1379 // <rdar://problem/8543820&9228031> verify entry point is in image
1380 if ( this->containsAddress(entry
) )
1384 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1386 throw "no valid entry point";
1389 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount
, const macho_header
* mh
)
1391 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
1395 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
1396 if ( mh
->filetype
== MH_EXECUTE
)
1399 bool isNonOSdylib
= false;
1400 const uint32_t cmd_count
= mh
->ncmds
;
1401 const struct load_command
* const cmds
= (struct load_command
*)((uint8_t*)mh
+sizeof(macho_header
));
1402 const struct load_command
* cmd
= cmds
;
1403 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1406 case LC_LOAD_WEAK_DYLIB
:
1407 case LC_REEXPORT_DYLIB
:
1408 case LC_LOAD_UPWARD_DYLIB
:
1412 const dylib_command
* dylibID
= (dylib_command
*)cmd
;
1413 const char* installPath
= (char*)cmd
+ dylibID
->dylib
.name
.offset
;
1414 // It is OK for OS dylibs (libSystem or libmath) to have no dependents
1415 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
1416 isNonOSdylib
= ( (strncmp(installPath
, "/usr/lib/", 9) != 0) && (strncmp(installPath
, "/System/DriverKit/usr/lib/", 26) != 0) );
1417 // if (isNonOSdylib) dyld::log("ImageLoaderMachO::needsAddedLibSystemDepency(%s)\n", installPath);
1421 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1423 return isNonOSdylib
;
1427 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[])
1429 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) {
1430 DependentLibraryInfo
* lib
= &libs
[0];
1431 lib
->name
= LIBSYSTEM_DYLIB_PATH
;
1432 lib
->info
.checksum
= 0;
1433 lib
->info
.minVersion
= 0;
1434 lib
->info
.maxVersion
= 0;
1435 lib
->required
= false;
1436 lib
->reExported
= false;
1437 lib
->upward
= false;
1441 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1442 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1443 const struct load_command
* cmd
= cmds
;
1444 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1447 case LC_LOAD_WEAK_DYLIB
:
1448 case LC_REEXPORT_DYLIB
:
1449 case LC_LOAD_UPWARD_DYLIB
:
1451 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
1452 DependentLibraryInfo
* lib
= &libs
[index
++];
1453 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
1454 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1455 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
1456 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
1457 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
1458 lib
->required
= (cmd
->cmd
!= LC_LOAD_WEAK_DYLIB
);
1459 lib
->reExported
= (cmd
->cmd
== LC_REEXPORT_DYLIB
);
1460 lib
->upward
= (cmd
->cmd
== LC_LOAD_UPWARD_DYLIB
);
1464 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1469 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo(const LibraryInfo
&)
1472 if ( fDylibIDOffset
!= 0 ) {
1473 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
1474 info
.minVersion
= dylibID
->dylib
.compatibility_version
;
1475 info
.maxVersion
= dylibID
->dylib
.current_version
;
1476 info
.checksum
= dylibID
->dylib
.timestamp
;
1479 info
.minVersion
= 0;
1480 info
.maxVersion
= 0;
1486 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const
1488 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1489 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1490 const struct load_command
* cmd
= cmds
;
1491 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1494 const char* pathToAdd
= NULL
;
1495 const char* path
= (char*)cmd
+ ((struct rpath_command
*)cmd
)->path
.offset
;
1496 if ( (strncmp(path
, "@loader_path", 12) == 0) && ((path
[12] == '/') || (path
[12] == '\0')) ) {
1497 if ( !context
.allowAtPaths
&& (context
.mainExecutable
== this) ) {
1498 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path (Codesign main executable with Library Validation to allow @ paths)\n", path
, this->getPath());
1501 char resolvedPath
[PATH_MAX
];
1502 if ( realpath(this->getPath(), resolvedPath
) != NULL
) {
1503 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1504 strcpy(newRealPath
, resolvedPath
);
1505 char* addPoint
= strrchr(newRealPath
,'/');
1506 if ( addPoint
!= NULL
) {
1507 strcpy(addPoint
, &path
[12]);
1508 pathToAdd
= strdup(newRealPath
);
1512 else if ( (strncmp(path
, "@executable_path", 16) == 0) && ((path
[16] == '/') || (path
[16] == '\0')) ) {
1513 if ( !context
.allowAtPaths
) {
1514 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path (Codesign main executable with Library Validation to allow @ paths)\n", path
, this->getPath());
1517 char resolvedPath
[PATH_MAX
];
1518 if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL
) {
1519 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1520 strcpy(newRealPath
, resolvedPath
);
1521 char* addPoint
= strrchr(newRealPath
,'/');
1522 if ( addPoint
!= NULL
) {
1523 strcpy(addPoint
, &path
[16]);
1524 pathToAdd
= strdup(newRealPath
);
1528 else if ( (path
[0] != '/') && !context
.allowAtPaths
) {
1529 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path
, this->getPath());
1532 #if SUPPORT_ROOT_PATH
1533 else if ( (path
[0] == '/') && (context
.rootPaths
!= NULL
) ) {
1534 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
1535 // <rdar://problem/49576123> Even if DYLD_ROOT_PATH exists, LC_RPATH should add raw path to rpaths
1536 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
1537 for (const char** rp
= context
.rootPaths
; *rp
!= NULL
; ++rp
) {
1538 char newPath
[PATH_MAX
];
1539 strlcpy(newPath
, *rp
, PATH_MAX
);
1540 strlcat(newPath
, path
, PATH_MAX
);
1541 struct stat stat_buf
;
1542 if ( dyld3::stat(newPath
, &stat_buf
) != -1 ) {
1543 // dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
1544 paths
.push_back(strdup(newPath
));
1547 // add in raw absolute path without root prefix
1548 pathToAdd
= strdup(path
);
1552 // realpath() is slow, and /usr/lib/swift is a real path, so don't realpath it
1553 if ( strcmp(path
, "/usr/lib/swift") != 0 ) {
1554 char resolvedPath
[PATH_MAX
];
1555 if ( (realpath(path
, resolvedPath
) != NULL
) && (strcmp(path
, resolvedPath
) != 0) ) {
1556 // <rdar://problem/45470293> support LC_RPATH symlinks to directories of things in the dyld cache
1557 path
= resolvedPath
;
1560 // make copy so that all elements of 'paths' can be freed
1561 pathToAdd
= strdup(path
);
1563 if ( pathToAdd
!= NULL
)
1564 paths
.push_back(pathToAdd
);
1567 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1572 bool ImageLoaderMachO::getUUID(uuid_t uuid
) const
1574 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1575 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1576 const struct load_command
* cmd
= cmds
;
1577 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1580 uuid_command
* uc
= (uuid_command
*)cmd
;
1581 memcpy(uuid
, uc
->uuid
, 16);
1584 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1590 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1592 // <rdar://problem/25329861> Delay calling setNeverUnload() until we know this is not for dlopen_preflight()
1593 if ( fRetainForObjC
)
1594 this->setNeverUnload();
1596 // dylibs with thread local variables cannot be unloaded because there is no way to clean up all threads
1597 if ( !this->inSharedCache() && (this->machHeader()->flags
& MH_HAS_TLV_DESCRIPTORS
) )
1598 this->setNeverUnload();
1600 // if prebound and loaded at prebound address, then no need to rebase
1601 if ( this->usablePrebinding(context
) ) {
1602 // skip rebasing because prebinding is valid
1603 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1607 // print why prebinding was not used
1608 if ( context
.verbosePrebinding
) {
1609 if ( !this->isPrebindable() ) {
1610 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1612 else if ( fSlide
!= 0 ) {
1613 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1615 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1616 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1618 else if ( !this->usesTwoLevelNameSpace() ){
1619 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1622 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1626 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1628 #if PREBOUND_IMAGE_SUPPORT
1629 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1630 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1631 if ( this->isPrebindable() && !fInSharedCache
)
1632 this->resetPreboundLazyPointers(context
);
1635 // if loaded at preferred address, no rebasing necessary
1636 if ( this->fSlide
== 0 )
1639 #if TEXT_RELOC_SUPPORT
1640 // if there are __TEXT fixups, temporarily make __TEXT writable
1641 if ( fTextSegmentRebases
)
1642 this->makeTextSegmentWritable(context
, true);
1645 // do actual rebasing
1646 this->rebase(context
, fSlide
);
1648 #if TEXT_RELOC_SUPPORT
1649 // if there were __TEXT fixups, restore write protection
1650 if ( fTextSegmentRebases
)
1651 this->makeTextSegmentWritable(context
, false);
1656 #if TEXT_RELOC_SUPPORT
1657 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext
& context
, bool writeable
)
1659 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1660 if ( segExecutable(i
) ) {
1662 segMakeWritable(i
, context
);
1665 #if !__i386__ && !__x86_64__
1666 // some processors require range to be invalidated before it is made executable
1667 sys_icache_invalidate((void*)segActualLoadAddress(i
), segSize(textSegmentIndex
));
1669 segProtect(i
, context
);
1677 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, bool searchReExports
, const char* thisPath
, const ImageLoader
** foundIn
) const
1679 // look in this image first
1680 const ImageLoader::Symbol
* result
= this->findShallowExportedSymbol(name
, foundIn
);
1681 if ( result
!= NULL
)
1684 if ( searchReExports
) {
1685 for(unsigned int i
=0; i
< libraryCount(); ++i
){
1686 if ( libReExported(i
) ) {
1687 ImageLoader
* image
= libImage(i
);
1688 if ( image
!= NULL
) {
1689 const char* reExPath
= libPath(i
);
1690 result
= image
->findExportedSymbol(name
, searchReExports
, reExPath
, foundIn
);
1691 if ( result
!= NULL
)
1704 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
1705 const ImageLoader
* requestor
, bool runResolver
, const char* symbolName
) const
1707 return this->getSymbolAddress(sym
, requestor
, context
, runResolver
);
1710 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol
* sym
, const ImageLoader
* requestor
,
1711 const LinkContext
& context
, bool runResolver
) const
1713 uintptr_t result
= exportedSymbolAddress(context
, sym
, requestor
, runResolver
);
1714 // check for interposing overrides
1715 result
= interposedAddress(context
, result
, requestor
);
1719 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1721 if ( exportedSymbolIsWeakDefintion(sym
) )
1722 return kWeakDefinition
;
1724 return kNoDefinitionOptions
;
1727 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1729 return exportedSymbolName(sym
);
1732 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1734 return exportedSymbolCount();
1738 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1740 return exportedSymbolIndexed(index
);
1744 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1746 return importedSymbolCount();
1750 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1752 return importedSymbolIndexed(index
);
1756 ImageLoader::ReferenceFlags
ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1758 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1763 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1765 return importedSymbolName(sym
);
1769 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1771 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1772 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1773 const struct load_command
* cmd
= cmds
;
1774 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1776 case LC_SEGMENT_COMMAND
:
1778 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1779 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1780 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1781 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1782 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1783 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1784 *length
= sect
->size
;
1791 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1798 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections
* info
)
1800 info
->mh
= this->machHeader();
1801 info
->dwarf_section
= 0;
1802 info
->dwarf_section_length
= 0;
1803 info
->compact_unwind_section
= 0;
1804 info
->compact_unwind_section_length
= 0;
1805 if ( fEHFrameSectionOffset
!= 0 ) {
1806 const macho_section
* sect
= (macho_section
*)&fMachOData
[fEHFrameSectionOffset
];
1807 info
->dwarf_section
= (void*)(sect
->addr
+ fSlide
);
1808 info
->dwarf_section_length
= sect
->size
;
1810 if ( fUnwindInfoSectionOffset
!= 0 ) {
1811 const macho_section
* sect
= (macho_section
*)&fMachOData
[fUnwindInfoSectionOffset
];
1812 info
->compact_unwind_section
= (void*)(sect
->addr
+ fSlide
);
1813 info
->compact_unwind_section_length
= sect
->size
;
1817 intptr_t ImageLoaderMachO::computeSlide(const mach_header
* mh
)
1819 const uint32_t cmd_count
= mh
->ncmds
;
1820 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
1821 const load_command
* cmd
= cmds
;
1822 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1823 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1824 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
1825 if ( strcmp(seg
->segname
, "__TEXT") == 0 )
1826 return (char*)mh
- (char*)(seg
->vmaddr
);
1828 cmd
= (const load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1833 bool ImageLoaderMachO::findSection(const mach_header
* mh
, const char* segmentName
, const char* sectionName
, void** sectAddress
, size_t* sectSize
)
1835 const uint32_t cmd_count
= mh
->ncmds
;
1836 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
1837 const load_command
* cmd
= cmds
;
1838 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1840 case LC_SEGMENT_COMMAND
:
1842 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
1843 const macho_section
* const sectionsStart
= (macho_section
*)((char*)seg
+ sizeof(macho_segment_command
));
1844 const macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1845 for (const macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1846 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1847 *sectAddress
= (void*)(sect
->addr
+ computeSlide(mh
));
1848 *sectSize
= sect
->size
;
1855 cmd
= (const load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1861 const macho_section
* ImageLoaderMachO::findSection(const void* imageInterior
) const
1863 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1864 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1865 const struct load_command
* cmd
= cmds
;
1866 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1867 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1869 case LC_SEGMENT_COMMAND
:
1871 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1872 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1873 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1874 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1875 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1876 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1884 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1890 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1892 if (const struct macho_section
* sect
= findSection(imageInterior
)) {
1893 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1894 if ( segmentName
!= NULL
)
1895 *segmentName
= sect
->segname
;
1896 if ( sectionName
!= NULL
)
1897 *sectionName
= sect
->sectname
;
1898 if ( sectionOffset
!= NULL
)
1899 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1905 const char* ImageLoaderMachO::libPath(unsigned int index
) const
1907 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1908 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1909 const struct load_command
* cmd
= cmds
;
1911 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1912 switch ( cmd
->cmd
) {
1914 case LC_LOAD_WEAK_DYLIB
:
1915 case LC_REEXPORT_DYLIB
:
1916 case LC_LOAD_UPWARD_DYLIB
:
1917 if ( index
== count
) {
1918 const struct dylib_command
* dylibCmd
= (struct dylib_command
*)cmd
;
1919 return (char*)cmd
+ dylibCmd
->dylib
.name
.offset
;
1924 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1927 // <rdar://problem/24256354> if image linked with nothing and we implicitly added libSystem.dylib, return that
1928 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) {
1929 return LIBSYSTEM_DYLIB_PATH
;
1936 void __attribute__((noreturn
)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext
& context
, const char* symbol
,
1937 const char* referencedFrom
, const char* fromVersMismatch
,
1938 const char* expectedIn
)
1940 // record values for possible use by CrashReporter or Finder
1941 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_SYMBOL_MISSING
, referencedFrom
, expectedIn
, symbol
);
1942 dyld::throwf("Symbol not found: %s\n Referenced from: %s%s\n Expected in: %s\n",
1943 symbol
, referencedFrom
, fromVersMismatch
, expectedIn
);
1946 const mach_header
* ImageLoaderMachO::machHeader() const
1948 return (mach_header
*)fMachOData
;
1951 uintptr_t ImageLoaderMachO::getSlide() const
1956 // hmm. maybe this should be up in ImageLoader??
1957 const void* ImageLoaderMachO::getEnd() const
1959 uintptr_t lastAddress
= 0;
1960 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1961 uintptr_t segEnd
= segActualEndAddress(i
);
1962 if ( strcmp(segName(i
), "__UNIXSTACK") != 0 ) {
1963 if ( segEnd
> lastAddress
)
1964 lastAddress
= segEnd
;
1967 return (const void*)lastAddress
;
1970 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext
& context
, uintptr_t baseVMAddress
,
1971 uintptr_t location
, uintptr_t value
,
1972 uint8_t type
, const char* symbolName
,
1973 intptr_t addend
, const char* inPath
, const char* toPath
, const char* msg
,
1974 ExtraBindData
*extraBindData
, uintptr_t slide
)
1976 auto logBind
= [&]() {
1977 if ( !context
.verboseBind
)
1979 if ( addend
!= 0 ) {
1980 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1981 msg
, shortName(inPath
), (uintptr_t)location
,
1982 ((toPath
!= NULL
) ? shortName(toPath
) : "<missing weak_import>"),
1983 symbolName
, (uintptr_t)location
, value
, addend
);
1985 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1986 msg
, shortName(inPath
), (uintptr_t)location
,
1987 ((toPath
!= NULL
) ? shortName(toPath
) : "<missing weak_import>"),
1988 symbolName
, (uintptr_t)location
, value
);
1994 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
1998 uintptr_t* locationToFix
= (uintptr_t*)location
;
2000 uintptr_t newValue
= value
+addend
;
2003 case BIND_TYPE_POINTER
:
2005 // test first so we don't needless dirty pages
2006 if ( *locationToFix
!= newValue
)
2007 *locationToFix
= newValue
;
2009 case BIND_TYPE_TEXT_ABSOLUTE32
:
2011 loc32
= (uint32_t*)locationToFix
;
2012 value32
= (uint32_t)newValue
;
2013 if ( *loc32
!= value32
)
2016 case BIND_TYPE_TEXT_PCREL32
:
2018 loc32
= (uint32_t*)locationToFix
;
2019 value32
= (uint32_t)(newValue
- (((uintptr_t)locationToFix
) + 4));
2020 if ( *loc32
!= value32
)
2023 case BIND_TYPE_THREADED_BIND
:
2025 // test first so we don't needless dirty pages
2026 if ( *locationToFix
!= newValue
)
2027 *locationToFix
= newValue
;
2029 case BIND_TYPE_THREADED_REBASE
: {
2030 // Regular pointer which needs to fit in 51-bits of value.
2031 // C++ RTTI uses the top bit, so we'll allow the whole top-byte
2032 // and the signed-extended bottom 43-bits to be fit in to 51-bits.
2033 uint64_t top8Bits
= *locationToFix
& 0x0007F80000000000ULL
;
2034 uint64_t bottom43Bits
= *locationToFix
& 0x000007FFFFFFFFFFULL
;
2035 uint64_t targetValue
= ( top8Bits
<< 13 ) | (((intptr_t)(bottom43Bits
<< 21) >> 21) & 0x00FFFFFFFFFFFFFF);
2036 newValue
= (uintptr_t)(targetValue
+ slide
);
2037 if ( context
.verboseRebase
) {
2038 dyld::log("dyld: rebase: %s:*0x%08lX += 0x%08lX = 0x%08lX\n", shortName(inPath
), (uintptr_t)locationToFix
, slide
, newValue
);
2040 *locationToFix
= newValue
;
2044 dyld::throwf("bad bind type %d", type
);
2047 // update statistics
2048 ++fgTotalBindFixups
;
2057 #if SUPPORT_OLD_CRT_INITIALIZATION
2058 // first 16 bytes of "start" in crt1.o
2060 static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
2065 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper
2066 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2067 // the following only exist in main executables built for 10.5 or later
2071 // These are defined in dyldStartup.s
2072 extern "C" void stub_binding_helper();
2073 extern "C" int _dyld_func_lookup(const char* name
, void** address
);
2075 static const char* libDyldPath(const ImageLoader::LinkContext
& context
)
2078 if ( context
.driverKit
)
2079 return DRIVERKIT_LIBDYLD_DYLIB_PATH
;
2082 return LIBDYLD_DYLIB_PATH
;
2085 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
2087 const macho_header
* mh
= (macho_header
*)fMachOData
;
2088 const uint32_t cmd_count
= mh
->ncmds
;
2089 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2090 const struct load_command
* cmd
;
2091 // There used to be some optimizations to skip this section scan, but we need to handle the
2092 // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
2093 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
2096 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2097 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2098 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2099 if ( strncmp(seg
->segname
, "__DATA", 6) == 0 ) {
2100 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2101 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2102 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2103 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) {
2104 struct DATAdyld
* dd
= (struct DATAdyld
*)(sect
->addr
+ fSlide
);
2105 #if !__arm64__ && !__ARM_ARCH_7K__
2106 if ( sect
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
2107 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
2108 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
2110 #endif // !__arm64__
2111 // <rdar://problem/40352925> Add work around for existing apps that have deprecated __dyld section
2112 const char* installNm
= this->getInstallPath();
2113 if ( (mh
->filetype
!= MH_DYLIB
) || (installNm
== NULL
) || (strcmp(installNm
, libDyldPath(context
)) != 0) ) {
2115 // don't allow macOS apps build with 10.14 or later SDK and targeting 10.8 or later to have a __dyld section
2116 if ( (minOSVersion() >= 0x000a0800) && (sdkVersion() >= 0x000a0e00) )
2117 dyld::throwf("__dyld section not supported in %s", this->getPath());
2119 #if TARGET_OS_IOS || TARGET_OS_TV
2120 // don't allow iOS apps build with 12.0 or later SDK to have a __dyld section
2121 if ( sdkVersion() >= 0x000c0000 )
2122 dyld::throwf("__dyld section not supported in %s", this->getPath());
2125 if ( sdkVersion() >= 0x00050000 )
2126 dyld::throwf("__dyld section not supported in %s", this->getPath());
2129 if ( sect
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
2130 if ( dd
->dyldFuncLookup
!= (void*)&_dyld_func_lookup
)
2131 dd
->dyldFuncLookup
= (void*)&_dyld_func_lookup
;
2133 if ( mh
->filetype
== MH_EXECUTE
) {
2134 // there are two ways to get the program variables
2135 if ( (sect
->size
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh
== mh
) ) {
2136 // some really old binaries have space for vars, but it is zero filled
2137 // main executable has 10.5 style __dyld section that has program variable pointers
2138 context
.setNewProgramVars(dd
->vars
);
2141 // main executable is pre-10.5 and requires the symbols names to be looked up
2142 this->lookupProgramVars(context
);
2143 #if SUPPORT_OLD_CRT_INITIALIZATION
2144 // If the first 16 bytes of the entry point's instructions do not
2145 // match what crt1.o supplies, then the program has a custom entry point.
2146 // This means it might be doing something that needs to be executed before
2147 // initializers are run.
2148 if ( memcmp(this->getEntryFromLC_UNIXTHREAD(), sStandardEntryPointInstructions
, 16) != 0 ) {
2149 if ( context
.verboseInit
)
2150 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
2151 context
.setRunInitialzersOldWay();
2156 else if ( mh
->filetype
== MH_DYLIB
) {
2157 const char* installPath
= this->getInstallPath();
2158 if ( (installPath
!= NULL
) && ((strncmp(installPath
, "/usr/lib/", 9) == 0) || (strncmp(installPath
, "/System/DriverKit/usr/lib/", 26) == 0)) ) {
2159 if ( sect
->size
> offsetof(DATAdyld
, vars
) ) {
2160 // use ProgramVars from libdyld.dylib but tweak mh field to correct value
2161 dd
->vars
.mh
= context
.mainExecutable
->machHeader();
2162 context
.setNewProgramVars(dd
->vars
);
2167 else if ( (strcmp(sect
->sectname
, "__program_vars" ) == 0) && (mh
->filetype
== MH_EXECUTE
) ) {
2168 // this is a Mac OS X 10.6 or later main executable
2169 struct ProgramVars
* pv
= (struct ProgramVars
*)(sect
->addr
+ fSlide
);
2170 context
.setNewProgramVars(*pv
);
2175 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2181 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const
2183 ProgramVars vars
= context
.programVars
;
2184 const ImageLoader::Symbol
* sym
;
2186 // get mach header directly
2187 vars
.mh
= (macho_header
*)fMachOData
;
2190 sym
= this->findShallowExportedSymbol("_NXArgc", NULL
);
2192 vars
.NXArgcPtr
= (int*)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2195 sym
= this->findShallowExportedSymbol("_NXArgv", NULL
);
2197 vars
.NXArgvPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2200 sym
= this->findShallowExportedSymbol("_environ", NULL
);
2202 vars
.environPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2204 // lookup __progname
2205 sym
= this->findShallowExportedSymbol("___progname", NULL
);
2207 vars
.__prognamePtr
= (const char**)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2209 context
.setNewProgramVars(vars
);
2213 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
2215 // dylibs in dyld cache do not need to be rebased or bound
2216 // for chained fixups always pretend dylib is up to date, patch tables will be used later
2217 if ( fInSharedCache
&& (this->allDependentLibrariesAsWhenPreBound() || context
.dyldCache
->header
.builtFromChainedFixups
) ) {
2218 // allow environment variables to disable prebinding
2219 if ( context
.bindFlat
)
2221 switch ( context
.prebindUsage
) {
2222 case kUseAllPrebinding
:
2224 case kUseSplitSegPrebinding
:
2225 return this->fIsSplitSeg
;
2226 case kUseAllButAppPredbinding
:
2227 return (this != context
.mainExecutable
);
2228 case kUseNoPrebinding
:
2235 static void *stripPointer(void *ptr
) {
2236 #if __has_feature(ptrauth_calls)
2237 return __builtin_ptrauth_strip(ptr
, ptrauth_key_asia
);
2244 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
2246 if ( fHasDashInit
) {
2247 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2248 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2249 const struct load_command
* cmd
= cmds
;
2250 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2252 case LC_ROUTINES_COMMAND
:
2253 Initializer func
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address
+ fSlide
);
2254 #if __has_feature(ptrauth_calls)
2255 func
= (Initializer
)__builtin_ptrauth_sign_unauthenticated((void*)func
, ptrauth_key_asia
, 0);
2257 // <rdar://problem/8543820&9228031> verify initializers are in image
2258 if ( ! this->containsAddress(stripPointer((void*)func
)) ) {
2259 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
2261 if ( ! dyld::gProcessInfo
->libSystemInitialized
) {
2262 // <rdar://problem/17973316> libSystem initializer must run first
2263 dyld::throwf("-init function in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2265 if ( context
.verboseInit
)
2266 dyld::log("dyld: calling -init function %p in %s\n", func
, this->getPath());
2268 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)fMachOData
, (uint64_t)func
, 0);
2269 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
2273 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2278 static const char* libSystemPath(const ImageLoader::LinkContext
& context
)
2281 if ( context
.driverKit
)
2282 return DRIVERKIT_LIBSYSTEM_DYLIB_PATH
;
2285 return LIBSYSTEM_DYLIB_PATH
;
2290 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
2292 if ( fHasInitializers
) {
2293 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2294 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2295 const struct load_command
* cmd
= cmds
;
2296 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2297 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2298 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2299 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2300 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2301 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2302 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2303 if ( type
== S_MOD_INIT_FUNC_POINTERS
) {
2304 Initializer
* inits
= (Initializer
*)(sect
->addr
+ fSlide
);
2305 const size_t count
= sect
->size
/ sizeof(uintptr_t);
2306 // <rdar://problem/23929217> Ensure __mod_init_func section is within segment
2307 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
2308 dyld::throwf("__mod_init_funcs section has malformed address range for %s\n", this->getPath());
2309 for (size_t j
=0; j
< count
; ++j
) {
2310 Initializer func
= inits
[j
];
2311 // <rdar://problem/8543820&9228031> verify initializers are in image
2312 if ( ! this->containsAddress(stripPointer((void*)func
)) ) {
2313 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
2315 if ( ! dyld::gProcessInfo
->libSystemInitialized
) {
2316 // <rdar://problem/17973316> libSystem initializer must run first
2317 const char* installPath
= getInstallPath();
2318 if ( (installPath
== NULL
) || (strcmp(installPath
, libSystemPath(context
)) != 0) )
2319 dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2321 if ( context
.verboseInit
)
2322 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath());
2323 bool haveLibSystemHelpersBefore
= (dyld::gLibSystemHelpers
!= NULL
);
2325 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)fMachOData
, (uint64_t)func
, 0);
2326 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
2328 bool haveLibSystemHelpersAfter
= (dyld::gLibSystemHelpers
!= NULL
);
2329 if ( !haveLibSystemHelpersBefore
&& haveLibSystemHelpersAfter
) {
2330 // now safe to use malloc() and other calls in libSystem.dylib
2331 dyld::gProcessInfo
->libSystemInitialized
= true;
2335 else if ( type
== S_INIT_FUNC_OFFSETS
) {
2336 const uint32_t* inits
= (uint32_t*)(sect
->addr
+ fSlide
);
2337 const size_t count
= sect
->size
/ sizeof(uint32_t);
2338 // Ensure section is within segment
2339 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
2340 dyld::throwf("__init_offsets section has malformed address range for %s\n", this->getPath());
2341 if ( seg
->initprot
& VM_PROT_WRITE
)
2342 dyld::throwf("__init_offsets section is not in read-only segment %s\n", this->getPath());
2343 for (size_t j
=0; j
< count
; ++j
) {
2344 uint32_t funcOffset
= inits
[j
];
2345 // verify initializers are in image
2346 if ( ! this->containsAddress((uint8_t*)this->machHeader() + funcOffset
) ) {
2347 dyld::throwf("initializer function offset 0x%08X not in mapped image for %s\n", funcOffset
, this->getPath());
2349 if ( ! dyld::gProcessInfo
->libSystemInitialized
) {
2350 // <rdar://problem/17973316> libSystem initializer must run first
2351 const char* installPath
= getInstallPath();
2352 if ( (installPath
== NULL
) || (strcmp(installPath
, libSystemPath(context
)) != 0) )
2353 dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2355 Initializer func
= (Initializer
)((uint8_t*)this->machHeader() + funcOffset
);
2356 if ( context
.verboseInit
)
2357 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath());
2358 #if __has_feature(ptrauth_calls)
2359 func
= (Initializer
)__builtin_ptrauth_sign_unauthenticated((void*)func
, ptrauth_key_asia
, 0);
2361 bool haveLibSystemHelpersBefore
= (dyld::gLibSystemHelpers
!= NULL
);
2363 dyld3::ScopedTimer(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)fMachOData
, (uint64_t)func
, 0);
2364 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
2366 bool haveLibSystemHelpersAfter
= (dyld::gLibSystemHelpers
!= NULL
);
2367 if ( !haveLibSystemHelpersBefore
&& haveLibSystemHelpersAfter
) {
2368 // now safe to use malloc() and other calls in libSystem.dylib
2369 dyld::gProcessInfo
->libSystemInitialized
= true;
2375 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2382 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
)
2384 if ( fHasDOFSections
) {
2385 // walk load commands (mapped in at start of __TEXT segment)
2386 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2387 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2388 const struct load_command
* cmd
= cmds
;
2389 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2391 case LC_SEGMENT_COMMAND
:
2393 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2394 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2395 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2396 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2397 if ( (sect
->flags
& SECTION_TYPE
) == S_DTRACE_DOF
) {
2398 // <rdar://problem/23929217> Ensure section is within segment
2399 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
2400 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2401 ImageLoader::DOFInfo info
;
2402 info
.dof
= (void*)(sect
->addr
+ fSlide
);
2403 info
.imageHeader
= this->machHeader();
2404 info
.imageShortName
= this->getShortName();
2405 dofs
.push_back(info
);
2411 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2417 bool ImageLoaderMachO::doInitialization(const LinkContext
& context
)
2419 CRSetCrashLogMessage2(this->getPath());
2421 // mach-o has -init and static initializers
2422 doImageInit(context
);
2423 doModInitFunctions(context
);
2425 CRSetCrashLogMessage2(NULL
);
2427 return (fHasDashInit
|| fHasInitializers
);
2430 bool ImageLoaderMachO::needsInitialization()
2432 return ( fHasDashInit
|| fHasInitializers
);
2436 bool ImageLoaderMachO::needsTermination()
2438 return fHasTerminators
;
2442 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
2444 if ( fHasTerminators
) {
2445 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2446 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2447 const struct load_command
* cmd
= cmds
;
2448 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2449 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2450 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2451 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2452 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2453 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2454 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2455 if ( type
== S_MOD_TERM_FUNC_POINTERS
) {
2456 // <rdar://problem/23929217> Ensure section is within segment
2457 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
2458 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2459 Terminator
* terms
= (Terminator
*)(sect
->addr
+ fSlide
);
2460 const size_t count
= sect
->size
/ sizeof(uintptr_t);
2461 for (size_t j
=count
; j
> 0; --j
) {
2462 Terminator func
= terms
[j
-1];
2463 #if __has_feature(ptrauth_calls)
2464 func
= (Terminator
)__builtin_ptrauth_sign_unauthenticated((void*)func
, ptrauth_key_asia
, 0);
2466 // <rdar://problem/8543820&9228031> verify terminators are in image
2467 if ( ! this->containsAddress(stripPointer((void*)func
)) ) {
2468 dyld::throwf("termination function %p not in mapped image for %s\n", func
, this->getPath());
2470 if ( context
.verboseInit
)
2471 dyld::log("dyld: calling termination function %p in %s\n", func
, this->getPath());
2477 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2483 void ImageLoaderMachO::printStatisticsDetails(unsigned int imageCount
, const InitializerTimingList
& timingInfo
)
2485 ImageLoader::printStatisticsDetails(imageCount
, timingInfo
);
2486 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs
);
2487 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs
);
2488 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions
);
2489 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing
);
2492 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext
& context
, size_t extraAllocationSize
)
2494 // preflight and calculate slide if needed
2495 const bool inPIE
= (fgNextPIEDylibAddress
!= 0);
2497 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
2498 intptr_t segmentReAlignSlide
= 0;
2499 bool needsToSlide
= false;
2500 bool imageHasPreferredLoadAddress
= segHasPreferredLoadAddress(0);
2501 uintptr_t lowAddr
= (unsigned long)(-1);
2502 uintptr_t highAddr
= 0;
2503 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2504 const uintptr_t segLow
= segPreferredLoadAddress(i
);
2505 const uintptr_t segHigh
= dyld_page_round(segLow
+ segSize(i
));
2506 if ( segLow
< highAddr
) {
2507 if ( dyld_page_size
> 4096 )
2508 dyld::throwf("can't map segments into 16KB pages");
2510 dyld::throwf("overlapping segments");
2512 if ( segLow
< lowAddr
)
2514 if ( segHigh
> highAddr
)
2517 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2518 // For Cambria on Aruba systems (16k page size), realign the image so the first segment ends on a 16k boundry.
2519 // FIXME: this can be removed when Aruba dev systems are no longer supported.
2520 if ( dyld::isTranslated() && vm_page_size
== 0x4000 && i
== 0 && segLow
== 0 ) {
2521 const uintptr_t segHighPageOffset
= segHigh
& vm_page_mask
;
2522 if ( segHighPageOffset
> 0 ) {
2523 // Adjust the slide to make the first segment end on a page boundry.
2524 needsToSlide
= true;
2525 segmentReAlignSlide
= vm_page_size
- segHighPageOffset
;
2527 if (context
.verboseMapping
) {
2528 dyld::log("dyld: Image %s first segment(%s) does not end on a page boundry [0x%lx, 0x%lx) adding 0x%lx to slide to realign\n", getPath(), segName(i
), segLow
, segHigh
, segmentReAlignSlide
);
2533 if ( needsToSlide
|| !imageHasPreferredLoadAddress
|| inPIE
|| !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
2534 needsToSlide
= true;
2536 if ( needsToSlide
) {
2537 // find a chunk of address space to hold all segments
2538 size_t size
= highAddr
-lowAddr
+segmentReAlignSlide
;
2539 uintptr_t addr
= reserveAnAddressRange(size
+extraAllocationSize
, context
);
2540 slide
= addr
- lowAddr
+ segmentReAlignSlide
;
2541 } else if ( extraAllocationSize
) {
2542 if (!reserveAddressRange(highAddr
, extraAllocationSize
)) {
2543 throw "failed to reserve space for aot";
2547 else if ( ! this->segmentsCanSlide() ) {
2548 uintptr_t highAddr
= 0;
2549 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2550 const uintptr_t segLow
= segPreferredLoadAddress(i
);
2551 const uintptr_t segHigh
= dyld_page_round(segLow
+ segSize(i
));
2553 if ( segHigh
> highAddr
)
2556 if ( (strcmp(segName(i
), "__PAGEZERO") == 0) && (segFileSize(i
) == 0) && (segPreferredLoadAddress(i
) == 0) )
2558 if ( !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
2559 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i
), segPreferredLoadAddress(i
), segSize(i
));
2561 if (extraAllocationSize
) {
2562 dyld::throwf("binaries with non-slidable segments don't support aot: %s", this->getPath());
2566 throw "mach-o does not support independently sliding segments";
2572 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
)
2574 vm_address_t addr
= 0;
2575 vm_size_t size
= length
;
2576 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
2577 if ( fgNextPIEDylibAddress
!= 0 ) {
2578 // add small (0-3 pages) random padding between dylibs
2579 addr
= fgNextPIEDylibAddress
+ (__stack_chk_guard
/fgNextPIEDylibAddress
& (sizeof(long)-1))*dyld_page_size
;
2580 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
2581 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2582 if ( r
== KERN_SUCCESS
) {
2583 fgNextPIEDylibAddress
= addr
+ size
;
2586 fgNextPIEDylibAddress
= 0;
2588 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2589 if ( r
!= KERN_SUCCESS
)
2590 throw "out of address space";
2595 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start
, size_t length
)
2597 vm_address_t addr
= start
;
2598 vm_size_t size
= length
;
2599 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2600 if ( r
!= KERN_SUCCESS
)
2605 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
2607 uint64_t extra_allocation_size
= 0;
2609 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2610 if (dyld::isTranslated()) {
2611 fAotPath
= new char[PATH_MAX
];
2612 int ret
= syscall(0x7000001, fd
, this->getPath(), &extra_allocation_size
, fAotPath
, PATH_MAX
);
2620 // find address range for image
2621 intptr_t slide
= this->assignSegmentAddresses(context
, extra_allocation_size
);
2622 if ( context
.verboseMapping
) {
2623 if ( offsetInFat
!= 0 )
2624 dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat
);
2626 dyld::log("dyld: Mapping %s\n", this->getPath());
2629 // <rdar://problem/47163421> speculatively read whole slice
2630 fspecread_t specread
= {} ;
2631 specread
.fsr_offset
= offsetInFat
;
2632 specread
.fsr_length
= lenInFat
;
2633 specread
.fsr_flags
= 0;
2634 fcntl(fd
, F_SPECULATIVE_READ
, &specread
);
2635 if ( context
.verboseMapping
)
2636 dyld::log("dyld: Speculatively read offset=0x%08llX, len=0x%08llX, path=%s\n", offsetInFat
, lenInFat
, this->getPath());
2638 // map in all segments
2639 uintptr_t baseAddress
= (unsigned long)(-1);
2640 uintptr_t endAddress
= 0;
2641 uintptr_t mappedMachHeaderAddress
= 0;
2642 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2643 vm_offset_t fileOffset
= (vm_offset_t
)(segFileOffset(i
) + offsetInFat
);
2644 vm_size_t size
= segFileSize(i
);
2645 uintptr_t requestedLoadAddress
= segPreferredLoadAddress(i
) + slide
;
2646 const uintptr_t segmentEnd
= dyld_page_round(requestedLoadAddress
+ segSize(i
));
2648 if ( requestedLoadAddress
< baseAddress
)
2649 baseAddress
= requestedLoadAddress
;
2650 if ( segmentEnd
> endAddress
)
2651 endAddress
= segmentEnd
;
2653 if (segFileOffset(i
) == 0 && segFileSize(i
) != 0) {
2654 mappedMachHeaderAddress
= requestedLoadAddress
;
2658 if ( !segUnaccessible(i
) ) {
2659 if ( segExecutable(i
) )
2660 protection
|= PROT_EXEC
;
2661 if ( segReadable(i
) )
2662 protection
|= PROT_READ
;
2663 if ( segWriteable(i
) ) {
2664 protection
|= PROT_WRITE
;
2665 // rdar://problem/22525618 force __LINKEDIT to always be mapped read-only
2666 if ( strcmp(segName(i
), "__LINKEDIT") == 0 )
2667 protection
= PROT_READ
;
2671 // initially map __IMPORT segments R/W so dyld can update them
2672 if ( segIsReadOnlyImport(i
) )
2673 protection
|= PROT_WRITE
;
2675 // wholly zero-fill segments have nothing to mmap() in
2677 if ( (fileOffset
+size
) > fileLen
) {
2678 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
2679 segName(i
), (uint64_t)(fileOffset
+size
), fileLen
);
2681 void* loadAddress
= xmmap((void*)requestedLoadAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, fileOffset
);
2682 if ( loadAddress
== ((void*)(-1)) ) {
2683 int mmapErr
= errno
;
2684 if ( mmapErr
== EPERM
) {
2685 if ( dyld::sandboxBlockedMmap(getPath()) )
2686 dyld::throwf("file system sandbox blocked mmap() of '%s'", this->getPath());
2688 dyld::throwf("code signing blocked mmap() of '%s'", this->getPath());
2691 dyld::throwf("mmap() errno=%d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
2692 mmapErr
, requestedLoadAddress
, (uintptr_t)size
, segName(i
), getPath());
2696 ++ImageLoader::fgTotalSegmentsMapped
;
2697 ImageLoader::fgTotalBytesMapped
+= size
;
2698 if ( context
.verboseMapping
)
2699 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i
), requestedLoadAddress
, requestedLoadAddress
+size
-1,
2700 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2703 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2704 if (dyld::isTranslated() && extra_allocation_size
!= 0) {
2705 const struct mach_header
* aot_load_address
;
2706 dyld_aot_image_info aot_image_info
= {};
2707 int ret
= syscall(0x7000002, this->getPath(), mappedMachHeaderAddress
, endAddress
, &aot_load_address
, &aot_image_info
.aotImageSize
, aot_image_info
.aotImageKey
);
2709 extern void addAotImagesToAllAotImages(uint32_t aotInfoCount
, const dyld_aot_image_info aotInfo
[]);
2711 // fill in the aot load address, at this point the cambria trap has filled in
2712 // the image size and image key fields
2713 aot_image_info
.aotLoadAddress
= aot_load_address
;
2714 aot_image_info
.x86LoadAddress
= (struct mach_header
*)baseAddress
;
2716 addAotImagesToAllAotImages(1, &aot_image_info
);
2721 // update slide to reflect load location
2722 this->setSlide(slide
);
2725 void ImageLoaderMachO::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
)
2727 // find address range for image
2728 intptr_t slide
= this->assignSegmentAddresses(context
, 0);
2729 if ( context
.verboseMapping
)
2730 dyld::log("dyld: Mapping memory %p\n", memoryImage
);
2731 // map in all segments
2732 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2733 vm_address_t loadAddress
= segPreferredLoadAddress(i
) + slide
;
2734 vm_address_t srcAddr
= (uintptr_t)memoryImage
+ segFileOffset(i
);
2735 vm_size_t size
= segFileSize(i
);
2736 kern_return_t r
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
);
2737 if ( r
!= KERN_SUCCESS
)
2738 throw "can't map segment";
2739 if ( context
.verboseMapping
)
2740 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i
), (uintptr_t)loadAddress
, (uintptr_t)loadAddress
+size
-1);
2742 // update slide to reflect load location
2743 this->setSlide(slide
);
2744 // set R/W permissions on all segments at slide location
2745 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2746 segProtect(i
, context
);
2750 static vm_prot_t
protectionForSegIndex(const ImageLoaderMachO
* image
, unsigned int segIndex
)
2752 if ( image
->segUnaccessible(segIndex
) )
2754 vm_prot_t protection
= 0;
2755 if ( image
->segExecutable(segIndex
) )
2756 protection
|= PROT_EXEC
;
2757 if ( image
->segReadable(segIndex
) )
2758 protection
|= PROT_READ
;
2759 if ( image
->segWriteable(segIndex
) )
2760 protection
|= PROT_WRITE
;
2765 void ImageLoaderMachO::segProtect(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
2767 vm_prot_t protection
= protectionForSegIndex(this, segIndex
);
2768 vm_address_t addr
= segActualLoadAddress(segIndex
);
2769 vm_size_t size
= segSize(segIndex
);
2771 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
2772 if ( dyld::isTranslated() ) {
2773 // <rdar://problem/60543794> can't vm_protect non-16KB segments
2774 if ( (segIndex
> 0) && ((addr
& 0x3FFF) != 0) ) {
2775 // overlaps previous segment
2776 vm_prot_t prevProt
= protectionForSegIndex(this, segIndex
-1);
2777 if ( (protection
& prevProt
) != prevProt
) {
2778 // previous had more bits, so we need to not apply new permissions to the overlap
2779 vm_size_t overlap
= 0x4000 - (addr
& 0x3FFF);
2781 if ( size
>= overlap
)
2783 else if ( size
< overlap
)
2792 const bool setCurrentPermissions
= false;
2793 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
2794 if ( r
!= KERN_SUCCESS
) {
2795 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2796 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
2798 if ( context
.verboseMapping
) {
2799 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,
2800 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2804 #if TEXT_RELOC_SUPPORT
2805 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
2807 vm_address_t addr
= segActualLoadAddress(segIndex
);
2808 vm_size_t size
= segSize(segIndex
);
2809 const bool setCurrentPermissions
= false;
2810 vm_prot_t protection
= VM_PROT_WRITE
| VM_PROT_READ
| VM_PROT_COPY
;
2811 if ( segExecutable(segIndex
) && !segHasRebaseFixUps(segIndex
) )
2812 protection
|= VM_PROT_EXECUTE
;
2813 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
2814 if ( r
!= KERN_SUCCESS
) {
2815 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2816 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
2818 if ( context
.verboseMapping
) {
2819 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,
2820 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2825 const char* ImageLoaderMachO::findClosestSymbol(const mach_header
* mh
, const void* addr
, const void** closestAddr
)
2827 // called by dladdr()
2828 // only works with compressed LINKEDIT if classic symbol table is also present
2829 const dysymtab_command
* dynSymbolTable
= NULL
;
2830 const symtab_command
* symtab
= NULL
;
2831 const macho_segment_command
* seg
;
2832 const uint8_t* unslidLinkEditBase
= NULL
;
2833 bool linkEditBaseFound
= false;
2835 const uint32_t cmd_count
= mh
->ncmds
;
2836 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
2837 const load_command
* cmd
= cmds
;
2838 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2840 case LC_SEGMENT_COMMAND
:
2841 seg
= (macho_segment_command
*)cmd
;
2842 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 ) {
2843 unslidLinkEditBase
= (uint8_t*)(seg
->vmaddr
- seg
->fileoff
);
2844 linkEditBaseFound
= true;
2846 else if ( strcmp(seg
->segname
, "__TEXT") == 0 ) {
2847 slide
= (uintptr_t)mh
- seg
->vmaddr
;
2851 symtab
= (symtab_command
*)cmd
;
2854 dynSymbolTable
= (dysymtab_command
*)cmd
;
2857 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2859 // no symbol table => no lookup by address
2860 if ( (symtab
== NULL
) || (dynSymbolTable
== NULL
) || !linkEditBaseFound
)
2863 const uint8_t* linkEditBase
= unslidLinkEditBase
+ slide
;
2864 const char* symbolTableStrings
= (const char*)&linkEditBase
[symtab
->stroff
];
2865 const macho_nlist
* symbolTable
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]);
2867 uintptr_t targetAddress
= (uintptr_t)addr
- slide
;
2868 const struct macho_nlist
* bestSymbol
= NULL
;
2869 // first walk all global symbols
2870 const struct macho_nlist
* const globalsStart
= &symbolTable
[dynSymbolTable
->iextdefsym
];
2871 const struct macho_nlist
* const globalsEnd
= &globalsStart
[dynSymbolTable
->nextdefsym
];
2872 for (const struct macho_nlist
* s
= globalsStart
; s
< globalsEnd
; ++s
) {
2873 if ( (s
->n_type
& N_TYPE
) == N_SECT
) {
2874 if ( bestSymbol
== NULL
) {
2875 if ( s
->n_value
<= targetAddress
)
2878 else if ( (s
->n_value
<= targetAddress
) && (bestSymbol
->n_value
< s
->n_value
) ) {
2883 // next walk all local symbols
2884 const struct macho_nlist
* const localsStart
= &symbolTable
[dynSymbolTable
->ilocalsym
];
2885 const struct macho_nlist
* const localsEnd
= &localsStart
[dynSymbolTable
->nlocalsym
];
2886 for (const struct macho_nlist
* s
= localsStart
; s
< localsEnd
; ++s
) {
2887 if ( ((s
->n_type
& N_TYPE
) == N_SECT
) && ((s
->n_type
& N_STAB
) == 0) ) {
2888 if ( bestSymbol
== NULL
) {
2889 if ( s
->n_value
<= targetAddress
)
2892 else if ( (s
->n_value
<= targetAddress
) && (bestSymbol
->n_value
< s
->n_value
) ) {
2897 if ( bestSymbol
!= NULL
) {
2899 if (bestSymbol
->n_desc
& N_ARM_THUMB_DEF
)
2900 *closestAddr
= (void*)((bestSymbol
->n_value
| 1) + slide
);
2902 *closestAddr
= (void*)(bestSymbol
->n_value
+ slide
);
2904 *closestAddr
= (void*)(bestSymbol
->n_value
+ slide
);
2906 return &symbolTableStrings
[bestSymbol
->n_un
.n_strx
];
2911 bool ImageLoaderMachO::getLazyBindingInfo(uint32_t& lazyBindingInfoOffset
, const uint8_t* lazyInfoStart
, const uint8_t* lazyInfoEnd
,
2912 uint8_t* segIndex
, uintptr_t* segOffset
, int* ordinal
, const char** symbolName
, bool* doneAfterBind
)
2914 if ( lazyBindingInfoOffset
> (lazyInfoEnd
-lazyInfoStart
) )
2917 const uint8_t* p
= &lazyInfoStart
[lazyBindingInfoOffset
];
2918 while ( !done
&& (p
< lazyInfoEnd
) ) {
2919 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
2920 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
2923 case BIND_OPCODE_DONE
:
2924 *doneAfterBind
= false;
2927 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
2928 *ordinal
= immediate
;
2930 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
2931 *ordinal
= (int)read_uleb128(p
, lazyInfoEnd
);
2933 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
2934 // the special ordinals are negative numbers
2935 if ( immediate
== 0 )
2938 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
2939 *ordinal
= signExtended
;
2942 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
2943 *symbolName
= (char*)p
;
2948 case BIND_OPCODE_SET_TYPE_IMM
:
2950 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
2951 *segIndex
= immediate
;
2952 *segOffset
= read_uleb128(p
, lazyInfoEnd
);
2954 case BIND_OPCODE_DO_BIND
:
2955 *doneAfterBind
= ((*p
& BIND_OPCODE_MASK
) == BIND_OPCODE_DONE
);
2956 lazyBindingInfoOffset
+= p
- &lazyInfoStart
[lazyBindingInfoOffset
];
2959 case BIND_OPCODE_SET_ADDEND_SLEB
:
2960 case BIND_OPCODE_ADD_ADDR_ULEB
:
2961 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
2962 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
2963 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
2971 const dyld_info_command
* ImageLoaderMachO::findDyldInfoLoadCommand(const mach_header
* mh
)
2973 const uint32_t cmd_count
= mh
->ncmds
;
2974 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
2975 const load_command
* cmd
= cmds
;
2976 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2979 case LC_DYLD_INFO_ONLY
:
2980 return (dyld_info_command
*)cmd
;
2982 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2988 uintptr_t ImageLoaderMachO::segPreferredAddress(const mach_header
* mh
, unsigned segIndex
)
2990 const uint32_t cmd_count
= mh
->ncmds
;
2991 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
2992 const load_command
* cmd
= cmds
;
2993 unsigned curSegIndex
= 0;
2994 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2995 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2996 if ( segIndex
== curSegIndex
) {
2997 const macho_segment_command
* segCmd
= (macho_segment_command
*)cmd
;
2998 return segCmd
->vmaddr
;
3002 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
3009 uintptr_t ImageLoaderMachO::imageBaseAddress() const {
3010 //printf("imageBaseAddress: %s %d->%d\n", getPath(), 0, segmentCount());
3011 for (unsigned int i
= 0, e
= segmentCount(); i
!= e
; ++i
) {
3012 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) )
3013 return segPreferredLoadAddress(i
);