1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 // work around until conformance work is complete rdar://problem/4508801
30 #define __STDC_LIMIT_MACROS
34 #include <sys/types.h>
35 #include <sys/fcntl.h>
38 #include <mach/mach.h>
39 #include <mach/thread_status.h>
40 #include <mach-o/loader.h>
41 #include <mach-o/nlist.h>
42 #include <sys/sysctl.h>
43 #include <sys/syscall.h>
44 #include <libkern/OSAtomic.h>
45 #include <libkern/OSCacheControl.h>
47 #include <System/sys/codesign.h>
49 #include "ImageLoaderMachO.h"
50 #include "ImageLoaderMachOCompressed.h"
51 #if SUPPORT_CLASSIC_MACHO
52 #include "ImageLoaderMachOClassic.h"
54 #include "mach-o/dyld_images.h"
58 // <rdar://problem/8718137> use stack guard random value to add padding between dylibs
59 extern "C" long __stack_chk_guard
;
61 #ifndef LC_LOAD_UPWARD_DYLIB
62 #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
65 #ifndef LC_VERSION_MIN_TVOS
66 #define LC_VERSION_MIN_TVOS 0x2F
69 #ifndef LC_VERSION_MIN_WATCHOS
70 #define LC_VERSION_MIN_WATCHOS 0x30
73 #ifndef LC_BUILD_VERSION
74 #define LC_BUILD_VERSION 0x32 /* build for platform min OS version */
77 * The build_version_command contains the min OS version on which this
78 * binary was built to run for its platform. The list of known platforms and
79 * tool values following it.
81 struct build_version_command
{
82 uint32_t cmd
; /* LC_BUILD_VERSION */
83 uint32_t cmdsize
; /* sizeof(struct build_version_command) plus */
84 /* ntools * sizeof(struct build_tool_version) */
85 uint32_t platform
; /* platform */
86 uint32_t minos
; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
87 uint32_t sdk
; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
88 uint32_t ntools
; /* number of tool entries following this */
91 struct build_tool_version
{
92 uint32_t tool
; /* enum for the tool */
93 uint32_t version
; /* version number of the tool */
96 /* Known values for the platform field above. */
97 #define PLATFORM_MACOS 1
98 #define PLATFORM_IOS 2
99 #define PLATFORM_TVOS 3
100 #define PLATFORM_WATCHOS 4
101 #define PLATFORM_BRIDGEOS 5
103 /* Known values for the tool field above. */
111 #if TARGET_IPHONE_SIMULATOR
112 #define LIBSYSTEM_DYLIB_PATH "/usr/lib/libSystem.dylib"
114 #define LIBSYSTEM_DYLIB_PATH "/usr/lib/libSystem.B.dylib"
117 // relocation_info.r_length field has value 3 for 64-bit executables and value 2 for 32-bit executables
119 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
120 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
121 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
122 struct macho_segment_command
: public segment_command_64
{};
123 struct macho_section
: public section_64
{};
124 struct macho_routines_command
: public routines_command_64
{};
126 #define LC_SEGMENT_COMMAND LC_SEGMENT
127 #define LC_ROUTINES_COMMAND LC_ROUTINES
128 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
129 struct macho_segment_command
: public segment_command
{};
130 struct macho_section
: public section
{};
131 struct macho_routines_command
: public routines_command
{};
134 uint32_t ImageLoaderMachO::fgSymbolTableBinarySearchs
= 0;
137 ImageLoaderMachO::ImageLoaderMachO(const macho_header
* mh
, const char* path
, unsigned int segCount
,
138 uint32_t segOffsets
[], unsigned int libCount
)
139 : ImageLoader(path
, libCount
), fCoveredCodeLength(0), fMachOData((uint8_t*)mh
), fLinkEditBase(NULL
), fSlide(0),
140 fEHFrameSectionOffset(0), fUnwindInfoSectionOffset(0), fDylibIDOffset(0),
141 fSegmentsCount(segCount
), fIsSplitSeg(false), fInSharedCache(false),
142 #if TEXT_RELOC_SUPPORT
143 fTextSegmentRebases(false),
144 fTextSegmentBinds(false),
147 fReadOnlyImportSegment(false),
149 fHasSubLibraries(false), fHasSubUmbrella(false), fInUmbrella(false), fHasDOFSections(false), fHasDashInit(false),
150 fHasInitializers(false), fHasTerminators(false), fNotifyObjC(false), fRetainForObjC(false), fRegisteredAsRequiresCoalescing(false)
152 fIsSplitSeg
= ((mh
->flags
& MH_SPLIT_SEGS
) != 0);
154 // construct SegmentMachO object for each LC_SEGMENT cmd using "placement new" to put
155 // each SegmentMachO object in array at end of ImageLoaderMachO object
156 const uint32_t cmd_count
= mh
->ncmds
;
157 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
158 const struct load_command
* cmd
= cmds
;
159 for (uint32_t i
= 0, segIndex
=0; i
< cmd_count
; ++i
) {
160 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
161 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
162 // ignore zero-sized segments
163 if ( segCmd
->vmsize
!= 0 ) {
164 // record offset of load command
165 segOffsets
[segIndex
++] = (uint32_t)((uint8_t*)segCmd
- fMachOData
);
168 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
173 #if __MAC_OS_X_VERSION_MIN_REQUIRED
174 static uintptr_t pageAlign(uintptr_t value
)
176 return (value
+ 4095) & (-4096);
180 // determine if this mach-o file has classic or compressed LINKEDIT and number of segments it has
181 void ImageLoaderMachO::sniffLoadCommands(const macho_header
* mh
, const char* path
, bool inCache
, bool* compressed
,
182 unsigned int* segCount
, unsigned int* libCount
, const LinkContext
& context
,
183 const linkedit_data_command
** codeSigCmd
,
184 const encryption_info_command
** encryptCmd
)
192 const uint32_t cmd_count
= mh
->ncmds
;
193 const uint32_t sizeofcmds
= mh
->sizeofcmds
;
194 if ( sizeofcmds
> (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
-sizeof(macho_header
)) )
195 dyld::throwf("malformed mach-o: load commands size (%u) > %u", sizeofcmds
, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
);
196 if ( cmd_count
> (sizeofcmds
/sizeof(load_command
)) )
197 dyld::throwf("malformed mach-o: ncmds (%u) too large to fit in sizeofcmds (%u)", cmd_count
, sizeofcmds
);
198 const struct load_command
* const startCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
));
199 const struct load_command
* const endCmds
= (struct load_command
*)(((uint8_t*)mh
) + sizeof(macho_header
) + sizeofcmds
);
200 const struct load_command
* cmd
= startCmds
;
201 bool foundLoadCommandSegment
= false;
202 const macho_segment_command
* linkeditSegCmd
= NULL
;
203 const macho_segment_command
* startOfFileSegCmd
= NULL
;
204 const dyld_info_command
* dyldInfoCmd
= NULL
;
205 const symtab_command
* symTabCmd
= NULL
;
206 const dysymtab_command
* dynSymbTabCmd
= NULL
;
207 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
208 uint32_t cmdLength
= cmd
->cmdsize
;
209 const macho_segment_command
* segCmd
;
210 const dylib_command
* dylibCmd
;
211 if ( cmdLength
< 8 ) {
212 dyld::throwf("malformed mach-o image: load command #%d length (%u) too small in %s",
215 const struct load_command
* const nextCmd
= (const struct load_command
*)(((char*)cmd
)+cmdLength
);
216 if ( (nextCmd
> endCmds
) || (nextCmd
< cmd
) ) {
217 dyld::throwf("malformed mach-o image: load command #%d length (%u) would exceed sizeofcmds (%u) in %s",
218 i
, cmdLength
, mh
->sizeofcmds
, path
);
222 case LC_DYLD_INFO_ONLY
:
223 if ( cmd
->cmdsize
!= sizeof(dyld_info_command
) )
224 throw "malformed mach-o image: LC_DYLD_INFO size wrong";
225 dyldInfoCmd
= (struct dyld_info_command
*)cmd
;
228 case LC_SEGMENT_COMMAND
:
229 segCmd
= (struct macho_segment_command
*)cmd
;
230 #if __MAC_OS_X_VERSION_MIN_REQUIRED
231 // rdar://problem/19617624 allow unmapped segments on OSX (but not iOS)
232 if ( ((segCmd
->filesize
) > pageAlign(segCmd
->vmsize
)) && (segCmd
->vmsize
!= 0) )
234 // <rdar://problem/19986776> dyld should support non-allocatable __LLVM segment
235 if ( (segCmd
->filesize
> segCmd
->vmsize
) && ((segCmd
->vmsize
!= 0) || ((segCmd
->flags
& SG_NORELOC
) == 0)) )
237 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
);
238 if ( cmd
->cmdsize
< sizeof(macho_segment_command
) )
239 throw "malformed mach-o image: LC_SEGMENT size too small";
240 if ( cmd
->cmdsize
!= (sizeof(macho_segment_command
) + segCmd
->nsects
* sizeof(macho_section
)) )
241 throw "malformed mach-o image: LC_SEGMENT size wrong for number of sections";
242 // ignore zero-sized segments
243 if ( segCmd
->vmsize
!= 0 )
245 if ( strcmp(segCmd
->segname
, "__LINKEDIT") == 0 ) {
246 #if TARGET_IPHONE_SIMULATOR
247 // Note: should check on all platforms that __LINKEDIT is read-only, but <rdar://problem/22637626&22525618>
248 if ( segCmd
->initprot
!= VM_PROT_READ
)
249 throw "malformed mach-o image: __LINKEDIT segment does not have read-only permissions";
251 if ( segCmd
->fileoff
== 0 )
252 throw "malformed mach-o image: __LINKEDIT has fileoff==0 which overlaps mach_header";
253 if ( linkeditSegCmd
!= NULL
)
254 throw "malformed mach-o image: multiple __LINKEDIT segments";
255 linkeditSegCmd
= segCmd
;
258 if ( segCmd
->initprot
& 0xFFFFFFF8 )
259 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in initprot", segCmd
->segname
, segCmd
->initprot
);
260 if ( segCmd
->maxprot
& 0xFFFFFFF8 )
261 dyld::throwf("malformed mach-o image: %s segment has invalid permission bits (0x%X) in maxprot", segCmd
->segname
, segCmd
->maxprot
);
262 if ( (segCmd
->initprot
!= 0) && ((segCmd
->initprot
& VM_PROT_READ
) == 0) )
263 dyld::throwf("malformed mach-o image: %s segment is not mapped readable", segCmd
->segname
);
265 if ( (segCmd
->fileoff
== 0) && (segCmd
->filesize
!= 0) ) {
266 if ( (segCmd
->initprot
& VM_PROT_READ
) == 0 )
267 dyld::throwf("malformed mach-o image: %s segment maps start of file but is not readable", segCmd
->segname
);
268 if ( (segCmd
->initprot
& VM_PROT_WRITE
) == VM_PROT_WRITE
) {
269 if ( context
.strictMachORequired
)
270 dyld::throwf("malformed mach-o image: %s segment maps start of file but is writable", segCmd
->segname
);
272 if ( segCmd
->filesize
< (sizeof(macho_header
) + mh
->sizeofcmds
) )
273 dyld::throwf("malformed mach-o image: %s segment does not map all of load commands", segCmd
->segname
);
274 if ( startOfFileSegCmd
!= NULL
)
275 dyld::throwf("malformed mach-o image: multiple segments map start of file: %s %s", startOfFileSegCmd
->segname
, segCmd
->segname
);
276 startOfFileSegCmd
= segCmd
;
278 if ( context
.strictMachORequired
) {
279 uintptr_t vmStart
= segCmd
->vmaddr
;
280 uintptr_t vmSize
= segCmd
->vmsize
;
281 uintptr_t vmEnd
= vmStart
+ vmSize
;
282 uintptr_t fileStart
= segCmd
->fileoff
;
283 uintptr_t fileSize
= segCmd
->filesize
;
284 if ( (intptr_t)(vmSize
) < 0 )
285 dyld::throwf("malformed mach-o image: segment load command %s vmsize too large in %s", segCmd
->segname
, path
);
286 if ( vmStart
> vmEnd
)
287 dyld::throwf("malformed mach-o image: segment load command %s wraps around address space", segCmd
->segname
);
288 if ( vmSize
!= fileSize
) {
289 if ( segCmd
->initprot
== 0 ) {
290 // allow: fileSize == 0 && initprot == 0 e.g. __PAGEZERO
291 // allow: vmSize == 0 && initprot == 0 e.g. __LLVM
292 if ( (fileSize
!= 0) && (vmSize
!= 0) )
293 dyld::throwf("malformed mach-o image: unaccessable segment %s has non-zero filesize and vmsize", segCmd
->segname
);
296 // allow: vmSize > fileSize && initprot != X e.g. __DATA
297 if ( vmSize
< fileSize
) {
298 dyld::throwf("malformed mach-o image: segment %s has vmsize < filesize", segCmd
->segname
);
300 if ( segCmd
->initprot
& VM_PROT_EXECUTE
) {
301 dyld::throwf("malformed mach-o image: segment %s has vmsize != filesize and is executable", segCmd
->segname
);
306 if ( (fileSize
!= 0) && (segCmd
->initprot
== (VM_PROT_READ
| VM_PROT_EXECUTE
)) ) {
307 if ( foundLoadCommandSegment
)
308 throw "load commands in multiple segments";
309 foundLoadCommandSegment
= true;
312 else if ( (fileStart
< mh
->sizeofcmds
) && (fileSize
!= 0) ) {
313 // <rdar://problem/7942521> all load commands must be in an executable segment
314 if ( (fileStart
!= 0) || (fileSize
< (mh
->sizeofcmds
+sizeof(macho_header
))) )
315 dyld::throwf("malformed mach-o image: segment %s does not span all load commands", segCmd
->segname
);
316 if ( segCmd
->initprot
!= (VM_PROT_READ
| VM_PROT_EXECUTE
) )
317 dyld::throwf("malformed mach-o image: load commands found in segment %s with wrong permissions", segCmd
->segname
);
318 if ( foundLoadCommandSegment
)
319 throw "load commands in multiple segments";
320 foundLoadCommandSegment
= true;
323 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
324 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
325 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
326 if (!inCache
&& sect
->offset
!= 0 && ((sect
->offset
+ sect
->size
) > (segCmd
->fileoff
+ segCmd
->filesize
)))
327 dyld::throwf("malformed mach-o image: section %s,%s of '%s' exceeds segment %s booundary", sect
->segname
, sect
->sectname
, path
, segCmd
->segname
);
331 case LC_SEGMENT_COMMAND_WRONG
:
332 dyld::throwf("malformed mach-o image: wrong LC_SEGMENT[_64] for architecture");
335 case LC_LOAD_WEAK_DYLIB
:
336 case LC_REEXPORT_DYLIB
:
337 case LC_LOAD_UPWARD_DYLIB
:
341 dylibCmd
= (dylib_command
*)cmd
;
342 if ( dylibCmd
->dylib
.name
.offset
> cmdLength
)
343 dyld::throwf("malformed mach-o image: dylib load command #%d has offset (%u) outside its size (%u)", i
, dylibCmd
->dylib
.name
.offset
, cmdLength
);
344 if ( (dylibCmd
->dylib
.name
.offset
+ strlen((char*)dylibCmd
+ dylibCmd
->dylib
.name
.offset
) + 1) > cmdLength
)
345 dyld::throwf("malformed mach-o image: dylib load command #%d string extends beyond end of load command", i
);
347 case LC_CODE_SIGNATURE
:
348 if ( cmd
->cmdsize
!= sizeof(linkedit_data_command
) )
349 throw "malformed mach-o image: LC_CODE_SIGNATURE size wrong";
350 // <rdar://problem/22799652> only support one LC_CODE_SIGNATURE per image
351 if ( *codeSigCmd
!= NULL
)
352 throw "malformed mach-o image: multiple LC_CODE_SIGNATURE load commands";
353 *codeSigCmd
= (struct linkedit_data_command
*)cmd
;
355 case LC_ENCRYPTION_INFO
:
356 if ( cmd
->cmdsize
!= sizeof(encryption_info_command
) )
357 throw "malformed mach-o image: LC_ENCRYPTION_INFO size wrong";
358 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO per image
359 if ( *encryptCmd
!= NULL
)
360 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO load commands";
361 *encryptCmd
= (encryption_info_command
*)cmd
;
363 case LC_ENCRYPTION_INFO_64
:
364 if ( cmd
->cmdsize
!= sizeof(encryption_info_command_64
) )
365 throw "malformed mach-o image: LC_ENCRYPTION_INFO_64 size wrong";
366 // <rdar://problem/22799652> only support one LC_ENCRYPTION_INFO_64 per image
367 if ( *encryptCmd
!= NULL
)
368 throw "malformed mach-o image: multiple LC_ENCRYPTION_INFO_64 load commands";
369 *encryptCmd
= (encryption_info_command
*)cmd
;
372 if ( cmd
->cmdsize
!= sizeof(symtab_command
) )
373 throw "malformed mach-o image: LC_SYMTAB size wrong";
374 symTabCmd
= (symtab_command
*)cmd
;
377 if ( cmd
->cmdsize
!= sizeof(dysymtab_command
) )
378 throw "malformed mach-o image: LC_DYSYMTAB size wrong";
379 dynSymbTabCmd
= (dysymtab_command
*)cmd
;
381 #if __MAC_OS_X_VERSION_MIN_REQUIRED
382 // <rdar://problem/26797345> error when loading iOS Simulator mach-o binary into macOS process
383 case LC_VERSION_MIN_WATCHOS
:
384 case LC_VERSION_MIN_TVOS
:
385 case LC_VERSION_MIN_IPHONEOS
:
386 throw "mach-o, but built for simulator (not macOS)";
393 if ( context
.strictMachORequired
&& !foundLoadCommandSegment
)
394 throw "load commands not in a segment";
395 if ( linkeditSegCmd
== NULL
)
396 throw "malformed mach-o image: missing __LINKEDIT segment";
397 if ( !inCache
&& (startOfFileSegCmd
== NULL
) )
398 throw "malformed mach-o image: missing __TEXT segment that maps start of file";
399 // <rdar://problem/13145644> verify every segment does not overlap another segment
400 if ( context
.strictMachORequired
) {
401 uintptr_t lastFileStart
= 0;
402 uintptr_t linkeditFileStart
= 0;
403 const struct load_command
* cmd1
= startCmds
;
404 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
405 if ( cmd1
->cmd
== LC_SEGMENT_COMMAND
) {
406 struct macho_segment_command
* segCmd1
= (struct macho_segment_command
*)cmd1
;
407 uintptr_t vmStart1
= segCmd1
->vmaddr
;
408 uintptr_t vmEnd1
= segCmd1
->vmaddr
+ segCmd1
->vmsize
;
409 uintptr_t fileStart1
= segCmd1
->fileoff
;
410 uintptr_t fileEnd1
= segCmd1
->fileoff
+ segCmd1
->filesize
;
412 if (fileStart1
> lastFileStart
)
413 lastFileStart
= fileStart1
;
415 if ( strcmp(&segCmd1
->segname
[0], "__LINKEDIT") == 0 ) {
416 linkeditFileStart
= fileStart1
;
419 const struct load_command
* cmd2
= startCmds
;
420 for (uint32_t j
= 0; j
< cmd_count
; ++j
) {
423 if ( cmd2
->cmd
== LC_SEGMENT_COMMAND
) {
424 struct macho_segment_command
* segCmd2
= (struct macho_segment_command
*)cmd2
;
425 uintptr_t vmStart2
= segCmd2
->vmaddr
;
426 uintptr_t vmEnd2
= segCmd2
->vmaddr
+ segCmd2
->vmsize
;
427 uintptr_t fileStart2
= segCmd2
->fileoff
;
428 uintptr_t fileEnd2
= segCmd2
->fileoff
+ segCmd2
->filesize
;
429 if ( ((vmStart2
<= vmStart1
) && (vmEnd2
> vmStart1
) && (vmEnd1
> vmStart1
))
430 || ((vmStart2
>= vmStart1
) && (vmStart2
< vmEnd1
) && (vmEnd2
> vmStart2
)) )
431 dyld::throwf("malformed mach-o image: segment %s vm overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);
432 if ( ((fileStart2
<= fileStart1
) && (fileEnd2
> fileStart1
) && (fileEnd1
> fileStart1
))
433 || ((fileStart2
>= fileStart1
) && (fileStart2
< fileEnd1
) && (fileEnd2
> fileStart2
)) )
434 dyld::throwf("malformed mach-o image: segment %s file content overlaps segment %s", segCmd1
->segname
, segCmd2
->segname
);
436 cmd2
= (const struct load_command
*)(((char*)cmd2
)+cmd2
->cmdsize
);
439 cmd1
= (const struct load_command
*)(((char*)cmd1
)+cmd1
->cmdsize
);
442 if (lastFileStart
!= linkeditFileStart
)
443 dyld::throwf("malformed mach-o image: __LINKEDIT must be last segment");
446 // validate linkedit content
447 if ( (dyldInfoCmd
== NULL
) && (symTabCmd
== NULL
) )
448 throw "malformed mach-o image: missing LC_SYMTAB or LC_DYLD_INFO";
449 if ( dynSymbTabCmd
== NULL
)
450 throw "malformed mach-o image: missing LC_DYSYMTAB";
452 uint32_t linkeditFileOffsetStart
= (uint32_t)linkeditSegCmd
->fileoff
;
453 uint32_t linkeditFileOffsetEnd
= (uint32_t)linkeditSegCmd
->fileoff
+ (uint32_t)linkeditSegCmd
->filesize
;
455 if ( !inCache
&& (dyldInfoCmd
!= NULL
) && context
.strictMachORequired
) {
456 // validate all LC_DYLD_INFO chunks fit in LINKEDIT and don't overlap
457 uint32_t offset
= linkeditFileOffsetStart
;
458 if ( dyldInfoCmd
->rebase_size
!= 0 ) {
459 if ( dyldInfoCmd
->rebase_size
& 0x80000000 )
460 throw "malformed mach-o image: dyld rebase info size overflow";
461 if ( dyldInfoCmd
->rebase_off
< offset
)
462 throw "malformed mach-o image: dyld rebase info underruns __LINKEDIT";
463 offset
= dyldInfoCmd
->rebase_off
+ dyldInfoCmd
->rebase_size
;
464 if ( offset
> linkeditFileOffsetEnd
)
465 throw "malformed mach-o image: dyld rebase info overruns __LINKEDIT";
467 if ( dyldInfoCmd
->bind_size
!= 0 ) {
468 if ( dyldInfoCmd
->bind_size
& 0x80000000 )
469 throw "malformed mach-o image: dyld bind info size overflow";
470 if ( dyldInfoCmd
->bind_off
< offset
)
471 throw "malformed mach-o image: dyld bind info overlaps rebase info";
472 offset
= dyldInfoCmd
->bind_off
+ dyldInfoCmd
->bind_size
;
473 if ( offset
> linkeditFileOffsetEnd
)
474 throw "malformed mach-o image: dyld bind info overruns __LINKEDIT";
476 if ( dyldInfoCmd
->weak_bind_size
!= 0 ) {
477 if ( dyldInfoCmd
->weak_bind_size
& 0x80000000 )
478 throw "malformed mach-o image: dyld weak bind info size overflow";
479 if ( dyldInfoCmd
->weak_bind_off
< offset
)
480 throw "malformed mach-o image: dyld weak bind info overlaps bind info";
481 offset
= dyldInfoCmd
->weak_bind_off
+ dyldInfoCmd
->weak_bind_size
;
482 if ( offset
> linkeditFileOffsetEnd
)
483 throw "malformed mach-o image: dyld weak bind info overruns __LINKEDIT";
485 if ( dyldInfoCmd
->lazy_bind_size
!= 0 ) {
486 if ( dyldInfoCmd
->lazy_bind_size
& 0x80000000 )
487 throw "malformed mach-o image: dyld lazy bind info size overflow";
488 if ( dyldInfoCmd
->lazy_bind_off
< offset
)
489 throw "malformed mach-o image: dyld lazy bind info overlaps weak bind info";
490 offset
= dyldInfoCmd
->lazy_bind_off
+ dyldInfoCmd
->lazy_bind_size
;
491 if ( offset
> linkeditFileOffsetEnd
)
492 throw "malformed mach-o image: dyld lazy bind info overruns __LINKEDIT";
494 if ( dyldInfoCmd
->export_size
!= 0 ) {
495 if ( dyldInfoCmd
->export_size
& 0x80000000 )
496 throw "malformed mach-o image: dyld export info size overflow";
497 if ( dyldInfoCmd
->export_off
< offset
)
498 throw "malformed mach-o image: dyld export info overlaps lazy bind info";
499 offset
= dyldInfoCmd
->export_off
+ dyldInfoCmd
->export_size
;
500 if ( offset
> linkeditFileOffsetEnd
)
501 throw "malformed mach-o image: dyld export info overruns __LINKEDIT";
505 if ( symTabCmd
!= NULL
) {
506 // validate symbol table fits in LINKEDIT
507 if ( symTabCmd
->symoff
< linkeditFileOffsetStart
)
508 throw "malformed mach-o image: symbol table underruns __LINKEDIT";
509 if ( symTabCmd
->nsyms
> 0x10000000 )
510 throw "malformed mach-o image: symbol table too large";
511 uint32_t symbolsSize
= symTabCmd
->nsyms
* sizeof(macho_nlist
);
512 if ( symbolsSize
> linkeditSegCmd
->filesize
)
513 throw "malformed mach-o image: symbol table overruns __LINKEDIT";
514 if ( symTabCmd
->symoff
+ symbolsSize
< symTabCmd
->symoff
)
515 throw "malformed mach-o image: symbol table size wraps";
516 if ( symTabCmd
->symoff
+ symbolsSize
> symTabCmd
->stroff
)
517 throw "malformed mach-o image: symbol table overlaps symbol strings";
518 if ( symTabCmd
->stroff
+ symTabCmd
->strsize
< symTabCmd
->stroff
)
519 throw "malformed mach-o image: symbol string size wraps";
520 if ( symTabCmd
->stroff
+ symTabCmd
->strsize
> linkeditFileOffsetEnd
) {
521 // <rdar://problem/24220313> let old apps overflow as long as it stays within mapped page
522 if ( context
.strictMachORequired
|| (symTabCmd
->stroff
+ symTabCmd
->strsize
> ((linkeditFileOffsetEnd
+ 4095) & (-4096))) )
523 throw "malformed mach-o image: symbol strings overrun __LINKEDIT";
525 // validate indirect symbol table
526 if ( dynSymbTabCmd
->nindirectsyms
!= 0 ) {
527 if ( dynSymbTabCmd
->indirectsymoff
< linkeditFileOffsetStart
)
528 throw "malformed mach-o image: indirect symbol table underruns __LINKEDIT";
529 if ( dynSymbTabCmd
->nindirectsyms
> 0x10000000 )
530 throw "malformed mach-o image: indirect symbol table too large";
531 uint32_t indirectTableSize
= dynSymbTabCmd
->nindirectsyms
* sizeof(uint32_t);
532 if ( indirectTableSize
> linkeditSegCmd
->filesize
)
533 throw "malformed mach-o image: indirect symbol table overruns __LINKEDIT";
534 if ( dynSymbTabCmd
->indirectsymoff
+ indirectTableSize
< dynSymbTabCmd
->indirectsymoff
)
535 throw "malformed mach-o image: indirect symbol table size wraps";
536 if ( context
.strictMachORequired
&& (dynSymbTabCmd
->indirectsymoff
+ indirectTableSize
> symTabCmd
->stroff
) )
537 throw "malformed mach-o image: indirect symbol table overruns string pool";
539 if ( (dynSymbTabCmd
->nlocalsym
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->ilocalsym
> symTabCmd
->nsyms
) )
540 throw "malformed mach-o image: indirect symbol table local symbol count exceeds total symbols";
541 if ( dynSymbTabCmd
->ilocalsym
+ dynSymbTabCmd
->nlocalsym
< dynSymbTabCmd
->ilocalsym
)
542 throw "malformed mach-o image: indirect symbol table local symbol count wraps";
543 if ( (dynSymbTabCmd
->nextdefsym
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->iextdefsym
> symTabCmd
->nsyms
) )
544 throw "malformed mach-o image: indirect symbol table extern symbol count exceeds total symbols";
545 if ( dynSymbTabCmd
->iextdefsym
+ dynSymbTabCmd
->nextdefsym
< dynSymbTabCmd
->iextdefsym
)
546 throw "malformed mach-o image: indirect symbol table extern symbol count wraps";
547 if ( (dynSymbTabCmd
->nundefsym
> symTabCmd
->nsyms
) || (dynSymbTabCmd
->iundefsym
> symTabCmd
->nsyms
) )
548 throw "malformed mach-o image: indirect symbol table undefined symbol count exceeds total symbols";
549 if ( dynSymbTabCmd
->iundefsym
+ dynSymbTabCmd
->nundefsym
< dynSymbTabCmd
->iundefsym
)
550 throw "malformed mach-o image: indirect symbol table undefined symbol count wraps";
554 // fSegmentsArrayCount is only 8-bits
555 if ( *segCount
> 255 )
556 dyld::throwf("malformed mach-o image: more than 255 segments in %s", path
);
558 // fSegmentsArrayCount is only 8-bits
559 if ( *libCount
> 4095 )
560 dyld::throwf("malformed mach-o image: more than 4095 dependent libraries in %s", path
);
562 if ( needsAddedLibSystemDepency(*libCount
, mh
) )
568 // create image for main executable
569 ImageLoader
* ImageLoaderMachO::instantiateMainExecutable(const macho_header
* mh
, uintptr_t slide
, const char* path
, const LinkContext
& context
)
571 //dyld::log("ImageLoader=%ld, ImageLoaderMachO=%ld, ImageLoaderMachOClassic=%ld, ImageLoaderMachOCompressed=%ld\n",
572 // sizeof(ImageLoader), sizeof(ImageLoaderMachO), sizeof(ImageLoaderMachOClassic), sizeof(ImageLoaderMachOCompressed));
574 unsigned int segCount
;
575 unsigned int libCount
;
576 const linkedit_data_command
* codeSigCmd
;
577 const encryption_info_command
* encryptCmd
;
578 sniffLoadCommands(mh
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
579 // instantiate concrete class based on content of load commands
581 return ImageLoaderMachOCompressed::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
583 #if SUPPORT_CLASSIC_MACHO
584 return ImageLoaderMachOClassic::instantiateMainExecutable(mh
, slide
, path
, segCount
, libCount
, context
);
586 throw "missing LC_DYLD_INFO load command";
591 // create image by mapping in a mach-o file
592 ImageLoader
* ImageLoaderMachO::instantiateFromFile(const char* path
, int fd
, const uint8_t firstPages
[], size_t firstPagesSize
, uint64_t offsetInFat
,
593 uint64_t lenInFat
, const struct stat
& info
, const LinkContext
& context
)
596 unsigned int segCount
;
597 unsigned int libCount
;
598 const linkedit_data_command
* codeSigCmd
;
599 const encryption_info_command
* encryptCmd
;
600 sniffLoadCommands((const macho_header
*)firstPages
, path
, false, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
601 // instantiate concrete class based on content of load commands
603 return ImageLoaderMachOCompressed::instantiateFromFile(path
, fd
, firstPages
, firstPagesSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, encryptCmd
, context
);
605 #if SUPPORT_CLASSIC_MACHO
606 return ImageLoaderMachOClassic::instantiateFromFile(path
, fd
, firstPages
, firstPagesSize
, offsetInFat
, lenInFat
, info
, segCount
, libCount
, codeSigCmd
, context
);
608 throw "missing LC_DYLD_INFO load command";
612 // create image by using cached mach-o file
613 ImageLoader
* ImageLoaderMachO::instantiateFromCache(const macho_header
* mh
, const char* path
, long slide
, const struct stat
& info
, const LinkContext
& context
)
615 // instantiate right concrete class
617 unsigned int segCount
;
618 unsigned int libCount
;
619 const linkedit_data_command
* codeSigCmd
;
620 const encryption_info_command
* encryptCmd
;
621 sniffLoadCommands(mh
, path
, true, &compressed
, &segCount
, &libCount
, context
, &codeSigCmd
, &encryptCmd
);
622 // instantiate concrete class based on content of load commands
624 return ImageLoaderMachOCompressed::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
626 #if SUPPORT_CLASSIC_MACHO
627 return ImageLoaderMachOClassic::instantiateFromCache(mh
, path
, slide
, info
, segCount
, libCount
, context
);
629 throw "missing LC_DYLD_INFO load command";
633 // create image by copying an in-memory mach-o file
634 ImageLoader
* ImageLoaderMachO::instantiateFromMemory(const char* moduleName
, const macho_header
* mh
, uint64_t len
, const LinkContext
& context
)
637 unsigned int segCount
;
638 unsigned int libCount
;
639 const linkedit_data_command
* sigcmd
;
640 const encryption_info_command
* encryptCmd
;
641 sniffLoadCommands(mh
, moduleName
, false, &compressed
, &segCount
, &libCount
, context
, &sigcmd
, &encryptCmd
);
642 // instantiate concrete class based on content of load commands
644 return ImageLoaderMachOCompressed::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
646 #if SUPPORT_CLASSIC_MACHO
647 return ImageLoaderMachOClassic::instantiateFromMemory(moduleName
, mh
, len
, segCount
, libCount
, context
);
649 throw "missing LC_DYLD_INFO load command";
654 int ImageLoaderMachO::crashIfInvalidCodeSignature()
656 // Now that segments are mapped in, try reading from first executable segment.
657 // If code signing is enabled the kernel will validate the code signature
658 // when paging in, and kill the process if invalid.
659 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
660 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
661 // return read value to ensure compiler does not optimize away load
662 int* p
= (int*)segActualLoadAddress(i
);
670 void ImageLoaderMachO::parseLoadCmds(const LinkContext
& context
)
672 // now that segments are mapped in, get real fMachOData, fLinkEditBase, and fSlide
673 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
674 // set up pointer to __LINKEDIT segment
675 if ( strcmp(segName(i
),"__LINKEDIT") == 0 ) {
676 if ( context
.requireCodeSignature
&& (segFileOffset(i
) > fCoveredCodeLength
))
677 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;
690 if ( segIsReadOnlyImport(i
) )
691 fReadOnlyImportSegment
= true;
693 // some segment always starts at beginning of file and contains mach_header and load commands
694 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
695 fMachOData
= (uint8_t*)(segActualLoadAddress(i
));
699 // keep count of prebound images with weak exports
700 if ( this->participatesInCoalescing() ) {
701 ++fgImagesRequiringCoalescing
;
702 fRegisteredAsRequiresCoalescing
= true;
703 if ( this->hasCoalescedExports() )
704 ++fgImagesHasWeakDefinitions
;
707 // keep count of images used in shared cache
708 if ( fInSharedCache
)
709 ++fgImagesUsedFromSharedCache
;
711 // walk load commands (mapped in at start of __TEXT segment)
712 const dyld_info_command
* dyldInfo
= NULL
;
713 const macho_nlist
* symbolTable
= NULL
;
714 const char* symbolTableStrings
= NULL
;
715 const struct load_command
* firstUnknownCmd
= NULL
;
716 const struct version_min_command
* minOSVersionCmd
= NULL
;
717 const dysymtab_command
* dynSymbolTable
= NULL
;
718 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
719 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
720 const struct load_command
* cmd
= cmds
;
721 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
725 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
726 symbolTableStrings
= (const char*)&fLinkEditBase
[symtab
->stroff
];
727 symbolTable
= (macho_nlist
*)(&fLinkEditBase
[symtab
->symoff
]);
731 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
733 case LC_SUB_UMBRELLA
:
734 fHasSubUmbrella
= true;
736 case LC_SUB_FRAMEWORK
:
740 fHasSubLibraries
= true;
742 case LC_ROUTINES_COMMAND
:
746 case LC_DYLD_INFO_ONLY
:
747 dyldInfo
= (struct dyld_info_command
*)cmd
;
749 case LC_SEGMENT_COMMAND
:
751 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
752 const bool isTextSeg
= (strcmp(seg
->segname
, "__TEXT") == 0);
753 #if __i386__ && __MAC_OS_X_VERSION_MIN_REQUIRED
754 const bool isObjCSeg
= (strcmp(seg
->segname
, "__OBJC") == 0);
758 const bool isDataSeg
= (strncmp(seg
->segname
, "__DATA", 6) == 0);
760 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
761 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
762 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
763 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
764 if ( type
== S_MOD_INIT_FUNC_POINTERS
)
765 fHasInitializers
= true;
766 else if ( type
== S_MOD_TERM_FUNC_POINTERS
)
767 fHasTerminators
= true;
768 else if ( type
== S_DTRACE_DOF
)
769 fHasDOFSections
= true;
770 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__eh_frame") == 0) )
771 fEHFrameSectionOffset
= (uint32_t)((uint8_t*)sect
- fMachOData
);
772 else if ( isTextSeg
&& (strcmp(sect
->sectname
, "__unwind_info") == 0) )
773 fUnwindInfoSectionOffset
= (uint32_t)((uint8_t*)sect
- fMachOData
);
775 #if __i386__ && __MAC_OS_X_VERSION_MIN_REQUIRED
776 else if ( isObjCSeg
) {
777 if ( strcmp(sect
->sectname
, "__image_info") == 0 ) {
778 const uint32_t* imageInfo
= (uint32_t*)(sect
->addr
+ fSlide
);
779 uint32_t flags
= imageInfo
[1];
780 if ( (flags
& 4) && (((macho_header
*)fMachOData
)->filetype
!= MH_EXECUTE
) )
781 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
783 else if ( ((macho_header
*)fMachOData
)->filetype
== MH_DYLIB
) {
784 fRetainForObjC
= true;
788 else if ( isDataSeg
&& (strncmp(sect
->sectname
, "__objc_imageinfo", 16) == 0) ) {
789 #if __MAC_OS_X_VERSION_MIN_REQUIRED
790 const uint32_t* imageInfo
= (uint32_t*)(sect
->addr
+ fSlide
);
791 uint32_t flags
= imageInfo
[1];
792 if ( (flags
& 4) && (((macho_header
*)fMachOData
)->filetype
!= MH_EXECUTE
) )
793 dyld::throwf("cannot load '%s' because Objective-C garbage collection is not supported", getPath());
797 else if ( isDataSeg
&& (strncmp(sect
->sectname
, "__objc_", 7) == 0) && (((macho_header
*)fMachOData
)->filetype
== MH_DYLIB
) )
798 fRetainForObjC
= true;
803 case LC_TWOLEVEL_HINTS
:
804 // no longer supported
808 fDylibIDOffset
= (uint32_t)((uint8_t*)cmd
- fMachOData
);
812 case LC_LOAD_WEAK_DYLIB
:
813 case LC_REEXPORT_DYLIB
:
814 case LC_LOAD_UPWARD_DYLIB
:
816 // do nothing, just prevent LC_REQ_DYLD exception from occuring
818 case LC_VERSION_MIN_MACOSX
:
819 case LC_VERSION_MIN_IPHONEOS
:
820 case LC_VERSION_MIN_TVOS
:
821 case LC_VERSION_MIN_WATCHOS
:
822 minOSVersionCmd
= (version_min_command
*)cmd
;
825 if ( (cmd
->cmd
& LC_REQ_DYLD
) != 0 ) {
826 if ( firstUnknownCmd
== NULL
)
827 firstUnknownCmd
= cmd
;
831 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
833 if ( firstUnknownCmd
!= NULL
) {
834 if ( minOSVersionCmd
!= NULL
) {
835 dyld::throwf("cannot load '%s' because it was built for OS version %u.%u (load command 0x%08X is unknown)",
836 this->getShortName(),
837 minOSVersionCmd
->version
>> 16, ((minOSVersionCmd
->version
>> 8) & 0xff),
838 firstUnknownCmd
->cmd
);
841 dyld::throwf("cannot load '%s' (load command 0x%08X is unknown)", this->getShortName(), firstUnknownCmd
->cmd
);
846 if ( dyldInfo
!= NULL
)
847 this->setDyldInfo(dyldInfo
);
848 if ( symbolTable
!= NULL
)
849 this->setSymbolTableInfo(symbolTable
, symbolTableStrings
, dynSymbolTable
);
853 // don't do this work in destructor because we need object to be full subclass
854 // for UnmapSegments() to work
855 void ImageLoaderMachO::destroy()
857 // update count of images with weak exports
858 if ( fRegisteredAsRequiresCoalescing
) {
859 --fgImagesRequiringCoalescing
;
860 if ( this->hasCoalescedExports() )
861 --fgImagesHasWeakDefinitions
;
864 // keep count of images used in shared cache
865 if ( fInSharedCache
)
866 --fgImagesUsedFromSharedCache
;
868 // unmap image when done
873 unsigned int ImageLoaderMachO::segmentCount() const
875 return fSegmentsCount
;
879 const macho_segment_command
* ImageLoaderMachO::segLoadCommand(unsigned int segIndex
) const
881 uint32_t* lcOffsets
= this->segmentCommandOffsets();
882 uint32_t lcOffset
= lcOffsets
[segIndex
];
883 return (macho_segment_command
*)(&fMachOData
[lcOffset
]);
886 const char* ImageLoaderMachO::segName(unsigned int segIndex
) const
888 return segLoadCommand(segIndex
)->segname
;
892 uintptr_t ImageLoaderMachO::segSize(unsigned int segIndex
) const
894 return segLoadCommand(segIndex
)->vmsize
;
898 uintptr_t ImageLoaderMachO::segFileSize(unsigned int segIndex
) const
900 return segLoadCommand(segIndex
)->filesize
;
904 bool ImageLoaderMachO::segHasTrailingZeroFill(unsigned int segIndex
)
906 return ( segWriteable(segIndex
) && (segSize(segIndex
) > segFileSize(segIndex
)) );
910 uintptr_t ImageLoaderMachO::segFileOffset(unsigned int segIndex
) const
912 return segLoadCommand(segIndex
)->fileoff
;
916 bool ImageLoaderMachO::segReadable(unsigned int segIndex
) const
918 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_READ
) != 0);
922 bool ImageLoaderMachO::segWriteable(unsigned int segIndex
) const
924 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_WRITE
) != 0);
928 bool ImageLoaderMachO::segExecutable(unsigned int segIndex
) const
930 return ( (segLoadCommand(segIndex
)->initprot
& VM_PROT_EXECUTE
) != 0);
934 bool ImageLoaderMachO::segUnaccessible(unsigned int segIndex
) const
936 return (segLoadCommand(segIndex
)->initprot
== 0);
939 bool ImageLoaderMachO::segHasPreferredLoadAddress(unsigned int segIndex
) const
941 return (segLoadCommand(segIndex
)->vmaddr
!= 0);
944 uintptr_t ImageLoaderMachO::segPreferredLoadAddress(unsigned int segIndex
) const
946 return segLoadCommand(segIndex
)->vmaddr
;
949 uintptr_t ImageLoaderMachO::segActualLoadAddress(unsigned int segIndex
) const
951 return segLoadCommand(segIndex
)->vmaddr
+ fSlide
;
955 uintptr_t ImageLoaderMachO::segActualEndAddress(unsigned int segIndex
) const
957 return segActualLoadAddress(segIndex
) + segSize(segIndex
);
960 bool ImageLoaderMachO::segHasRebaseFixUps(unsigned int segIndex
) const
962 #if TEXT_RELOC_SUPPORT
963 // scan sections for fix-up bit
964 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
965 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
966 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
967 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
968 if ( (sect
->flags
& S_ATTR_LOC_RELOC
) != 0 )
975 bool ImageLoaderMachO::segHasBindFixUps(unsigned int segIndex
) const
977 #if TEXT_RELOC_SUPPORT
978 // scan sections for fix-up bit
979 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
980 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)segCmd
+ sizeof(struct macho_segment_command
));
981 const struct macho_section
* const sectionsEnd
= §ionsStart
[segCmd
->nsects
];
982 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
983 if ( (sect
->flags
& S_ATTR_EXT_RELOC
) != 0 )
991 bool ImageLoaderMachO::segIsReadOnlyImport(unsigned int segIndex
) const
993 const macho_segment_command
* segCmd
= segLoadCommand(segIndex
);
994 return ( (segCmd
->initprot
& VM_PROT_EXECUTE
)
995 && ((segCmd
->initprot
& VM_PROT_WRITE
) == 0)
996 && (strcmp(segCmd
->segname
, "__IMPORT") == 0) );
1001 void ImageLoaderMachO::UnmapSegments()
1003 // usually unmap image when done
1004 if ( ! this->leaveMapped() && (this->getState() >= dyld_image_state_mapped
) ) {
1005 // unmap TEXT segment last because it contains load command being inspected
1006 unsigned int textSegmentIndex
= 0;
1007 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1008 //dyld::log("unmap %s at 0x%08lX\n", seg->getName(), seg->getActualLoadAddress(this));
1009 if ( (segFileOffset(i
) == 0) && (segFileSize(i
) != 0) ) {
1010 textSegmentIndex
= i
;
1014 --ImageLoader::fgTotalSegmentsMapped
;
1015 ImageLoader::fgTotalBytesMapped
-= segSize(i
);
1016 munmap((void*)segActualLoadAddress(i
), segSize(i
));
1020 --ImageLoader::fgTotalSegmentsMapped
;
1021 ImageLoader::fgTotalBytesMapped
-= segSize(textSegmentIndex
);
1022 munmap((void*)segActualLoadAddress(textSegmentIndex
), segSize(textSegmentIndex
));
1027 // prefetch __DATA/__OBJC pages during launch, but not for dynamically loaded code
1028 void ImageLoaderMachO::preFetchDATA(int fd
, uint64_t offsetInFat
, const LinkContext
& context
)
1030 if ( context
.linkingMainExecutable
) {
1031 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
1032 if ( segWriteable(i
) && (segFileSize(i
) > 0) ) {
1033 // prefetch writable segment that have mmap'ed regions
1035 advice
.ra_offset
= offsetInFat
+ segFileOffset(i
);
1036 advice
.ra_count
= (int)segFileSize(i
);
1037 // limit prefetch to 1MB (256 pages)
1038 if ( advice
.ra_count
> 1024*1024 )
1039 advice
.ra_count
= 1024*1024;
1040 // don't prefetch single pages, let them fault in
1041 fgTotalBytesPreFetched
+= advice
.ra_count
;
1042 fcntl(fd
, F_RDADVISE
, &advice
);
1043 if ( context
.verboseMapping
) {
1044 dyld::log("%18s prefetching 0x%0lX -> 0x%0lX\n",
1045 segName(i
), segActualLoadAddress(i
), segActualLoadAddress(i
)+advice
.ra_count
-1);
1053 bool ImageLoaderMachO::segmentsMustSlideTogether() const
1058 bool ImageLoaderMachO::segmentsCanSlide() const
1060 return (this->isDylib() || this->isBundle() || this->isPositionIndependentExecutable());
1063 bool ImageLoaderMachO::isBundle() const
1065 const macho_header
* mh
= (macho_header
*)fMachOData
;
1066 return ( mh
->filetype
== MH_BUNDLE
);
1069 bool ImageLoaderMachO::isDylib() const
1071 const macho_header
* mh
= (macho_header
*)fMachOData
;
1072 return ( mh
->filetype
== MH_DYLIB
);
1075 bool ImageLoaderMachO::isExecutable() const
1077 const macho_header
* mh
= (macho_header
*)fMachOData
;
1078 return ( mh
->filetype
== MH_EXECUTE
);
1081 bool ImageLoaderMachO::isPositionIndependentExecutable() const
1083 const macho_header
* mh
= (macho_header
*)fMachOData
;
1084 return ( (mh
->filetype
== MH_EXECUTE
) && ((mh
->flags
& MH_PIE
) != 0) );
1088 bool ImageLoaderMachO::forceFlat() const
1090 const macho_header
* mh
= (macho_header
*)fMachOData
;
1091 return ( (mh
->flags
& MH_FORCE_FLAT
) != 0 );
1094 bool ImageLoaderMachO::usesTwoLevelNameSpace() const
1096 const macho_header
* mh
= (macho_header
*)fMachOData
;
1097 return ( (mh
->flags
& MH_TWOLEVEL
) != 0 );
1100 bool ImageLoaderMachO::isPrebindable() const
1102 const macho_header
* mh
= (macho_header
*)fMachOData
;
1103 return ( (mh
->flags
& MH_PREBOUND
) != 0 );
1106 bool ImageLoaderMachO::hasCoalescedExports() const
1108 const macho_header
* mh
= (macho_header
*)fMachOData
;
1109 return ( (mh
->flags
& MH_WEAK_DEFINES
) != 0 );
1112 bool ImageLoaderMachO::hasReferencesToWeakSymbols() const
1114 const macho_header
* mh
= (macho_header
*)fMachOData
;
1115 return ( (mh
->flags
& MH_BINDS_TO_WEAK
) != 0 );
1118 bool ImageLoaderMachO::participatesInCoalescing() const
1120 const macho_header
* mh
= (macho_header
*)fMachOData
;
1121 // if image is loaded with RTLD_LOCAL, then its symbols' visibility
1122 // is reduced and it can't coalesce with other images
1123 if ( this->hasHiddenExports() )
1125 return ( (mh
->flags
& (MH_WEAK_DEFINES
|MH_BINDS_TO_WEAK
)) != 0 );
1130 void ImageLoaderMachO::setSlide(intptr_t slide
)
1135 void ImageLoaderMachO::loadCodeSignature(const struct linkedit_data_command
* codeSigCmd
, int fd
, uint64_t offsetInFatFile
, const LinkContext
& context
)
1137 // if dylib being loaded has no code signature load command
1138 if ( codeSigCmd
== NULL
) {
1139 if (context
.requireCodeSignature
) {
1140 // if we require dylibs to be codesigned there needs to be a signature.
1141 dyld::throwf("required code signature missing for '%s'\n", this->getPath());
1143 disableCoverageCheck();
1147 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1148 // <rdar://problem/13622786> ignore code signatures in binaries built with pre-10.9 tools
1149 if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9
) {
1153 fsignatures_t siginfo
;
1154 siginfo
.fs_file_start
=offsetInFatFile
; // start of mach-o slice in fat file
1155 siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
); // start of CD in mach-o file
1156 siginfo
.fs_blob_size
=codeSigCmd
->datasize
; // size of CD
1157 int result
= fcntl(fd
, F_ADDFILESIGS_RETURN
, &siginfo
);
1159 #if TARGET_IPHONE_SIMULATOR
1160 // rdar://problem/18759224> check range covered by the code directory after loading
1161 // Attempt to fallback only if we are in the simulator
1163 if ( result
== -1 ) {
1164 result
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
);
1165 siginfo
.fs_file_start
= codeSigCmd
->dataoff
;
1169 if ( result
== -1 ) {
1170 if ( (errno
== EPERM
) || (errno
== EBADEXEC
) )
1171 dyld::throwf("code signature invalid for '%s'\n", this->getPath());
1172 if ( context
.verboseCodeSignatures
)
1173 dyld::log("dyld: Failed registering code signature for %s, errno=%d\n", this->getPath(), errno
);
1174 siginfo
.fs_file_start
= UINT64_MAX
;
1175 } else if ( context
.verboseCodeSignatures
) {
1176 dyld::log("dyld: Registered code signature for %s\n", this->getPath());
1178 fCoveredCodeLength
= siginfo
.fs_file_start
;
1180 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1181 if ( context
.processUsingLibraryValidation
) {
1183 char messageBuffer
[512];
1184 messageBuffer
[0] = '\0';
1185 checkInfo
.lv_file_start
= offsetInFatFile
;
1186 checkInfo
.lv_error_message_size
= sizeof(messageBuffer
);
1187 checkInfo
.lv_error_message
= messageBuffer
;
1188 int res
= fcntl(fd
, F_CHECK_LV
, &checkInfo
);
1190 dyld::throwf("code signature in (%s) not valid for use in process using Library Validation: %s", this->getPath(), messageBuffer
);
1197 void ImageLoaderMachO::validateFirstPages(const struct linkedit_data_command
* codeSigCmd
, int fd
, const uint8_t *fileData
, size_t lenFileData
, off_t offsetInFat
, const LinkContext
& context
)
1199 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1200 // rdar://problem/21839703> 15A226d: dyld crashes in mageLoaderMachO::validateFirstPages during dlopen() after encountering an mmap failure
1201 // We need to ignore older code signatures because they will be bad.
1202 if ( this->sdkVersion() < DYLD_MACOSX_VERSION_10_9
) {
1206 if (codeSigCmd
!= NULL
) {
1207 void *fdata
= xmmap(NULL
, lenFileData
, PROT_READ
| PROT_EXEC
, MAP_SHARED
, fd
, offsetInFat
);
1208 if ( fdata
== MAP_FAILED
) {
1209 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1210 if ( context
.processUsingLibraryValidation
) {
1211 dyld::throwf("cannot load image with wrong team ID in process using Library Validation");
1216 int errnoCopy
= errno
;
1217 if ( errnoCopy
== EPERM
) {
1218 if ( dyld::sandboxBlockedMmap(getPath()) )
1219 dyld::throwf("file system sandbox blocked mmap() of '%s'", getPath());
1221 dyld::throwf("code signing blocked mmap() of '%s'", getPath());
1224 dyld::throwf("mmap() errno=%d validating first page of '%s'", errnoCopy
, getPath());
1227 if ( memcmp(fdata
, fileData
, lenFileData
) != 0 )
1228 dyld::throwf("mmap() page compare failed for '%s'", getPath());
1229 munmap(fdata
, lenFileData
);
1234 const char* ImageLoaderMachO::getInstallPath() const
1236 if ( fDylibIDOffset
!= 0 ) {
1237 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
1238 return (char*)dylibID
+ dylibID
->dylib
.name
.offset
;
1243 void ImageLoaderMachO::registerInterposing()
1245 // mach-o files advertise interposing by having a __DATA __interpose section
1246 struct InterposeData
{ uintptr_t replacement
; uintptr_t replacee
; };
1247 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1248 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1249 const struct load_command
* cmd
= cmds
;
1250 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1252 case LC_SEGMENT_COMMAND
:
1254 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1255 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1256 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1257 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1258 if ( ((sect
->flags
& SECTION_TYPE
) == S_INTERPOSING
) || ((strcmp(sect
->sectname
, "__interpose") == 0) && (strcmp(seg
->segname
, "__DATA") == 0)) ) {
1259 // <rdar://problem/23929217> Ensure section is within segment
1260 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
1261 dyld::throwf("interpose section has malformed address range for %s\n", this->getPath());
1262 const InterposeData
* interposeArray
= (InterposeData
*)(sect
->addr
+ fSlide
);
1263 const size_t count
= sect
->size
/ sizeof(InterposeData
);
1264 for (size_t j
=0; j
< count
; ++j
) {
1265 ImageLoader::InterposeTuple tuple
;
1266 tuple
.replacement
= interposeArray
[j
].replacement
;
1267 tuple
.neverImage
= this;
1268 tuple
.onlyImage
= NULL
;
1269 tuple
.replacee
= interposeArray
[j
].replacee
;
1270 // <rdar://problem/25686570> ignore interposing on a weak function that does not exist
1271 if ( tuple
.replacee
== 0 )
1273 // <rdar://problem/7937695> verify that replacement is in this image
1274 if ( this->containsAddress((void*)tuple
.replacement
) ) {
1275 // chain to any existing interpositions
1276 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it
!= fgInterposingTuples
.end(); it
++) {
1277 if ( it
->replacee
== tuple
.replacee
) {
1278 tuple
.replacee
= it
->replacement
;
1281 ImageLoader::fgInterposingTuples
.push_back(tuple
);
1289 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1293 uint32_t ImageLoaderMachO::sdkVersion(const mach_header
* mh
)
1295 const uint32_t cmd_count
= mh
->ncmds
;
1296 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
));
1297 const struct load_command
* cmd
= cmds
;
1298 const struct version_min_command
* versCmd
;
1299 const struct build_version_command
* buildVersCmd
;
1300 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1301 switch ( cmd
->cmd
) {
1302 case LC_VERSION_MIN_MACOSX
:
1303 case LC_VERSION_MIN_IPHONEOS
:
1304 case LC_VERSION_MIN_TVOS
:
1305 case LC_VERSION_MIN_WATCHOS
:
1306 versCmd
= (version_min_command
*)cmd
;
1307 return versCmd
->sdk
;
1308 case LC_BUILD_VERSION
:
1309 buildVersCmd
= (build_version_command
*)cmd
;
1310 return buildVersCmd
->sdk
;
1312 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1317 uint32_t ImageLoaderMachO::sdkVersion() const
1319 return ImageLoaderMachO::sdkVersion(machHeader());
1322 uint32_t ImageLoaderMachO::minOSVersion(const mach_header
* mh
)
1324 const uint32_t cmd_count
= mh
->ncmds
;
1325 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
));
1326 const struct load_command
* cmd
= cmds
;
1327 const struct version_min_command
* versCmd
;
1328 const struct build_version_command
* buildVersCmd
;
1329 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1330 switch ( cmd
->cmd
) {
1331 case LC_VERSION_MIN_MACOSX
:
1332 case LC_VERSION_MIN_IPHONEOS
:
1333 case LC_VERSION_MIN_TVOS
:
1334 case LC_VERSION_MIN_WATCHOS
:
1335 versCmd
= (version_min_command
*)cmd
;
1336 return versCmd
->version
;
1337 case LC_BUILD_VERSION
:
1338 buildVersCmd
= (build_version_command
*)cmd
;
1339 return buildVersCmd
->minos
;
1341 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1346 uint32_t ImageLoaderMachO::minOSVersion() const
1348 return ImageLoaderMachO::minOSVersion(machHeader());
1352 void* ImageLoaderMachO::getThreadPC() const
1354 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1355 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1356 const struct load_command
* cmd
= cmds
;
1357 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1358 if ( cmd
->cmd
== LC_MAIN
) {
1359 entry_point_command
* mainCmd
= (entry_point_command
*)cmd
;
1360 void* entry
= (void*)(mainCmd
->entryoff
+ (char*)fMachOData
);
1361 // <rdar://problem/8543820&9228031> verify entry point is in image
1362 if ( this->containsAddress(entry
) )
1365 throw "LC_MAIN entryoff is out of range";
1367 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1373 void* ImageLoaderMachO::getMain() const
1375 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1376 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1377 const struct load_command
* cmd
= cmds
;
1378 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1383 const i386_thread_state_t
* registers
= (i386_thread_state_t
*)(((char*)cmd
) + 16);
1384 void* entry
= (void*)(registers
->eip
+ fSlide
);
1386 const x86_thread_state64_t
* registers
= (x86_thread_state64_t
*)(((char*)cmd
) + 16);
1387 void* entry
= (void*)(registers
->rip
+ fSlide
);
1389 const arm_thread_state_t
* registers
= (arm_thread_state_t
*)(((char*)cmd
) + 16);
1390 void* entry
= (void*)(registers
->__pc
+ fSlide
);
1392 const arm_thread_state64_t
* registers
= (arm_thread_state64_t
*)(((char*)cmd
) + 16);
1393 void* entry
= (void*)(registers
->__pc
+ fSlide
);
1395 #warning need processor specific code
1397 // <rdar://problem/8543820&9228031> verify entry point is in image
1398 if ( this->containsAddress(entry
) ) {
1404 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1406 throw "no valid entry point";
1409 bool ImageLoaderMachO::needsAddedLibSystemDepency(unsigned int libCount
, const macho_header
* mh
)
1411 // <rdar://problem/6357561> ensure that every image depends on something which depends on libSystem
1415 // <rdar://problem/6409800> dyld implicit-libSystem breaks valgrind
1416 if ( mh
->filetype
== MH_EXECUTE
)
1419 bool isNonOSdylib
= false;
1420 const uint32_t cmd_count
= mh
->ncmds
;
1421 const struct load_command
* const cmds
= (struct load_command
*)((uint8_t*)mh
+sizeof(macho_header
));
1422 const struct load_command
* cmd
= cmds
;
1423 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1426 case LC_LOAD_WEAK_DYLIB
:
1427 case LC_REEXPORT_DYLIB
:
1428 case LC_LOAD_UPWARD_DYLIB
:
1432 const dylib_command
* dylibID
= (dylib_command
*)cmd
;
1433 const char* installPath
= (char*)cmd
+ dylibID
->dylib
.name
.offset
;
1434 // It is OK for OS dylibs (libSystem or libmath or Rosetta shims) to have no dependents
1435 // but all other dylibs must depend on libSystem for initialization to initialize libSystem first
1436 // <rdar://problem/6497528> rosetta circular dependency spew
1437 isNonOSdylib
= ( (strncmp(installPath
, "/usr/lib/", 9) != 0) && (strncmp(installPath
, "/usr/libexec/oah/Shims", 9) != 0) );
1441 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1443 return isNonOSdylib
;
1447 void ImageLoaderMachO::doGetDependentLibraries(DependentLibraryInfo libs
[])
1449 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) {
1450 DependentLibraryInfo
* lib
= &libs
[0];
1451 lib
->name
= LIBSYSTEM_DYLIB_PATH
;
1452 lib
->info
.checksum
= 0;
1453 lib
->info
.minVersion
= 0;
1454 lib
->info
.maxVersion
= 0;
1455 lib
->required
= false;
1456 lib
->reExported
= false;
1457 lib
->upward
= false;
1461 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1462 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1463 const struct load_command
* cmd
= cmds
;
1464 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1467 case LC_LOAD_WEAK_DYLIB
:
1468 case LC_REEXPORT_DYLIB
:
1469 case LC_LOAD_UPWARD_DYLIB
:
1471 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
1472 DependentLibraryInfo
* lib
= &libs
[index
++];
1473 lib
->name
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
1474 //lib->name = strdup((char*)cmd + dylib->dylib.name.offset);
1475 lib
->info
.checksum
= dylib
->dylib
.timestamp
;
1476 lib
->info
.minVersion
= dylib
->dylib
.compatibility_version
;
1477 lib
->info
.maxVersion
= dylib
->dylib
.current_version
;
1478 lib
->required
= (cmd
->cmd
!= LC_LOAD_WEAK_DYLIB
);
1479 lib
->reExported
= (cmd
->cmd
== LC_REEXPORT_DYLIB
);
1480 lib
->upward
= (cmd
->cmd
== LC_LOAD_UPWARD_DYLIB
);
1484 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1489 ImageLoader::LibraryInfo
ImageLoaderMachO::doGetLibraryInfo(const LibraryInfo
&)
1492 if ( fDylibIDOffset
!= 0 ) {
1493 const dylib_command
* dylibID
= (dylib_command
*)(&fMachOData
[fDylibIDOffset
]);
1494 info
.minVersion
= dylibID
->dylib
.compatibility_version
;
1495 info
.maxVersion
= dylibID
->dylib
.current_version
;
1496 info
.checksum
= dylibID
->dylib
.timestamp
;
1499 info
.minVersion
= 0;
1500 info
.maxVersion
= 0;
1506 void ImageLoaderMachO::getRPaths(const LinkContext
& context
, std::vector
<const char*>& paths
) const
1508 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1509 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1510 const struct load_command
* cmd
= cmds
;
1511 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1514 const char* pathToAdd
= NULL
;
1515 const char* path
= (char*)cmd
+ ((struct rpath_command
*)cmd
)->path
.offset
;
1516 if ( (strncmp(path
, "@loader_path", 12) == 0) && ((path
[12] == '/') || (path
[12] == '\0')) ) {
1517 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1518 if ( context
.processIsRestricted
&& (context
.mainExecutable
== this) ) {
1519 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @loader_path\n", path
, this->getPath());
1523 char resolvedPath
[PATH_MAX
];
1524 if ( realpath(this->getPath(), resolvedPath
) != NULL
) {
1525 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1526 strcpy(newRealPath
, resolvedPath
);
1527 char* addPoint
= strrchr(newRealPath
,'/');
1528 if ( addPoint
!= NULL
) {
1529 strcpy(addPoint
, &path
[12]);
1530 pathToAdd
= strdup(newRealPath
);
1534 else if ( (strncmp(path
, "@executable_path", 16) == 0) && ((path
[16] == '/') || (path
[16] == '\0')) ) {
1535 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1536 if ( context
.processIsRestricted
) {
1537 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because of @executable_path\n", path
, this->getPath());
1541 char resolvedPath
[PATH_MAX
];
1542 if ( realpath(context
.mainExecutable
->getPath(), resolvedPath
) != NULL
) {
1543 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
1544 strcpy(newRealPath
, resolvedPath
);
1545 char* addPoint
= strrchr(newRealPath
,'/');
1546 if ( addPoint
!= NULL
) {
1547 strcpy(addPoint
, &path
[16]);
1548 pathToAdd
= strdup(newRealPath
);
1552 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1553 else if ( (path
[0] != '/') && context
.processIsRestricted
) {
1554 dyld::warn("LC_RPATH %s in %s being ignored in restricted program because it is a relative path\n", path
, this->getPath());
1558 #if SUPPORT_ROOT_PATH
1559 else if ( (path
[0] == '/') && (context
.rootPaths
!= NULL
) ) {
1560 // <rdar://problem/5869973> DYLD_ROOT_PATH should apply to LC_RPATH rpaths
1561 // DYLD_ROOT_PATH can be a list of paths, but at this point we can only support one, so use first combination that exists
1563 for(const char** rp
= context
.rootPaths
; *rp
!= NULL
; ++rp
) {
1564 char newPath
[PATH_MAX
];
1565 strlcpy(newPath
, *rp
, PATH_MAX
);
1566 strlcat(newPath
, path
, PATH_MAX
);
1567 struct stat stat_buf
;
1568 if ( stat(newPath
, &stat_buf
) != -1 ) {
1569 //dyld::log("combined DYLD_ROOT_PATH and LC_RPATH: %s\n", newPath);
1570 pathToAdd
= strdup(newPath
);
1576 // make copy so that all elements of 'paths' can be freed
1577 pathToAdd
= strdup(path
);
1582 // make copy so that all elements of 'paths' can be freed
1583 pathToAdd
= strdup(path
);
1585 if ( pathToAdd
!= NULL
)
1586 paths
.push_back(pathToAdd
);
1589 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1594 bool ImageLoaderMachO::getUUID(uuid_t uuid
) const
1596 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1597 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1598 const struct load_command
* cmd
= cmds
;
1599 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1602 uuid_command
* uc
= (uuid_command
*)cmd
;
1603 memcpy(uuid
, uc
->uuid
, 16);
1606 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1612 void ImageLoaderMachO::doRebase(const LinkContext
& context
)
1614 // <rdar://problem/25329861> Delay calling setNeverUnload() until we know this is not for dlopen_preflight()
1615 if ( fRetainForObjC
)
1616 this->setNeverUnload();
1618 // if prebound and loaded at prebound address, then no need to rebase
1619 if ( this->usablePrebinding(context
) ) {
1620 // skip rebasing because prebinding is valid
1621 ++fgImagesWithUsedPrebinding
; // bump totals for statistics
1625 // print why prebinding was not used
1626 if ( context
.verbosePrebinding
) {
1627 if ( !this->isPrebindable() ) {
1628 dyld::log("dyld: image not prebound, so could not use prebinding in %s\n", this->getPath());
1630 else if ( fSlide
!= 0 ) {
1631 dyld::log("dyld: image slid, so could not use prebinding in %s\n", this->getPath());
1633 else if ( !this->allDependentLibrariesAsWhenPreBound() ) {
1634 dyld::log("dyld: dependent libraries changed, so could not use prebinding in %s\n", this->getPath());
1636 else if ( !this->usesTwoLevelNameSpace() ){
1637 dyld::log("dyld: image uses flat-namespace so, parts of prebinding ignored %s\n", this->getPath());
1640 dyld::log("dyld: environment variable disabled use of prebinding in %s\n", this->getPath());
1644 //dyld::log("slide=0x%08lX for %s\n", slide, this->getPath());
1646 #if PREBOUND_IMAGE_SUPPORT
1647 // if prebound and we got here, then prebinding is not valid, so reset all lazy pointers
1648 // if this image is in the shared cache, do not reset, they will be bound in doBind()
1649 if ( this->isPrebindable() && !fInSharedCache
)
1650 this->resetPreboundLazyPointers(context
);
1653 // if loaded at preferred address, no rebasing necessary
1654 if ( this->fSlide
== 0 )
1657 #if TEXT_RELOC_SUPPORT
1658 // if there are __TEXT fixups, temporarily make __TEXT writable
1659 if ( fTextSegmentRebases
)
1660 this->makeTextSegmentWritable(context
, true);
1663 // do actual rebasing
1664 this->rebase(context
, fSlide
);
1666 #if TEXT_RELOC_SUPPORT
1667 // if there were __TEXT fixups, restore write protection
1668 if ( fTextSegmentRebases
)
1669 this->makeTextSegmentWritable(context
, false);
1674 #if TEXT_RELOC_SUPPORT
1675 void ImageLoaderMachO::makeTextSegmentWritable(const LinkContext
& context
, bool writeable
)
1677 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1678 if ( segExecutable(i
) ) {
1680 segMakeWritable(i
, context
);
1683 #if !__i386__ && !__x86_64__
1684 // some processors require range to be invalidated before it is made executable
1685 sys_icache_invalidate((void*)segActualLoadAddress(i
), segSize(textSegmentIndex
));
1687 segProtect(i
, context
);
1695 const ImageLoader::Symbol
* ImageLoaderMachO::findExportedSymbol(const char* name
, bool searchReExports
, const char* thisPath
, const ImageLoader
** foundIn
) const
1697 // look in this image first
1698 const ImageLoader::Symbol
* result
= this->findShallowExportedSymbol(name
, foundIn
);
1699 if ( result
!= NULL
)
1702 if ( searchReExports
) {
1703 for(unsigned int i
=0; i
< libraryCount(); ++i
){
1704 if ( libReExported(i
) ) {
1705 ImageLoader
* image
= libImage(i
);
1706 if ( image
!= NULL
) {
1707 const char* reExPath
= libPath(i
);
1708 result
= image
->findExportedSymbol(name
, searchReExports
, reExPath
, foundIn
);
1709 if ( result
!= NULL
)
1722 uintptr_t ImageLoaderMachO::getExportedSymbolAddress(const Symbol
* sym
, const LinkContext
& context
,
1723 const ImageLoader
* requestor
, bool runResolver
, const char* symbolName
) const
1725 return this->getSymbolAddress(sym
, requestor
, context
, runResolver
);
1728 uintptr_t ImageLoaderMachO::getSymbolAddress(const Symbol
* sym
, const ImageLoader
* requestor
,
1729 const LinkContext
& context
, bool runResolver
) const
1731 uintptr_t result
= exportedSymbolAddress(context
, sym
, requestor
, runResolver
);
1732 // check for interposing overrides
1733 result
= interposedAddress(context
, result
, requestor
);
1737 ImageLoader::DefinitionFlags
ImageLoaderMachO::getExportedSymbolInfo(const Symbol
* sym
) const
1739 if ( exportedSymbolIsWeakDefintion(sym
) )
1740 return kWeakDefinition
;
1742 return kNoDefinitionOptions
;
1745 const char* ImageLoaderMachO::getExportedSymbolName(const Symbol
* sym
) const
1747 return exportedSymbolName(sym
);
1750 uint32_t ImageLoaderMachO::getExportedSymbolCount() const
1752 return exportedSymbolCount();
1756 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedExportedSymbol(uint32_t index
) const
1758 return exportedSymbolIndexed(index
);
1762 uint32_t ImageLoaderMachO::getImportedSymbolCount() const
1764 return importedSymbolCount();
1768 const ImageLoader::Symbol
* ImageLoaderMachO::getIndexedImportedSymbol(uint32_t index
) const
1770 return importedSymbolIndexed(index
);
1774 ImageLoader::ReferenceFlags
ImageLoaderMachO::getImportedSymbolInfo(const ImageLoader::Symbol
* sym
) const
1776 ImageLoader::ReferenceFlags flags
= kNoReferenceOptions
;
1781 const char* ImageLoaderMachO::getImportedSymbolName(const ImageLoader::Symbol
* sym
) const
1783 return importedSymbolName(sym
);
1787 bool ImageLoaderMachO::getSectionContent(const char* segmentName
, const char* sectionName
, void** start
, size_t* length
)
1789 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1790 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1791 const struct load_command
* cmd
= cmds
;
1792 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1794 case LC_SEGMENT_COMMAND
:
1796 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1797 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1798 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1799 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1800 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1801 *start
= (uintptr_t*)(sect
->addr
+ fSlide
);
1802 *length
= sect
->size
;
1809 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1816 void ImageLoaderMachO::getUnwindInfo(dyld_unwind_sections
* info
)
1818 info
->mh
= this->machHeader();
1819 info
->dwarf_section
= 0;
1820 info
->dwarf_section_length
= 0;
1821 info
->compact_unwind_section
= 0;
1822 info
->compact_unwind_section_length
= 0;
1823 if ( fEHFrameSectionOffset
!= 0 ) {
1824 const macho_section
* sect
= (macho_section
*)&fMachOData
[fEHFrameSectionOffset
];
1825 info
->dwarf_section
= (void*)(sect
->addr
+ fSlide
);
1826 info
->dwarf_section_length
= sect
->size
;
1828 if ( fUnwindInfoSectionOffset
!= 0 ) {
1829 const macho_section
* sect
= (macho_section
*)&fMachOData
[fUnwindInfoSectionOffset
];
1830 info
->compact_unwind_section
= (void*)(sect
->addr
+ fSlide
);
1831 info
->compact_unwind_section_length
= sect
->size
;
1835 intptr_t ImageLoaderMachO::computeSlide(const mach_header
* mh
)
1837 const uint32_t cmd_count
= mh
->ncmds
;
1838 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
1839 const load_command
* cmd
= cmds
;
1840 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1841 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
1842 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
1843 if ( strcmp(seg
->segname
, "__TEXT") == 0 )
1844 return (char*)mh
- (char*)(seg
->vmaddr
);
1846 cmd
= (const load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1851 bool ImageLoaderMachO::findSection(const mach_header
* mh
, const char* segmentName
, const char* sectionName
, void** sectAddress
, size_t* sectSize
)
1853 const uint32_t cmd_count
= mh
->ncmds
;
1854 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
1855 const load_command
* cmd
= cmds
;
1856 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1858 case LC_SEGMENT_COMMAND
:
1860 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
1861 const macho_section
* const sectionsStart
= (macho_section
*)((char*)seg
+ sizeof(macho_segment_command
));
1862 const macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1863 for (const macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1864 if ( (strcmp(sect
->segname
, segmentName
) == 0) && (strcmp(sect
->sectname
, sectionName
) == 0) ) {
1865 *sectAddress
= (void*)(sect
->addr
+ computeSlide(mh
));
1866 *sectSize
= sect
->size
;
1873 cmd
= (const load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1879 bool ImageLoaderMachO::findSection(const void* imageInterior
, const char** segmentName
, const char** sectionName
, size_t* sectionOffset
)
1881 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1882 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1883 const struct load_command
* cmd
= cmds
;
1884 const uintptr_t unslidInteriorAddress
= (uintptr_t)imageInterior
- this->getSlide();
1885 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1887 case LC_SEGMENT_COMMAND
:
1889 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
1890 if ( (unslidInteriorAddress
>= seg
->vmaddr
) && (unslidInteriorAddress
< (seg
->vmaddr
+seg
->vmsize
)) ) {
1891 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
1892 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
1893 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
1894 if ((sect
->addr
<= unslidInteriorAddress
) && (unslidInteriorAddress
< (sect
->addr
+sect
->size
))) {
1895 if ( segmentName
!= NULL
)
1896 *segmentName
= sect
->segname
;
1897 if ( sectionName
!= NULL
)
1898 *sectionName
= sect
->sectname
;
1899 if ( sectionOffset
!= NULL
)
1900 *sectionOffset
= unslidInteriorAddress
- sect
->addr
;
1908 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1913 const char* ImageLoaderMachO::libPath(unsigned int index
) const
1915 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
1916 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
1917 const struct load_command
* cmd
= cmds
;
1919 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1920 switch ( cmd
->cmd
) {
1922 case LC_LOAD_WEAK_DYLIB
:
1923 case LC_REEXPORT_DYLIB
:
1924 case LC_LOAD_UPWARD_DYLIB
:
1925 if ( index
== count
) {
1926 const struct dylib_command
* dylibCmd
= (struct dylib_command
*)cmd
;
1927 return (char*)cmd
+ dylibCmd
->dylib
.name
.offset
;
1932 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1935 // <rdar://problem/24256354> if image linked with nothing and we implicitly added libSystem.dylib, return that
1936 if ( needsAddedLibSystemDepency(libraryCount(), (macho_header
*)fMachOData
) ) {
1937 return LIBSYSTEM_DYLIB_PATH
;
1944 void __attribute__((noreturn
)) ImageLoaderMachO::throwSymbolNotFound(const LinkContext
& context
, const char* symbol
,
1945 const char* referencedFrom
, const char* fromVersMismatch
,
1946 const char* expectedIn
)
1948 // record values for possible use by CrashReporter or Finder
1949 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_SYMBOL_MISSING
, referencedFrom
, expectedIn
, symbol
);
1950 dyld::throwf("Symbol not found: %s\n Referenced from: %s%s\n Expected in: %s\n",
1951 symbol
, referencedFrom
, fromVersMismatch
, expectedIn
);
1954 const mach_header
* ImageLoaderMachO::machHeader() const
1956 return (mach_header
*)fMachOData
;
1959 uintptr_t ImageLoaderMachO::getSlide() const
1964 // hmm. maybe this should be up in ImageLoader??
1965 const void* ImageLoaderMachO::getEnd() const
1967 uintptr_t lastAddress
= 0;
1968 for(unsigned int i
=0; i
< fSegmentsCount
; ++i
) {
1969 uintptr_t segEnd
= segActualEndAddress(i
);
1970 if ( strcmp(segName(i
), "__UNIXSTACK") != 0 ) {
1971 if ( segEnd
> lastAddress
)
1972 lastAddress
= segEnd
;
1975 return (const void*)lastAddress
;
1979 uintptr_t ImageLoaderMachO::bindLocation(const LinkContext
& context
, uintptr_t location
, uintptr_t value
,
1980 uint8_t type
, const char* symbolName
,
1981 intptr_t addend
, const char* inPath
, const char* toPath
, const char* msg
)
1984 if ( context
.verboseBind
) {
1986 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX + %ld\n",
1987 msg
, shortName(inPath
), (uintptr_t)location
,
1988 ((toPath
!= NULL
) ? shortName(toPath
) : "<missing weak_import>"),
1989 symbolName
, (uintptr_t)location
, value
, addend
);
1991 dyld::log("dyld: %sbind: %s:0x%08lX = %s:%s, *0x%08lX = 0x%08lX\n",
1992 msg
, shortName(inPath
), (uintptr_t)location
,
1993 ((toPath
!= NULL
) ? shortName(toPath
) : "<missing weak_import>"),
1994 symbolName
, (uintptr_t)location
, value
);
1997 // dyld::logBindings("%s: %s\n", targetImage->getShortName(), symbolName);
2001 uintptr_t* locationToFix
= (uintptr_t*)location
;
2003 uintptr_t newValue
= value
+addend
;
2006 case BIND_TYPE_POINTER
:
2007 // test first so we don't needless dirty pages
2008 if ( *locationToFix
!= newValue
)
2009 *locationToFix
= newValue
;
2011 case BIND_TYPE_TEXT_ABSOLUTE32
:
2012 loc32
= (uint32_t*)locationToFix
;
2013 value32
= (uint32_t)newValue
;
2014 if ( *loc32
!= value32
)
2017 case BIND_TYPE_TEXT_PCREL32
:
2018 loc32
= (uint32_t*)locationToFix
;
2019 value32
= (uint32_t)(newValue
- (((uintptr_t)locationToFix
) + 4));
2020 if ( *loc32
!= value32
)
2024 dyld::throwf("bad bind type %d", type
);
2027 // update statistics
2028 ++fgTotalBindFixups
;
2037 #if SUPPORT_OLD_CRT_INITIALIZATION
2038 // first 16 bytes of "start" in crt1.o
2040 static uint8_t sStandardEntryPointInstructions
[16] = { 0x6a, 0x00, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0x8b, 0x5d, 0x04, 0x89, 0x5c, 0x24 };
2045 void* dyldLazyBinder
; // filled in at launch by dyld to point into dyld to &stub_binding_helper
2046 void* dyldFuncLookup
; // filled in at launch by dyld to point into dyld to &_dyld_func_lookup
2047 // the following only exist in main executables built for 10.5 or later
2051 // These are defined in dyldStartup.s
2052 extern "C" void stub_binding_helper();
2053 extern "C" int _dyld_func_lookup(const char* name
, void** address
);
2055 void ImageLoaderMachO::setupLazyPointerHandler(const LinkContext
& context
)
2057 const macho_header
* mh
= (macho_header
*)fMachOData
;
2058 const uint32_t cmd_count
= mh
->ncmds
;
2059 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2060 const struct load_command
* cmd
;
2061 // There used to be some optimizations to skip this section scan, but we need to handle the
2062 // __dyld section in libdyld.dylib, so everything needs to be scanned for now.
2063 // <rdar://problem/10910062> CrashTracer: 1,295 crashes in bash at bash: getenv
2066 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2067 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2068 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2069 if ( strncmp(seg
->segname
, "__DATA", 6) == 0 ) {
2070 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2071 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2072 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2073 if ( strcmp(sect
->sectname
, "__dyld" ) == 0 ) {
2074 struct DATAdyld
* dd
= (struct DATAdyld
*)(sect
->addr
+ fSlide
);
2075 #if !__arm64__ && !__ARM_ARCH_7K__
2076 if ( sect
->size
> offsetof(DATAdyld
, dyldLazyBinder
) ) {
2077 if ( dd
->dyldLazyBinder
!= (void*)&stub_binding_helper
)
2078 dd
->dyldLazyBinder
= (void*)&stub_binding_helper
;
2080 #endif // !__arm64__
2081 if ( sect
->size
> offsetof(DATAdyld
, dyldFuncLookup
) ) {
2082 if ( dd
->dyldFuncLookup
!= (void*)&_dyld_func_lookup
)
2083 dd
->dyldFuncLookup
= (void*)&_dyld_func_lookup
;
2085 if ( mh
->filetype
== MH_EXECUTE
) {
2086 // there are two ways to get the program variables
2087 if ( (sect
->size
> offsetof(DATAdyld
, vars
)) && (dd
->vars
.mh
== mh
) ) {
2088 // some really old binaries have space for vars, but it is zero filled
2089 // main executable has 10.5 style __dyld section that has program variable pointers
2090 context
.setNewProgramVars(dd
->vars
);
2093 // main executable is pre-10.5 and requires the symbols names to be looked up
2094 this->lookupProgramVars(context
);
2095 #if SUPPORT_OLD_CRT_INITIALIZATION
2096 // If the first 16 bytes of the entry point's instructions do not
2097 // match what crt1.o supplies, then the program has a custom entry point.
2098 // This means it might be doing something that needs to be executed before
2099 // initializers are run.
2100 if ( memcmp(this->getMain(), sStandardEntryPointInstructions
, 16) != 0 ) {
2101 if ( context
.verboseInit
)
2102 dyld::log("dyld: program uses non-standard entry point so delaying running of initializers\n");
2103 context
.setRunInitialzersOldWay();
2108 else if ( mh
->filetype
== MH_DYLIB
) {
2109 const char* installPath
= this->getInstallPath();
2110 if ( (installPath
!= NULL
) && (strncmp(installPath
, "/usr/lib/", 9) == 0) ) {
2111 if ( sect
->size
> offsetof(DATAdyld
, vars
) ) {
2112 // use ProgramVars from libdyld.dylib but tweak mh field to correct value
2113 dd
->vars
.mh
= context
.mainExecutable
->machHeader();
2114 context
.setNewProgramVars(dd
->vars
);
2119 else if ( (strcmp(sect
->sectname
, "__program_vars" ) == 0) && (mh
->filetype
== MH_EXECUTE
) ) {
2120 // this is a Mac OS X 10.6 or later main executable
2121 struct ProgramVars
* pv
= (struct ProgramVars
*)(sect
->addr
+ fSlide
);
2122 context
.setNewProgramVars(*pv
);
2127 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2133 void ImageLoaderMachO::lookupProgramVars(const LinkContext
& context
) const
2135 ProgramVars vars
= context
.programVars
;
2136 const ImageLoader::Symbol
* sym
;
2138 // get mach header directly
2139 vars
.mh
= (macho_header
*)fMachOData
;
2142 sym
= this->findShallowExportedSymbol("_NXArgc", NULL
);
2144 vars
.NXArgcPtr
= (int*)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2147 sym
= this->findShallowExportedSymbol("_NXArgv", NULL
);
2149 vars
.NXArgvPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2152 sym
= this->findShallowExportedSymbol("_environ", NULL
);
2154 vars
.environPtr
= (const char***)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2156 // lookup __progname
2157 sym
= this->findShallowExportedSymbol("___progname", NULL
);
2159 vars
.__prognamePtr
= (const char**)this->getExportedSymbolAddress(sym
, context
, this, false, NULL
);
2161 context
.setNewProgramVars(vars
);
2165 bool ImageLoaderMachO::usablePrebinding(const LinkContext
& context
) const
2167 // if prebound and loaded at prebound address, and all libraries are same as when this was prebound, then no need to bind
2168 if ( ((this->isPrebindable() && (this->getSlide() == 0)) || fInSharedCache
)
2169 && this->usesTwoLevelNameSpace()
2170 && this->allDependentLibrariesAsWhenPreBound() ) {
2171 // allow environment variables to disable prebinding
2172 if ( context
.bindFlat
)
2174 switch ( context
.prebindUsage
) {
2175 case kUseAllPrebinding
:
2177 case kUseSplitSegPrebinding
:
2178 return this->fIsSplitSeg
;
2179 case kUseAllButAppPredbinding
:
2180 return (this != context
.mainExecutable
);
2181 case kUseNoPrebinding
:
2189 void ImageLoaderMachO::doImageInit(const LinkContext
& context
)
2191 if ( fHasDashInit
) {
2192 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2193 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2194 const struct load_command
* cmd
= cmds
;
2195 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2197 case LC_ROUTINES_COMMAND
:
2198 Initializer func
= (Initializer
)(((struct macho_routines_command
*)cmd
)->init_address
+ fSlide
);
2199 // <rdar://problem/8543820&9228031> verify initializers are in image
2200 if ( ! this->containsAddress((void*)func
) ) {
2201 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
2203 if ( ! dyld::gProcessInfo
->libSystemInitialized
) {
2204 // <rdar://problem/17973316> libSystem initializer must run first
2205 dyld::throwf("-init function in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2207 if ( context
.verboseInit
)
2208 dyld::log("dyld: calling -init function %p in %s\n", func
, this->getPath());
2209 dyld3::kdebug_trace_dyld_duration(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)func
, 0, ^{
2210 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
2214 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2219 void ImageLoaderMachO::doModInitFunctions(const LinkContext
& context
)
2221 if ( fHasInitializers
) {
2222 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2223 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2224 const struct load_command
* cmd
= cmds
;
2225 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2226 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2227 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2228 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2229 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2230 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2231 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2232 if ( type
== S_MOD_INIT_FUNC_POINTERS
) {
2233 Initializer
* inits
= (Initializer
*)(sect
->addr
+ fSlide
);
2234 const size_t count
= sect
->size
/ sizeof(uintptr_t);
2235 // <rdar://problem/23929217> Ensure __mod_init_func section is within segment
2236 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
2237 dyld::throwf("__mod_init_funcs section has malformed address range for %s\n", this->getPath());
2238 for (size_t j
=0; j
< count
; ++j
) {
2239 Initializer func
= inits
[j
];
2240 // <rdar://problem/8543820&9228031> verify initializers are in image
2241 if ( ! this->containsAddress((void*)func
) ) {
2242 dyld::throwf("initializer function %p not in mapped image for %s\n", func
, this->getPath());
2244 if ( ! dyld::gProcessInfo
->libSystemInitialized
) {
2245 // <rdar://problem/17973316> libSystem initializer must run first
2246 const char* installPath
= getInstallPath();
2247 if ( (installPath
== NULL
) || (strcmp(installPath
, LIBSYSTEM_DYLIB_PATH
) != 0) )
2248 dyld::throwf("initializer in image (%s) that does not link with libSystem.dylib\n", this->getPath());
2250 if ( context
.verboseInit
)
2251 dyld::log("dyld: calling initializer function %p in %s\n", func
, this->getPath());
2252 bool haveLibSystemHelpersBefore
= (dyld::gLibSystemHelpers
!= NULL
);
2253 dyld3::kdebug_trace_dyld_duration(DBG_DYLD_TIMING_STATIC_INITIALIZER
, (uint64_t)func
, 0, ^{
2254 func(context
.argc
, context
.argv
, context
.envp
, context
.apple
, &context
.programVars
);
2256 bool haveLibSystemHelpersAfter
= (dyld::gLibSystemHelpers
!= NULL
);
2257 if ( !haveLibSystemHelpersBefore
&& haveLibSystemHelpersAfter
) {
2258 // now safe to use malloc() and other calls in libSystem.dylib
2259 dyld::gProcessInfo
->libSystemInitialized
= true;
2265 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2272 void ImageLoaderMachO::doGetDOFSections(const LinkContext
& context
, std::vector
<ImageLoader::DOFInfo
>& dofs
)
2274 if ( fHasDOFSections
) {
2275 // walk load commands (mapped in at start of __TEXT segment)
2276 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2277 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2278 const struct load_command
* cmd
= cmds
;
2279 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2281 case LC_SEGMENT_COMMAND
:
2283 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2284 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2285 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2286 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2287 if ( (sect
->flags
& SECTION_TYPE
) == S_DTRACE_DOF
) {
2288 // <rdar://problem/23929217> Ensure section is within segment
2289 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
2290 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2291 ImageLoader::DOFInfo info
;
2292 info
.dof
= (void*)(sect
->addr
+ fSlide
);
2293 info
.imageHeader
= this->machHeader();
2294 info
.imageShortName
= this->getShortName();
2295 dofs
.push_back(info
);
2301 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2307 bool ImageLoaderMachO::doInitialization(const LinkContext
& context
)
2309 CRSetCrashLogMessage2(this->getPath());
2311 // mach-o has -init and static initializers
2312 doImageInit(context
);
2313 doModInitFunctions(context
);
2315 CRSetCrashLogMessage2(NULL
);
2317 return (fHasDashInit
|| fHasInitializers
);
2320 bool ImageLoaderMachO::needsInitialization()
2322 return ( fHasDashInit
|| fHasInitializers
);
2326 bool ImageLoaderMachO::needsTermination()
2328 return fHasTerminators
;
2332 void ImageLoaderMachO::doTermination(const LinkContext
& context
)
2334 if ( fHasTerminators
) {
2335 const uint32_t cmd_count
= ((macho_header
*)fMachOData
)->ncmds
;
2336 const struct load_command
* const cmds
= (struct load_command
*)&fMachOData
[sizeof(macho_header
)];
2337 const struct load_command
* cmd
= cmds
;
2338 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2339 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2340 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2341 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2342 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2343 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2344 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
2345 if ( type
== S_MOD_TERM_FUNC_POINTERS
) {
2346 // <rdar://problem/23929217> Ensure section is within segment
2347 if ( (sect
->addr
< seg
->vmaddr
) || (sect
->addr
+sect
->size
> seg
->vmaddr
+seg
->vmsize
) || (sect
->addr
+sect
->size
< sect
->addr
) )
2348 dyld::throwf("DOF section has malformed address range for %s\n", this->getPath());
2349 Terminator
* terms
= (Terminator
*)(sect
->addr
+ fSlide
);
2350 const size_t count
= sect
->size
/ sizeof(uintptr_t);
2351 for (size_t j
=count
; j
> 0; --j
) {
2352 Terminator func
= terms
[j
-1];
2353 // <rdar://problem/8543820&9228031> verify terminators are in image
2354 if ( ! this->containsAddress((void*)func
) ) {
2355 dyld::throwf("termination function %p not in mapped image for %s\n", func
, this->getPath());
2357 if ( context
.verboseInit
)
2358 dyld::log("dyld: calling termination function %p in %s\n", func
, this->getPath());
2364 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2370 void ImageLoaderMachO::printStatisticsDetails(unsigned int imageCount
, const InitializerTimingList
& timingInfo
)
2372 ImageLoader::printStatisticsDetails(imageCount
, timingInfo
);
2373 dyld::log("total symbol trie searches: %d\n", fgSymbolTrieSearchs
);
2374 dyld::log("total symbol table binary searches: %d\n", fgSymbolTableBinarySearchs
);
2375 dyld::log("total images defining weak symbols: %u\n", fgImagesHasWeakDefinitions
);
2376 dyld::log("total images using weak symbols: %u\n", fgImagesRequiringCoalescing
);
2380 intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext
& context
)
2382 // preflight and calculate slide if needed
2383 const bool inPIE
= (fgNextPIEDylibAddress
!= 0);
2385 if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
2386 bool needsToSlide
= false;
2387 bool imageHasPreferredLoadAddress
= segHasPreferredLoadAddress(0);
2388 uintptr_t lowAddr
= (unsigned long)(-1);
2389 uintptr_t highAddr
= 0;
2390 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2391 const uintptr_t segLow
= segPreferredLoadAddress(i
);
2392 const uintptr_t segHigh
= dyld_page_round(segLow
+ segSize(i
));
2393 if ( segLow
< highAddr
) {
2394 if ( dyld_page_size
> 4096 )
2395 dyld::throwf("can't map segments into 16KB pages");
2397 dyld::throwf("overlapping segments");
2399 if ( segLow
< lowAddr
)
2401 if ( segHigh
> highAddr
)
2404 if ( needsToSlide
|| !imageHasPreferredLoadAddress
|| inPIE
|| !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
2405 needsToSlide
= true;
2407 if ( needsToSlide
) {
2408 // find a chunk of address space to hold all segments
2409 uintptr_t addr
= reserveAnAddressRange(highAddr
-lowAddr
, context
);
2410 slide
= addr
- lowAddr
;
2413 else if ( ! this->segmentsCanSlide() ) {
2414 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2415 if ( (strcmp(segName(i
), "__PAGEZERO") == 0) && (segFileSize(i
) == 0) && (segPreferredLoadAddress(i
) == 0) )
2417 if ( !reserveAddressRange(segPreferredLoadAddress(i
), segSize(i
)) )
2418 dyld::throwf("can't map unslidable segment %s to 0x%lX with size 0x%lX", segName(i
), segPreferredLoadAddress(i
), segSize(i
));
2422 throw "mach-o does not support independently sliding segments";
2428 uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length
, const ImageLoader::LinkContext
& context
)
2430 vm_address_t addr
= 0;
2431 vm_size_t size
= length
;
2432 // in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
2433 if ( fgNextPIEDylibAddress
!= 0 ) {
2434 // add small (0-3 pages) random padding between dylibs
2435 addr
= fgNextPIEDylibAddress
+ (__stack_chk_guard
/fgNextPIEDylibAddress
& (sizeof(long)-1))*dyld_page_size
;
2436 //dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
2437 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2438 if ( r
== KERN_SUCCESS
) {
2439 fgNextPIEDylibAddress
= addr
+ size
;
2442 fgNextPIEDylibAddress
= 0;
2444 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_ANYWHERE
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2445 if ( r
!= KERN_SUCCESS
)
2446 throw "out of address space";
2451 bool ImageLoaderMachO::reserveAddressRange(uintptr_t start
, size_t length
)
2453 vm_address_t addr
= start
;
2454 vm_size_t size
= length
;
2455 kern_return_t r
= vm_alloc(&addr
, size
, VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_DYLIB
));
2456 if ( r
!= KERN_SUCCESS
)
2463 void ImageLoaderMachO::mapSegments(int fd
, uint64_t offsetInFat
, uint64_t lenInFat
, uint64_t fileLen
, const LinkContext
& context
)
2465 // find address range for image
2466 intptr_t slide
= this->assignSegmentAddresses(context
);
2467 if ( context
.verboseMapping
) {
2468 if ( offsetInFat
!= 0 )
2469 dyld::log("dyld: Mapping %s (slice offset=%llu)\n", this->getPath(), (unsigned long long)offsetInFat
);
2471 dyld::log("dyld: Mapping %s\n", this->getPath());
2473 // map in all segments
2474 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2475 vm_offset_t fileOffset
= (vm_offset_t
)(segFileOffset(i
) + offsetInFat
);
2476 vm_size_t size
= segFileSize(i
);
2477 uintptr_t requestedLoadAddress
= segPreferredLoadAddress(i
) + slide
;
2479 if ( !segUnaccessible(i
) ) {
2480 // If has text-relocs, don't set x-bit initially.
2481 // Instead set it later after text-relocs have been done.
2482 if ( segExecutable(i
) && !(segHasRebaseFixUps(i
) && (slide
!= 0)) )
2483 protection
|= PROT_EXEC
;
2484 if ( segReadable(i
) )
2485 protection
|= PROT_READ
;
2486 if ( segWriteable(i
) ) {
2487 protection
|= PROT_WRITE
;
2488 // rdar://problem/22525618 force __LINKEDIT to always be mapped read-only
2489 if ( strcmp(segName(i
), "__LINKEDIT") == 0 )
2490 protection
= PROT_READ
;
2494 // initially map __IMPORT segments R/W so dyld can update them
2495 if ( segIsReadOnlyImport(i
) )
2496 protection
|= PROT_WRITE
;
2498 // wholly zero-fill segments have nothing to mmap() in
2500 if ( (fileOffset
+size
) > fileLen
) {
2501 dyld::throwf("truncated mach-o error: segment %s extends to %llu which is past end of file %llu",
2502 segName(i
), (uint64_t)(fileOffset
+size
), fileLen
);
2504 void* loadAddress
= xmmap((void*)requestedLoadAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, fileOffset
);
2505 if ( loadAddress
== ((void*)(-1)) ) {
2506 int mmapErr
= errno
;
2507 if ( mmapErr
== EPERM
) {
2508 if ( dyld::sandboxBlockedMmap(getPath()) )
2509 dyld::throwf("file system sandbox blocked mmap() of '%s'", this->getPath());
2511 dyld::throwf("code signing blocked mmap() of '%s'", this->getPath());
2514 dyld::throwf("mmap() errno=%d at address=0x%08lX, size=0x%08lX segment=%s in Segment::map() mapping %s",
2515 mmapErr
, requestedLoadAddress
, (uintptr_t)size
, segName(i
), getPath());
2519 ++ImageLoader::fgTotalSegmentsMapped
;
2520 ImageLoader::fgTotalBytesMapped
+= size
;
2521 if ( context
.verboseMapping
)
2522 dyld::log("%18s at 0x%08lX->0x%08lX with permissions %c%c%c\n", segName(i
), requestedLoadAddress
, requestedLoadAddress
+size
-1,
2523 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2526 // update slide to reflect load location
2527 this->setSlide(slide
);
2530 void ImageLoaderMachO::mapSegments(const void* memoryImage
, uint64_t imageLen
, const LinkContext
& context
)
2532 // find address range for image
2533 intptr_t slide
= this->assignSegmentAddresses(context
);
2534 if ( context
.verboseMapping
)
2535 dyld::log("dyld: Mapping memory %p\n", memoryImage
);
2536 // map in all segments
2537 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2538 vm_address_t loadAddress
= segPreferredLoadAddress(i
) + slide
;
2539 vm_address_t srcAddr
= (uintptr_t)memoryImage
+ segFileOffset(i
);
2540 vm_size_t size
= segFileSize(i
);
2541 kern_return_t r
= vm_copy(mach_task_self(), srcAddr
, size
, loadAddress
);
2542 if ( r
!= KERN_SUCCESS
)
2543 throw "can't map segment";
2544 if ( context
.verboseMapping
)
2545 dyld::log("%18s at 0x%08lX->0x%08lX\n", segName(i
), (uintptr_t)loadAddress
, (uintptr_t)loadAddress
+size
-1);
2547 // update slide to reflect load location
2548 this->setSlide(slide
);
2549 // set R/W permissions on all segments at slide location
2550 for(unsigned int i
=0, e
=segmentCount(); i
< e
; ++i
) {
2551 segProtect(i
, context
);
2556 void ImageLoaderMachO::segProtect(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
2558 vm_prot_t protection
= 0;
2559 if ( !segUnaccessible(segIndex
) ) {
2560 if ( segExecutable(segIndex
) )
2561 protection
|= PROT_EXEC
;
2562 if ( segReadable(segIndex
) )
2563 protection
|= PROT_READ
;
2564 if ( segWriteable(segIndex
) )
2565 protection
|= PROT_WRITE
;
2567 vm_address_t addr
= segActualLoadAddress(segIndex
);
2568 vm_size_t size
= segSize(segIndex
);
2569 const bool setCurrentPermissions
= false;
2570 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
2571 if ( r
!= KERN_SUCCESS
) {
2572 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2573 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
2575 if ( context
.verboseMapping
) {
2576 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,
2577 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2581 void ImageLoaderMachO::segMakeWritable(unsigned int segIndex
, const ImageLoader::LinkContext
& context
)
2583 vm_address_t addr
= segActualLoadAddress(segIndex
);
2584 vm_size_t size
= segSize(segIndex
);
2585 const bool setCurrentPermissions
= false;
2586 vm_prot_t protection
= VM_PROT_WRITE
| VM_PROT_READ
;
2587 if ( segExecutable(segIndex
) && !segHasRebaseFixUps(segIndex
) )
2588 protection
|= VM_PROT_EXECUTE
;
2589 kern_return_t r
= vm_protect(mach_task_self(), addr
, size
, setCurrentPermissions
, protection
);
2590 if ( r
!= KERN_SUCCESS
) {
2591 dyld::throwf("vm_protect(0x%08llX, 0x%08llX, false, 0x%02X) failed, result=%d for segment %s in %s",
2592 (long long)addr
, (long long)size
, protection
, r
, segName(segIndex
), this->getPath());
2594 if ( context
.verboseMapping
) {
2595 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,
2596 (protection
& PROT_READ
) ? 'r' : '.', (protection
& PROT_WRITE
) ? 'w' : '.', (protection
& PROT_EXEC
) ? 'x' : '.' );
2601 const char* ImageLoaderMachO::findClosestSymbol(const mach_header
* mh
, const void* addr
, const void** closestAddr
)
2603 // called by dladdr()
2604 // only works with compressed LINKEDIT if classic symbol table is also present
2605 const dysymtab_command
* dynSymbolTable
= NULL
;
2606 const symtab_command
* symtab
= NULL
;
2607 const macho_segment_command
* seg
;
2608 const uint8_t* unslidLinkEditBase
= NULL
;
2609 bool linkEditBaseFound
= false;
2611 const uint32_t cmd_count
= mh
->ncmds
;
2612 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
2613 const load_command
* cmd
= cmds
;
2614 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2616 case LC_SEGMENT_COMMAND
:
2617 seg
= (macho_segment_command
*)cmd
;
2618 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 ) {
2619 unslidLinkEditBase
= (uint8_t*)(seg
->vmaddr
- seg
->fileoff
);
2620 linkEditBaseFound
= true;
2622 else if ( strcmp(seg
->segname
, "__TEXT") == 0 ) {
2623 slide
= (uintptr_t)mh
- seg
->vmaddr
;
2627 symtab
= (symtab_command
*)cmd
;
2630 dynSymbolTable
= (dysymtab_command
*)cmd
;
2633 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2635 // no symbol table => no lookup by address
2636 if ( (symtab
== NULL
) || (dynSymbolTable
== NULL
) || !linkEditBaseFound
)
2639 const uint8_t* linkEditBase
= unslidLinkEditBase
+ slide
;
2640 const char* symbolTableStrings
= (const char*)&linkEditBase
[symtab
->stroff
];
2641 const macho_nlist
* symbolTable
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]);
2643 uintptr_t targetAddress
= (uintptr_t)addr
- slide
;
2644 const struct macho_nlist
* bestSymbol
= NULL
;
2645 // first walk all global symbols
2646 const struct macho_nlist
* const globalsStart
= &symbolTable
[dynSymbolTable
->iextdefsym
];
2647 const struct macho_nlist
* const globalsEnd
= &globalsStart
[dynSymbolTable
->nextdefsym
];
2648 for (const struct macho_nlist
* s
= globalsStart
; s
< globalsEnd
; ++s
) {
2649 if ( (s
->n_type
& N_TYPE
) == N_SECT
) {
2650 if ( bestSymbol
== NULL
) {
2651 if ( s
->n_value
<= targetAddress
)
2654 else if ( (s
->n_value
<= targetAddress
) && (bestSymbol
->n_value
< s
->n_value
) ) {
2659 // next walk all local symbols
2660 const struct macho_nlist
* const localsStart
= &symbolTable
[dynSymbolTable
->ilocalsym
];
2661 const struct macho_nlist
* const localsEnd
= &localsStart
[dynSymbolTable
->nlocalsym
];
2662 for (const struct macho_nlist
* s
= localsStart
; s
< localsEnd
; ++s
) {
2663 if ( ((s
->n_type
& N_TYPE
) == N_SECT
) && ((s
->n_type
& N_STAB
) == 0) ) {
2664 if ( bestSymbol
== NULL
) {
2665 if ( s
->n_value
<= targetAddress
)
2668 else if ( (s
->n_value
<= targetAddress
) && (bestSymbol
->n_value
< s
->n_value
) ) {
2673 if ( bestSymbol
!= NULL
) {
2675 if (bestSymbol
->n_desc
& N_ARM_THUMB_DEF
)
2676 *closestAddr
= (void*)((bestSymbol
->n_value
| 1) + slide
);
2678 *closestAddr
= (void*)(bestSymbol
->n_value
+ slide
);
2680 *closestAddr
= (void*)(bestSymbol
->n_value
+ slide
);
2682 return &symbolTableStrings
[bestSymbol
->n_un
.n_strx
];
2687 bool ImageLoaderMachO::getLazyBindingInfo(uint32_t& lazyBindingInfoOffset
, const uint8_t* lazyInfoStart
, const uint8_t* lazyInfoEnd
,
2688 uint8_t* segIndex
, uintptr_t* segOffset
, int* ordinal
, const char** symbolName
, bool* doneAfterBind
)
2690 if ( lazyBindingInfoOffset
> (lazyInfoEnd
-lazyInfoStart
) )
2692 uint8_t type
= BIND_TYPE_POINTER
;
2693 uint8_t symboFlags
= 0;
2695 const uint8_t* p
= &lazyInfoStart
[lazyBindingInfoOffset
];
2696 while ( !done
&& (p
< lazyInfoEnd
) ) {
2697 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
2698 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
2701 case BIND_OPCODE_DONE
:
2702 *doneAfterBind
= false;
2705 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
2706 *ordinal
= immediate
;
2708 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
2709 *ordinal
= (int)read_uleb128(p
, lazyInfoEnd
);
2711 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
2712 // the special ordinals are negative numbers
2713 if ( immediate
== 0 )
2716 int8_t signExtended
= BIND_OPCODE_MASK
| immediate
;
2717 *ordinal
= signExtended
;
2720 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
2721 *symbolName
= (char*)p
;
2722 symboFlags
= immediate
;
2727 case BIND_OPCODE_SET_TYPE_IMM
:
2730 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
2731 *segIndex
= immediate
;
2732 *segOffset
= read_uleb128(p
, lazyInfoEnd
);
2734 case BIND_OPCODE_DO_BIND
:
2735 *doneAfterBind
= ((*p
& BIND_OPCODE_MASK
) == BIND_OPCODE_DONE
);
2736 lazyBindingInfoOffset
+= p
- &lazyInfoStart
[lazyBindingInfoOffset
];
2739 case BIND_OPCODE_SET_ADDEND_SLEB
:
2740 case BIND_OPCODE_ADD_ADDR_ULEB
:
2741 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
2742 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
2743 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
2751 const dyld_info_command
* ImageLoaderMachO::findDyldInfoLoadCommand(const mach_header
* mh
)
2753 const uint32_t cmd_count
= mh
->ncmds
;
2754 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
2755 const load_command
* cmd
= cmds
;
2756 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2759 case LC_DYLD_INFO_ONLY
:
2760 return (dyld_info_command
*)cmd
;
2762 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2768 uintptr_t ImageLoaderMachO::segPreferredAddress(const mach_header
* mh
, unsigned segIndex
)
2770 const uint32_t cmd_count
= mh
->ncmds
;
2771 const load_command
* const cmds
= (load_command
*)((char*)mh
+ sizeof(macho_header
));
2772 const load_command
* cmd
= cmds
;
2773 unsigned curSegIndex
= 0;
2774 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2775 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
2776 if ( segIndex
== curSegIndex
) {
2777 const macho_segment_command
* segCmd
= (macho_segment_command
*)cmd
;
2778 return segCmd
->vmaddr
;
2782 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);