]>
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 <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> | |
35 | #if __x86_64__ | |
36 | #include <mach-o/x86_64/reloc.h> | |
37 | #endif | |
38 | #include "dyld.h" | |
39 | #include "dyldSyscallInterface.h" | |
40 | ||
41 | // from dyld_gdb.cpp | |
42 | extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]); | |
43 | extern void syncProcessInfo(); | |
44 | ||
45 | #ifndef MH_PIE | |
46 | #define MH_PIE 0x200000 | |
47 | #endif | |
48 | ||
49 | // currently dyld has no initializers, but if some come back, set this to non-zero | |
50 | #define DYLD_INITIALIZER_SUPPORT 0 | |
51 | ||
52 | #if __LP64__ | |
53 | #define LC_SEGMENT_COMMAND LC_SEGMENT_64 | |
54 | #define macho_segment_command segment_command_64 | |
55 | #define macho_section section_64 | |
56 | #define RELOC_SIZE 3 | |
57 | #else | |
58 | #define LC_SEGMENT_COMMAND LC_SEGMENT | |
59 | #define macho_segment_command segment_command | |
60 | #define macho_section section | |
61 | #define RELOC_SIZE 2 | |
62 | #endif | |
63 | ||
64 | #if __x86_64__ | |
65 | #define POINTER_RELOC X86_64_RELOC_UNSIGNED | |
66 | #else | |
67 | #define POINTER_RELOC GENERIC_RELOC_VANILLA | |
68 | #endif | |
69 | ||
70 | ||
71 | #if TARGET_IPHONE_SIMULATOR | |
72 | const dyld::SyscallHelpers* gSyscallHelpers = NULL; | |
73 | #endif | |
74 | ||
75 | ||
76 | // | |
77 | // Code to bootstrap dyld into a runnable state | |
78 | // | |
79 | // | |
80 | ||
81 | namespace dyldbootstrap { | |
82 | ||
83 | ||
84 | ||
85 | #if DYLD_INITIALIZER_SUPPORT | |
86 | ||
87 | typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[]); | |
88 | ||
89 | extern const Initializer inits_start __asm("section$start$__DATA$__mod_init_func"); | |
90 | extern const Initializer inits_end __asm("section$end$__DATA$__mod_init_func"); | |
91 | ||
92 | // | |
93 | // For a regular executable, the crt code calls dyld to run the executables initializers. | |
94 | // For a static executable, crt directly runs the initializers. | |
95 | // dyld (should be static) but is a dynamic executable and needs this hack to run its own initializers. | |
96 | // We pass argc, argv, etc in case libc.a uses those arguments | |
97 | // | |
98 | static void runDyldInitializers(const struct macho_header* mh, intptr_t slide, int argc, const char* argv[], const char* envp[], const char* apple[]) | |
99 | { | |
100 | for (const Initializer* p = &inits_start; p < &inits_end; ++p) { | |
101 | (*p)(argc, argv, envp, apple); | |
102 | } | |
103 | } | |
104 | #endif // DYLD_INITIALIZER_SUPPORT | |
105 | ||
106 | ||
107 | // | |
108 | // The kernel may have slid a Position Independent Executable | |
109 | // | |
110 | static uintptr_t slideOfMainExecutable(const struct macho_header* mh) | |
111 | { | |
112 | const uint32_t cmd_count = mh->ncmds; | |
113 | const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); | |
114 | const struct load_command* cmd = cmds; | |
115 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
116 | if ( cmd->cmd == LC_SEGMENT_COMMAND ) { | |
117 | const struct macho_segment_command* segCmd = (struct macho_segment_command*)cmd; | |
118 | if ( (segCmd->fileoff == 0) && (segCmd->filesize != 0)) { | |
119 | return (uintptr_t)mh - segCmd->vmaddr; | |
120 | } | |
121 | } | |
122 | cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); | |
123 | } | |
124 | return 0; | |
125 | } | |
126 | ||
127 | ||
128 | // | |
129 | // If the kernel does not load dyld at its preferred address, we need to apply | |
130 | // fixups to various initialized parts of the __DATA segment | |
131 | // | |
132 | static void rebaseDyld(const struct macho_header* mh, intptr_t slide) | |
133 | { | |
134 | // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries) | |
135 | // and get interesting pointers into dyld | |
136 | const uint32_t cmd_count = mh->ncmds; | |
137 | const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); | |
138 | const struct load_command* cmd = cmds; | |
139 | const struct macho_segment_command* linkEditSeg = NULL; | |
140 | #if __x86_64__ | |
141 | const struct macho_segment_command* firstWritableSeg = NULL; | |
142 | #endif | |
143 | const struct dysymtab_command* dynamicSymbolTable = NULL; | |
144 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
145 | switch (cmd->cmd) { | |
146 | case LC_SEGMENT_COMMAND: | |
147 | { | |
148 | const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; | |
149 | if ( strcmp(seg->segname, "__LINKEDIT") == 0 ) | |
150 | linkEditSeg = seg; | |
151 | const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); | |
152 | const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; | |
153 | for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { | |
154 | const uint8_t type = sect->flags & SECTION_TYPE; | |
155 | if ( type == S_NON_LAZY_SYMBOL_POINTERS ) { | |
156 | // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries) | |
157 | const uint32_t pointerCount = (uint32_t)(sect->size / sizeof(uintptr_t)); | |
158 | uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + slide); | |
159 | for (uint32_t j=0; j < pointerCount; ++j) { | |
160 | symbolPointers[j] += slide; | |
161 | } | |
162 | } | |
163 | } | |
164 | #if __x86_64__ | |
165 | if ( (firstWritableSeg == NULL) && (seg->initprot & VM_PROT_WRITE) ) | |
166 | firstWritableSeg = seg; | |
167 | #endif | |
168 | } | |
169 | break; | |
170 | case LC_DYSYMTAB: | |
171 | dynamicSymbolTable = (struct dysymtab_command *)cmd; | |
172 | break; | |
173 | } | |
174 | cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); | |
175 | } | |
176 | ||
177 | // use reloc's to rebase all random data pointers | |
178 | #if __x86_64__ | |
179 | const uintptr_t relocBase = firstWritableSeg->vmaddr + slide; | |
180 | #else | |
181 | const uintptr_t relocBase = (uintptr_t)mh; | |
182 | #endif | |
183 | const relocation_info* const relocsStart = (struct relocation_info*)(linkEditSeg->vmaddr + slide + dynamicSymbolTable->locreloff - linkEditSeg->fileoff); | |
184 | const relocation_info* const relocsEnd = &relocsStart[dynamicSymbolTable->nlocrel]; | |
185 | for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { | |
186 | if ( reloc->r_length != RELOC_SIZE ) | |
187 | throw "relocation in dyld has wrong size"; | |
188 | ||
189 | if ( reloc->r_type != POINTER_RELOC ) | |
190 | throw "relocation in dyld has wrong type"; | |
191 | ||
192 | // update pointer by amount dyld slid | |
193 | *((uintptr_t*)(reloc->r_address + relocBase)) += slide; | |
194 | } | |
195 | } | |
196 | ||
197 | ||
198 | extern "C" void mach_init(); | |
199 | extern "C" void __guard_setup(const char* apple[]); | |
200 | ||
201 | ||
202 | // | |
203 | // This is code to bootstrap dyld. This work in normally done for a program by dyld and crt. | |
204 | // In dyld we have to do this manually. | |
205 | // | |
206 | uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char* argv[], | |
207 | intptr_t slide, const struct macho_header* dyldsMachHeader, | |
208 | uintptr_t* startGlue) | |
209 | { | |
210 | // if kernel had to slide dyld, we need to fix up load sensitive locations | |
211 | // we have to do this before using any global variables | |
212 | if ( slide != 0 ) { | |
213 | rebaseDyld(dyldsMachHeader, slide); | |
214 | } | |
215 | ||
216 | // allow dyld to use mach messaging | |
217 | mach_init(); | |
218 | ||
219 | // kernel sets up env pointer to be just past end of agv array | |
220 | const char** envp = &argv[argc+1]; | |
221 | ||
222 | // kernel sets up apple pointer to be just past end of envp array | |
223 | const char** apple = envp; | |
224 | while(*apple != NULL) { ++apple; } | |
225 | ++apple; | |
226 | ||
227 | // set up random value for stack canary | |
228 | __guard_setup(apple); | |
229 | ||
230 | #if DYLD_INITIALIZER_SUPPORT | |
231 | // run all C++ initializers inside dyld | |
232 | runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple); | |
233 | #endif | |
234 | ||
235 | // now that we are done bootstrapping dyld, call dyld's main | |
236 | uintptr_t appsSlide = slideOfMainExecutable(appsMachHeader); | |
237 | return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue); | |
238 | } | |
239 | ||
240 | ||
241 | #if TARGET_IPHONE_SIMULATOR | |
242 | ||
243 | extern "C" uintptr_t start_sim(int argc, const char* argv[], const char* envp[], const char* apple[], | |
244 | const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide, | |
245 | const dyld::SyscallHelpers*, uintptr_t* startGlue); | |
246 | ||
247 | ||
248 | uintptr_t start_sim(int argc, const char* argv[], const char* envp[], const char* apple[], | |
249 | const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide, | |
250 | const dyld::SyscallHelpers* sc, uintptr_t* startGlue) | |
251 | { | |
252 | // if simulator dyld loaded slid, it needs to rebase itself | |
253 | // we have to do this before using any global variables | |
254 | if ( dyldSlide != 0 ) { | |
255 | rebaseDyld(dyldMH, dyldSlide); | |
256 | } | |
257 | ||
258 | // save table of syscall pointers | |
259 | gSyscallHelpers = sc; | |
260 | ||
261 | // allow dyld to use mach messaging | |
262 | mach_init(); | |
263 | ||
264 | // set up random value for stack canary | |
265 | __guard_setup(apple); | |
266 | ||
267 | // setup gProcessInfo to point to host dyld's struct | |
268 | dyld::gProcessInfo = (struct dyld_all_image_infos*)(sc->getProcessInfo()); | |
269 | syncProcessInfo(); | |
270 | ||
271 | // now that we are done bootstrapping dyld, call dyld's main | |
272 | uintptr_t appsSlide = slideOfMainExecutable(mainExecutableMH); | |
273 | return dyld::_main(mainExecutableMH, appsSlide, argc, argv, envp, apple, startGlue); | |
274 | } | |
275 | #endif | |
276 | ||
277 | ||
278 | } // end of namespace | |
279 | ||
280 | ||
281 | ||
282 |