]>
Commit | Line | Data |
---|---|---|
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- | |
2 | * | |
3 | * Copyright (c) 2004-2008 Apple Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
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 | |
12 | * file. | |
13 | * | |
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. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | #define __STDC_LIMIT_MACROS | |
26 | #include <stdint.h> | |
27 | #include <stddef.h> | |
28 | #include <string.h> | |
29 | #include <stdlib.h> | |
30 | #include <sys/mman.h> | |
31 | #include <mach/mach.h> | |
32 | ||
33 | #include "dyld2.h" | |
34 | #include "dyldSyscallInterface.h" | |
35 | #include "MachOAnalyzer.h" | |
36 | #include "Tracing.h" | |
37 | ||
38 | // from libc.a | |
39 | extern "C" void mach_init(); | |
40 | extern "C" void __guard_setup(const char* apple[]); | |
41 | extern "C" void _subsystem_init(const char* apple[]); | |
42 | ||
43 | // from dyld_debugger.cpp | |
44 | extern void syncProcessInfo(); | |
45 | ||
46 | const dyld::SyscallHelpers* gSyscallHelpers = NULL; | |
47 | ||
48 | ||
49 | // | |
50 | // Code to bootstrap dyld into a runnable state | |
51 | // | |
52 | // | |
53 | ||
54 | namespace dyldbootstrap { | |
55 | ||
56 | ||
57 | // currently dyld has no initializers, but if some come back, set this to non-zero | |
58 | #define DYLD_INITIALIZER_SUPPORT 0 | |
59 | ||
60 | ||
61 | #if DYLD_INITIALIZER_SUPPORT | |
62 | ||
63 | typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[]); | |
64 | ||
65 | extern const Initializer inits_start __asm("section$start$__DATA$__mod_init_func"); | |
66 | extern const Initializer inits_end __asm("section$end$__DATA$__mod_init_func"); | |
67 | ||
68 | // | |
69 | // For a regular executable, the crt code calls dyld to run the executables initializers. | |
70 | // For a static executable, crt directly runs the initializers. | |
71 | // dyld (should be static) but is a dynamic executable and needs this hack to run its own initializers. | |
72 | // We pass argc, argv, etc in case libc.a uses those arguments | |
73 | // | |
74 | static void runDyldInitializers(int argc, const char* argv[], const char* envp[], const char* apple[]) | |
75 | { | |
76 | for (const Initializer* p = &inits_start; p < &inits_end; ++p) { | |
77 | (*p)(argc, argv, envp, apple); | |
78 | } | |
79 | } | |
80 | #endif // DYLD_INITIALIZER_SUPPORT | |
81 | ||
82 | ||
83 | // | |
84 | // On disk, all pointers in dyld's DATA segment are chained together. | |
85 | // They need to be fixed up to be real pointers to run. | |
86 | // | |
87 | static void rebaseDyld(const dyld3::MachOLoaded* dyldMH) | |
88 | { | |
89 | // walk all fixups chains and rebase dyld | |
90 | const dyld3::MachOAnalyzer* ma = (dyld3::MachOAnalyzer*)dyldMH; | |
91 | assert(ma->hasChainedFixups()); | |
92 | uintptr_t slide = (long)ma; // all fixup chain based images have a base address of zero, so slide == load address | |
93 | __block Diagnostics diag; | |
94 | ma->withChainStarts(diag, 0, ^(const dyld_chained_starts_in_image* starts) { | |
95 | ma->fixupAllChainedFixups(diag, starts, slide, dyld3::Array<const void*>(), nullptr); | |
96 | }); | |
97 | diag.assertNoError(); | |
98 | ||
99 | // now that rebasing done, initialize mach/syscall layer | |
100 | mach_init(); | |
101 | ||
102 | // <rdar://47805386> mark __DATA_CONST segment in dyld as read-only (once fixups are done) | |
103 | ma->forEachSegment(^(const dyld3::MachOFile::SegmentInfo& info, bool& stop) { | |
104 | if ( info.readOnlyData ) { | |
105 | ::mprotect(((uint8_t*)(dyldMH))+info.vmAddr, (size_t)info.vmSize, VM_PROT_READ); | |
106 | } | |
107 | }); | |
108 | } | |
109 | ||
110 | ||
111 | ||
112 | // | |
113 | // This is code to bootstrap dyld. This work in normally done for a program by dyld and crt. | |
114 | // In dyld we have to do this manually. | |
115 | // | |
116 | uintptr_t start(const dyld3::MachOLoaded* appsMachHeader, int argc, const char* argv[], | |
117 | const dyld3::MachOLoaded* dyldsMachHeader, uintptr_t* startGlue) | |
118 | { | |
119 | ||
120 | // Emit kdebug tracepoint to indicate dyld bootstrap has started <rdar://46878536> | |
121 | dyld3::kdebug_trace_dyld_marker(DBG_DYLD_TIMING_BOOTSTRAP_START, 0, 0, 0, 0); | |
122 | ||
123 | // if kernel had to slide dyld, we need to fix up load sensitive locations | |
124 | // we have to do this before using any global variables | |
125 | rebaseDyld(dyldsMachHeader); | |
126 | ||
127 | // kernel sets up env pointer to be just past end of agv array | |
128 | const char** envp = &argv[argc+1]; | |
129 | ||
130 | // kernel sets up apple pointer to be just past end of envp array | |
131 | const char** apple = envp; | |
132 | while(*apple != NULL) { ++apple; } | |
133 | ++apple; | |
134 | ||
135 | // set up random value for stack canary | |
136 | __guard_setup(apple); | |
137 | ||
138 | #if DYLD_INITIALIZER_SUPPORT | |
139 | // run all C++ initializers inside dyld | |
140 | runDyldInitializers(argc, argv, envp, apple); | |
141 | #endif | |
142 | ||
143 | _subsystem_init(apple); | |
144 | ||
145 | // now that we are done bootstrapping dyld, call dyld's main | |
146 | uintptr_t appsSlide = appsMachHeader->getSlide(); | |
147 | return dyld::_main((macho_header*)appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue); | |
148 | } | |
149 | ||
150 | ||
151 | #if TARGET_OS_SIMULATOR | |
152 | ||
153 | extern "C" uintptr_t start_sim(int argc, const char* argv[], const char* envp[], const char* apple[], | |
154 | const dyld3::MachOLoaded* mainExecutableMH, const dyld3::MachOLoaded* dyldMH, uintptr_t dyldSlide, | |
155 | const dyld::SyscallHelpers*, uintptr_t* startGlue); | |
156 | ||
157 | ||
158 | uintptr_t start_sim(int argc, const char* argv[], const char* envp[], const char* apple[], | |
159 | const dyld3::MachOLoaded* mainExecutableMH, const dyld3::MachOLoaded* dyldSimMH, uintptr_t dyldSlide, | |
160 | const dyld::SyscallHelpers* sc, uintptr_t* startGlue) | |
161 | { | |
162 | // save table of syscall pointers | |
163 | gSyscallHelpers = sc; | |
164 | ||
165 | // dyld_sim uses chained rebases, so it always need to be fixed up | |
166 | rebaseDyld(dyldSimMH); | |
167 | ||
168 | // set up random value for stack canary | |
169 | __guard_setup(apple); | |
170 | ||
171 | // setup gProcessInfo to point to host dyld's struct | |
172 | dyld::gProcessInfo = (struct dyld_all_image_infos*)(sc->getProcessInfo()); | |
173 | syncProcessInfo(); | |
174 | ||
175 | // now that we are done bootstrapping dyld, call dyld's main | |
176 | uintptr_t appsSlide = mainExecutableMH->getSlide(); | |
177 | return dyld::_main((macho_header*)mainExecutableMH, appsSlide, argc, argv, envp, apple, startGlue); | |
178 | } | |
179 | #endif | |
180 | ||
181 | ||
182 | } // end of namespace | |
183 | ||
184 | ||
185 | ||
186 |