]>
Commit | Line | Data |
---|---|---|
0959b6d4 A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
39a8cd10 | 3 | * Copyright (c) 2004-2008 Apple Inc. All rights reserved. |
0959b6d4 A |
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 | ||
bac542e6 A |
25 | #define __STDC_LIMIT_MACROS |
26 | #include <stdint.h> | |
0959b6d4 A |
27 | #include <stddef.h> |
28 | #include <string.h> | |
bac542e6 | 29 | #include <stdlib.h> |
2fd3f4e8 | 30 | #include <Availability.h> |
0959b6d4 A |
31 | #include <mach/mach.h> |
32 | #include <mach-o/loader.h> | |
33 | #include <mach-o/ldsyms.h> | |
34 | #include <mach-o/reloc.h> | |
8bc9f0af A |
35 | #if __x86_64__ |
36 | #include <mach-o/x86_64/reloc.h> | |
37 | #endif | |
0959b6d4 | 38 | #include "dyld.h" |
2fd3f4e8 A |
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(); | |
0959b6d4 | 44 | |
bac542e6 A |
45 | #ifndef MH_PIE |
46 | #define MH_PIE 0x200000 | |
47 | #endif | |
48 | ||
2fd3f4e8 A |
49 | // currently dyld has no initializers, but if some come back, set this to non-zero |
50 | #define DYLD_INITIALIZER_SUPPORT 0 | |
bac542e6 | 51 | |
0959b6d4 | 52 | #if __LP64__ |
0959b6d4 A |
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 | |
0959b6d4 A |
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 | ||
8bc9f0af A |
64 | #if __x86_64__ |
65 | #define POINTER_RELOC X86_64_RELOC_UNSIGNED | |
66 | #else | |
3d7c199a | 67 | #define POINTER_RELOC GENERIC_RELOC_VANILLA |
8bc9f0af | 68 | #endif |
0959b6d4 | 69 | |
2fd3f4e8 A |
70 | |
71 | #if TARGET_IPHONE_SIMULATOR | |
72 | const dyld::SyscallHelpers* gSyscallHelpers = NULL; | |
73 | #endif | |
bac542e6 A |
74 | |
75 | ||
0959b6d4 A |
76 | // |
77 | // Code to bootstrap dyld into a runnable state | |
78 | // | |
79 | // | |
80 | ||
81 | namespace dyldbootstrap { | |
82 | ||
83 | ||
2fd3f4e8 A |
84 | |
85 | #if DYLD_INITIALIZER_SUPPORT | |
86 | ||
0959b6d4 A |
87 | typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[]); |
88 | ||
2fd3f4e8 A |
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 | ||
0959b6d4 A |
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 | { | |
2fd3f4e8 A |
100 | for (const Initializer* p = &inits_start; p < &inits_end; ++p) { |
101 | (*p)(argc, argv, envp, apple); | |
0959b6d4 A |
102 | } |
103 | } | |
2fd3f4e8 | 104 | #endif // DYLD_INITIALIZER_SUPPORT |
0959b6d4 | 105 | |
412ebb8e A |
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 ( strcmp(segCmd->segname, "__TEXT") == 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 | ||
0959b6d4 A |
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 | { | |
3d7c199a A |
134 | // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries) |
135 | // and get interesting pointers into dyld | |
0959b6d4 A |
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; | |
8bc9f0af A |
140 | #if __x86_64__ |
141 | const struct macho_segment_command* firstWritableSeg = NULL; | |
142 | #endif | |
0959b6d4 | 143 | const struct dysymtab_command* dynamicSymbolTable = NULL; |
0959b6d4 A |
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; | |
3d7c199a A |
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) | |
19894a12 | 157 | const uint32_t pointerCount = (uint32_t)(sect->size / sizeof(uintptr_t)); |
3d7c199a A |
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 | } | |
0959b6d4 | 163 | } |
8bc9f0af A |
164 | #if __x86_64__ |
165 | if ( (firstWritableSeg == NULL) && (seg->initprot & VM_PROT_WRITE) ) | |
166 | firstWritableSeg = seg; | |
167 | #endif | |
0959b6d4 A |
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 | |
8bc9f0af A |
178 | #if __x86_64__ |
179 | const uintptr_t relocBase = firstWritableSeg->vmaddr + slide; | |
180 | #else | |
0959b6d4 | 181 | const uintptr_t relocBase = (uintptr_t)mh; |
8bc9f0af | 182 | #endif |
0959b6d4 A |
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) { | |
3d7c199a A |
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; | |
0959b6d4 | 194 | } |
0959b6d4 A |
195 | } |
196 | ||
3d7c199a | 197 | |
0959b6d4 | 198 | extern "C" void mach_init(); |
2fd3f4e8 | 199 | extern "C" void __guard_setup(const char* apple[]); |
bac542e6 A |
200 | |
201 | ||
0959b6d4 A |
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 | // | |
412ebb8e | 206 | uintptr_t start(const struct macho_header* appsMachHeader, int argc, const char* argv[], |
832b6fce A |
207 | intptr_t slide, const struct macho_header* dyldsMachHeader, |
208 | uintptr_t* startGlue) | |
0959b6d4 | 209 | { |
0959b6d4 A |
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 | } | |
412ebb8e | 215 | |
0959b6d4 A |
216 | // allow dyld to use mach messaging |
217 | mach_init(); | |
218 | ||
0959b6d4 A |
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 | ||
2fd3f4e8 A |
227 | // set up random value for stack canary |
228 | __guard_setup(apple); | |
229 | ||
230 | #if DYLD_INITIALIZER_SUPPORT | |
0959b6d4 A |
231 | // run all C++ initializers inside dyld |
232 | runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple); | |
2fd3f4e8 A |
233 | #endif |
234 | ||
0959b6d4 | 235 | // now that we are done bootstrapping dyld, call dyld's main |
412ebb8e | 236 | uintptr_t appsSlide = slideOfMainExecutable(appsMachHeader); |
832b6fce | 237 | return dyld::_main(appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue); |
0959b6d4 A |
238 | } |
239 | ||
240 | ||
2fd3f4e8 A |
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 | |
0959b6d4 A |
276 | |
277 | ||
278 | } // end of namespace | |
279 | ||
280 | ||
281 | ||
282 |