1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2008 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 #define __STDC_LIMIT_MACROS
30 #include <Availability.h>
31 #include <mach/mach.h>
32 #include <mach-o/loader.h>
33 #include <mach-o/ldsyms.h>
34 #include <mach-o/reloc.h>
36 #include <mach-o/x86_64/reloc.h>
39 #include "dyldSyscallInterface.h"
42 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]);
43 extern void syncProcessInfo();
46 #define MH_PIE 0x200000
49 // currently dyld has no initializers, but if some come back, set this to non-zero
50 #define DYLD_INITIALIZER_SUPPORT 0
53 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
54 #define macho_segment_command segment_command_64
55 #define macho_section section_64
58 #define LC_SEGMENT_COMMAND LC_SEGMENT
59 #define macho_segment_command segment_command
60 #define macho_section section
65 #define POINTER_RELOC X86_64_RELOC_UNSIGNED
67 #define POINTER_RELOC GENERIC_RELOC_VANILLA
70 #ifndef BIND_OPCODE_THREADED
71 #define BIND_OPCODE_THREADED 0xD0
74 #ifndef BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
75 #define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00
78 #ifndef BIND_SUBOPCODE_THREADED_APPLY
79 #define BIND_SUBOPCODE_THREADED_APPLY 0x01
83 #if __has_feature(ptrauth_calls)
88 #if TARGET_IPHONE_SIMULATOR
89 const dyld::SyscallHelpers
* gSyscallHelpers
= NULL
;
94 // Code to bootstrap dyld into a runnable state
98 namespace dyldbootstrap
{
102 #if DYLD_INITIALIZER_SUPPORT
104 typedef void (*Initializer
)(int argc
, const char* argv
[], const char* envp
[], const char* apple
[]);
106 extern const Initializer inits_start
__asm("section$start$__DATA$__mod_init_func");
107 extern const Initializer inits_end
__asm("section$end$__DATA$__mod_init_func");
110 // For a regular executable, the crt code calls dyld to run the executables initializers.
111 // For a static executable, crt directly runs the initializers.
112 // dyld (should be static) but is a dynamic executable and needs this hack to run its own initializers.
113 // We pass argc, argv, etc in case libc.a uses those arguments
115 static void runDyldInitializers(const struct macho_header
* mh
, intptr_t slide
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[])
117 for (const Initializer
* p
= &inits_start
; p
< &inits_end
; ++p
) {
118 (*p
)(argc
, argv
, envp
, apple
);
121 #endif // DYLD_INITIALIZER_SUPPORT
125 // The kernel may have slid a Position Independent Executable
127 static uintptr_t slideOfMainExecutable(const struct macho_header
* mh
)
129 const uint32_t cmd_count
= mh
->ncmds
;
130 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
131 const struct load_command
* cmd
= cmds
;
132 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
133 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
134 const struct macho_segment_command
* segCmd
= (struct macho_segment_command
*)cmd
;
135 if ( (segCmd
->fileoff
== 0) && (segCmd
->filesize
!= 0)) {
136 return (uintptr_t)mh
- segCmd
->vmaddr
;
139 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
144 inline uint64_t read_uleb128(const uint8_t*& p
, const uint8_t* end
) {
149 throw "malformed uleb128 extends beyond trie";
150 uint64_t slice
= *p
& 0x7f;
152 if (bit
>= 64 || slice
<< bit
>> bit
!= slice
)
153 throw "uleb128 too big for 64-bits";
155 result
|= (slice
<< bit
);
163 inline int64_t read_sleb128(const uint8_t*& p
, const uint8_t* end
)
170 throw "malformed sleb128";
172 result
|= (((int64_t)(byte
& 0x7f)) << bit
);
174 } while (byte
& 0x80);
175 // sign extend negative numbers
176 if ( (byte
& 0x40) != 0 )
177 result
|= (~0ULL) << bit
;
183 // If the kernel does not load dyld at its preferred address, we need to apply
184 // fixups to various initialized parts of the __DATA segment
186 static void rebaseDyld(const struct macho_header
* mh
, intptr_t slide
)
188 // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries)
189 // and get interesting pointers into dyld
190 const uint32_t cmd_count
= mh
->ncmds
;
191 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
192 const struct load_command
* cmd
= cmds
;
194 // First look for compressed info and use it if it exists.
195 const struct macho_segment_command
* linkEditSeg
= NULL
;
196 const dyld_info_command
* dyldInfoCmd
= NULL
;
197 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
199 case LC_SEGMENT_COMMAND
:
201 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
202 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 )
206 case LC_DYLD_INFO_ONLY
:
207 dyldInfoCmd
= (struct dyld_info_command
*)cmd
;
210 if (dyldInfoCmd
&& linkEditSeg
)
212 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
214 if ( linkEditSeg
== NULL
)
215 throw "dyld missing LINKEDIT";
217 // Reset the iterator.
220 auto getSegmentAtIndex
= [cmd_count
, cmds
](unsigned segIndex
) -> const struct macho_segment_command
* {
221 const struct load_command
* cmd
= cmds
;
222 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
224 case LC_SEGMENT_COMMAND
:
226 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
232 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
234 throw "out of bounds command";
238 auto segActualLoadAddress
= [&](unsigned segIndex
) -> uintptr_t {
239 const struct macho_segment_command
* seg
= getSegmentAtIndex(segIndex
);
240 return seg
->vmaddr
+ slide
;
243 #if __has_feature(ptrauth_calls)
244 auto imageBaseAddress
= [cmds
, cmd_count
]() -> uintptr_t {
245 const struct load_command
* cmd
= cmds
;
246 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
248 case LC_SEGMENT_COMMAND
: {
249 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
250 if ( (seg
->fileoff
== 0) && (seg
->filesize
!= 0) )
255 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
261 if (dyldInfoCmd
&& (dyldInfoCmd
->bind_size
!= 0) ) {
262 if ( dyldInfoCmd
->rebase_size
!= 0 )
263 throw "unthreaded rebases are not supported";
265 const uint8_t* linkEditBase
= (uint8_t*)(linkEditSeg
->vmaddr
+ slide
- linkEditSeg
->fileoff
);
267 const uint8_t* const start
= linkEditBase
+ dyldInfoCmd
->bind_off
;
268 const uint8_t* const end
= &start
[dyldInfoCmd
->bind_size
];
269 const uint8_t* p
= start
;
271 uintptr_t segmentStartAddress
= 0;
272 uint64_t segOffset
= 0;
274 #if __has_feature(ptrauth_calls)
275 uintptr_t fBaseAddress
= imageBaseAddress();
279 while ( !done
&& (p
< end
) ) {
280 uint8_t immediate
= *p
& BIND_IMMEDIATE_MASK
;
281 uint8_t opcode
= *p
& BIND_OPCODE_MASK
;
284 case BIND_OPCODE_DONE
:
287 case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
:
289 case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
291 case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM
:
293 case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
298 case BIND_OPCODE_SET_TYPE_IMM
:
300 case BIND_OPCODE_SET_ADDEND_SLEB
:
301 read_sleb128(p
, end
);
303 case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
304 segIndex
= immediate
;
305 segmentStartAddress
= segActualLoadAddress(segIndex
);
306 segOffset
= read_uleb128(p
, end
);
308 case BIND_OPCODE_ADD_ADDR_ULEB
:
309 segOffset
+= read_uleb128(p
, end
);
311 case BIND_OPCODE_DO_BIND
:
313 case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
315 case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED
:
317 case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
318 read_uleb128(p
, end
);
319 read_uleb128(p
, end
);
321 case BIND_OPCODE_THREADED
:
322 // Note the immediate is a sub opcode
324 case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
:
325 read_uleb128(p
, end
);
327 case BIND_SUBOPCODE_THREADED_APPLY
: {
330 uintptr_t address
= segmentStartAddress
+ (uintptr_t)segOffset
;
331 uint64_t value
= *(uint64_t*)address
;
333 #if __has_feature(ptrauth_calls)
334 uint16_t diversity
= (uint16_t)(value
>> 32);
335 bool hasAddressDiversity
= (value
& (1ULL << 48)) != 0;
336 ptrauth_key key
= (ptrauth_key
)((value
>> 49) & 0x3);
337 bool isAuthenticated
= (value
& (1ULL << 63)) != 0;
339 bool isRebase
= (value
& (1ULL << 62)) == 0;
342 #if __has_feature(ptrauth_calls)
343 if (isAuthenticated
) {
344 // The new value for a rebase is the low 32-bits of the threaded value plus the slide.
345 uint64_t newValue
= (value
& 0xFFFFFFFF) + slide
;
346 // Add in the offset from the mach_header
347 newValue
+= fBaseAddress
;
348 // We have bits to merge in to the discriminator
349 uintptr_t discriminator
= diversity
;
350 if (hasAddressDiversity
) {
351 // First calculate a new discriminator using the address of where we are trying to store the value
352 discriminator
= __builtin_ptrauth_blend_discriminator((void*)address
, discriminator
);
355 case ptrauth_key_asia
:
356 newValue
= (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)newValue
, ptrauth_key_asia
, discriminator
);
358 case ptrauth_key_asib
:
359 newValue
= (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)newValue
, ptrauth_key_asib
, discriminator
);
361 case ptrauth_key_asda
:
362 newValue
= (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)newValue
, ptrauth_key_asda
, discriminator
);
364 case ptrauth_key_asdb
:
365 newValue
= (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)newValue
, ptrauth_key_asdb
, discriminator
);
368 *(uint64_t*)address
= newValue
;
372 // Regular pointer which needs to fit in 51-bits of value.
373 // C++ RTTI uses the top bit, so we'll allow the whole top-byte
374 // and the signed-extended bottom 43-bits to be fit in to 51-bits.
375 uint64_t top8Bits
= value
& 0x0007F80000000000ULL
;
376 uint64_t bottom43Bits
= value
& 0x000007FFFFFFFFFFULL
;
377 uint64_t targetValue
= ( top8Bits
<< 13 ) | (((intptr_t)(bottom43Bits
<< 21) >> 21) & 0x00FFFFFFFFFFFFFF);
378 targetValue
= targetValue
+ slide
;
379 *(uint64_t*)address
= targetValue
;
383 // The delta is bits [51..61]
384 // And bit 62 is to tell us if we are a rebase (0) or bind (1)
385 value
&= ~(1ULL << 62);
386 delta
= ( value
& 0x3FF8000000000000 ) >> 51;
387 segOffset
+= delta
* sizeof(uintptr_t);
388 } while ( delta
!= 0 );
392 throw "unknown threaded bind subopcode";
396 throw "unknown bind opcode";
403 const struct macho_segment_command
* firstWritableSeg
= NULL
;
405 const struct dysymtab_command
* dynamicSymbolTable
= NULL
;
406 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
408 case LC_SEGMENT_COMMAND
:
410 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
411 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
412 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
413 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
414 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
415 if ( type
== S_NON_LAZY_SYMBOL_POINTERS
) {
416 // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries)
417 const uint32_t pointerCount
= (uint32_t)(sect
->size
/ sizeof(uintptr_t));
418 uintptr_t* const symbolPointers
= (uintptr_t*)(sect
->addr
+ slide
);
419 for (uint32_t j
=0; j
< pointerCount
; ++j
) {
420 symbolPointers
[j
] += slide
;
425 if ( (firstWritableSeg
== NULL
) && (seg
->initprot
& VM_PROT_WRITE
) )
426 firstWritableSeg
= seg
;
431 dynamicSymbolTable
= (struct dysymtab_command
*)cmd
;
434 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
437 // use reloc's to rebase all random data pointers
439 if ( firstWritableSeg
== NULL
)
440 throw "no writable segment in dyld";
441 const uintptr_t relocBase
= firstWritableSeg
->vmaddr
+ slide
;
443 const uintptr_t relocBase
= (uintptr_t)mh
;
445 const relocation_info
* const relocsStart
= (struct relocation_info
*)(linkEditSeg
->vmaddr
+ slide
+ dynamicSymbolTable
->locreloff
- linkEditSeg
->fileoff
);
446 const relocation_info
* const relocsEnd
= &relocsStart
[dynamicSymbolTable
->nlocrel
];
447 for (const relocation_info
* reloc
=relocsStart
; reloc
< relocsEnd
; ++reloc
) {
448 if ( reloc
->r_length
!= RELOC_SIZE
)
449 throw "relocation in dyld has wrong size";
451 if ( reloc
->r_type
!= POINTER_RELOC
)
452 throw "relocation in dyld has wrong type";
454 // update pointer by amount dyld slid
455 *((uintptr_t*)(reloc
->r_address
+ relocBase
)) += slide
;
460 extern "C" void mach_init();
461 extern "C" void __guard_setup(const char* apple
[]);
465 // This is code to bootstrap dyld. This work in normally done for a program by dyld and crt.
466 // In dyld we have to do this manually.
468 uintptr_t start(const struct macho_header
* appsMachHeader
, int argc
, const char* argv
[],
469 intptr_t slide
, const struct macho_header
* dyldsMachHeader
,
470 uintptr_t* startGlue
)
472 // if kernel had to slide dyld, we need to fix up load sensitive locations
473 // we have to do this before using any global variables
474 slide
= slideOfMainExecutable(dyldsMachHeader
);
475 bool shouldRebase
= slide
!= 0;
476 #if __has_feature(ptrauth_calls)
479 if ( shouldRebase
) {
480 rebaseDyld(dyldsMachHeader
, slide
);
483 // allow dyld to use mach messaging
486 // kernel sets up env pointer to be just past end of agv array
487 const char** envp
= &argv
[argc
+1];
489 // kernel sets up apple pointer to be just past end of envp array
490 const char** apple
= envp
;
491 while(*apple
!= NULL
) { ++apple
; }
494 // set up random value for stack canary
495 __guard_setup(apple
);
497 #if DYLD_INITIALIZER_SUPPORT
498 // run all C++ initializers inside dyld
499 runDyldInitializers(dyldsMachHeader
, slide
, argc
, argv
, envp
, apple
);
502 // now that we are done bootstrapping dyld, call dyld's main
503 uintptr_t appsSlide
= slideOfMainExecutable(appsMachHeader
);
504 return dyld::_main(appsMachHeader
, appsSlide
, argc
, argv
, envp
, apple
, startGlue
);
508 #if TARGET_IPHONE_SIMULATOR
510 extern "C" uintptr_t start_sim(int argc
, const char* argv
[], const char* envp
[], const char* apple
[],
511 const macho_header
* mainExecutableMH
, const macho_header
* dyldMH
, uintptr_t dyldSlide
,
512 const dyld::SyscallHelpers
*, uintptr_t* startGlue
);
515 uintptr_t start_sim(int argc
, const char* argv
[], const char* envp
[], const char* apple
[],
516 const macho_header
* mainExecutableMH
, const macho_header
* dyldMH
, uintptr_t dyldSlide
,
517 const dyld::SyscallHelpers
* sc
, uintptr_t* startGlue
)
519 // if simulator dyld loaded slid, it needs to rebase itself
520 // we have to do this before using any global variables
521 if ( dyldSlide
!= 0 ) {
522 rebaseDyld(dyldMH
, dyldSlide
);
525 // save table of syscall pointers
526 gSyscallHelpers
= sc
;
528 // allow dyld to use mach messaging
531 // set up random value for stack canary
532 __guard_setup(apple
);
534 // setup gProcessInfo to point to host dyld's struct
535 dyld::gProcessInfo
= (struct dyld_all_image_infos
*)(sc
->getProcessInfo());
538 // now that we are done bootstrapping dyld, call dyld's main
539 uintptr_t appsSlide
= slideOfMainExecutable(mainExecutableMH
);
540 return dyld::_main(mainExecutableMH
, appsSlide
, argc
, argv
, envp
, apple
, startGlue
);
545 } // end of namespace