]>
Commit | Line | Data |
---|---|---|
0959b6d4 A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2004-2005 Apple Computer, 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 | #include <stddef.h> | |
26 | #include <string.h> | |
27 | #include <mach/mach.h> | |
28 | #include <mach-o/loader.h> | |
29 | #include <mach-o/ldsyms.h> | |
30 | #include <mach-o/reloc.h> | |
31 | #if __ppc__ || __ppc64__ | |
32 | #include <mach-o/ppc/reloc.h> | |
33 | #endif | |
34 | #include "dyld.h" | |
35 | ||
36 | #if __LP64__ | |
37 | #define macho_header mach_header_64 | |
38 | #define LC_SEGMENT_COMMAND LC_SEGMENT_64 | |
39 | #define macho_segment_command segment_command_64 | |
40 | #define macho_section section_64 | |
41 | #define RELOC_SIZE 3 | |
42 | #else | |
43 | #define macho_header mach_header | |
44 | #define LC_SEGMENT_COMMAND LC_SEGMENT | |
45 | #define macho_segment_command segment_command | |
46 | #define macho_section section | |
47 | #define RELOC_SIZE 2 | |
48 | #endif | |
49 | ||
50 | ||
51 | // | |
52 | // Code to bootstrap dyld into a runnable state | |
53 | // | |
54 | // | |
55 | ||
56 | namespace dyldbootstrap { | |
57 | ||
58 | ||
59 | typedef void (*Initializer)(int argc, const char* argv[], const char* envp[], const char* apple[]); | |
60 | ||
61 | // | |
62 | // For a regular executable, the crt code calls dyld to run the executables initializers. | |
63 | // For a static executable, crt directly runs the initializers. | |
64 | // dyld (should be static) but is a dynamic executable and needs this hack to run its own initializers. | |
65 | // We pass argc, argv, etc in case libc.a uses those arguments | |
66 | // | |
67 | static void runDyldInitializers(const struct macho_header* mh, intptr_t slide, int argc, const char* argv[], const char* envp[], const char* apple[]) | |
68 | { | |
69 | const uint32_t cmd_count = mh->ncmds; | |
70 | const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); | |
71 | const struct load_command* cmd = cmds; | |
72 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
73 | switch (cmd->cmd) { | |
74 | case LC_SEGMENT_COMMAND: | |
75 | { | |
76 | const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; | |
77 | const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); | |
78 | const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; | |
79 | for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { | |
80 | const uint8_t type = sect->flags & SECTION_TYPE; | |
81 | if ( type == S_MOD_INIT_FUNC_POINTERS ){ | |
82 | Initializer* inits = (Initializer*)(sect->addr + slide); | |
83 | const uint32_t count = sect->size / sizeof(uintptr_t); | |
84 | for (uint32_t i=0; i < count; ++i) { | |
85 | Initializer func = inits[i]; | |
86 | func(argc, argv, envp, apple); | |
87 | } | |
88 | } | |
89 | } | |
90 | } | |
91 | break; | |
92 | } | |
93 | cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); | |
94 | } | |
95 | } | |
96 | ||
97 | ||
98 | // | |
99 | // If the kernel does not load dyld at its preferred address, we need to apply | |
100 | // fixups to various initialized parts of the __DATA segment | |
101 | // | |
102 | static void rebaseDyld(const struct macho_header* mh, intptr_t slide) | |
103 | { | |
104 | // get interesting pointers into dyld | |
105 | const uint32_t cmd_count = mh->ncmds; | |
106 | const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); | |
107 | const struct load_command* cmd = cmds; | |
108 | const struct macho_segment_command* linkEditSeg = NULL; | |
109 | const struct dysymtab_command* dynamicSymbolTable = NULL; | |
110 | const struct macho_section* nonLazySection = NULL; | |
111 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
112 | switch (cmd->cmd) { | |
113 | case LC_SEGMENT_COMMAND: | |
114 | { | |
115 | const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; | |
116 | if ( strcmp(seg->segname, "__LINKEDIT") == 0 ) | |
117 | linkEditSeg = seg; | |
118 | const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command)); | |
119 | const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects]; | |
120 | for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) { | |
121 | const uint8_t type = sect->flags & SECTION_TYPE; | |
122 | if ( type == S_NON_LAZY_SYMBOL_POINTERS ) | |
123 | nonLazySection = sect; | |
124 | } | |
125 | } | |
126 | break; | |
127 | case LC_DYSYMTAB: | |
128 | dynamicSymbolTable = (struct dysymtab_command *)cmd; | |
129 | break; | |
130 | } | |
131 | cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); | |
132 | } | |
133 | ||
134 | // use reloc's to rebase all random data pointers | |
135 | const uintptr_t relocBase = (uintptr_t)mh; | |
136 | const relocation_info* const relocsStart = (struct relocation_info*)(linkEditSeg->vmaddr + slide + dynamicSymbolTable->locreloff - linkEditSeg->fileoff); | |
137 | const relocation_info* const relocsEnd = &relocsStart[dynamicSymbolTable->nlocrel]; | |
138 | for (const relocation_info* reloc=relocsStart; reloc < relocsEnd; ++reloc) { | |
139 | if ( (reloc->r_address & R_SCATTERED) == 0 ) { | |
140 | if (reloc->r_length == RELOC_SIZE) { | |
141 | switch(reloc->r_type) { | |
142 | case GENERIC_RELOC_VANILLA: | |
143 | *((uintptr_t*)(reloc->r_address + relocBase)) += slide; | |
144 | break; | |
145 | } | |
146 | } | |
147 | } | |
148 | else { | |
149 | const struct scattered_relocation_info* sreloc = (struct scattered_relocation_info*)reloc; | |
150 | if (sreloc->r_length == RELOC_SIZE) { | |
151 | uintptr_t* locationToFix = (uintptr_t*)(sreloc->r_address + relocBase); | |
152 | switch(sreloc->r_type) { | |
153 | case GENERIC_RELOC_VANILLA: | |
154 | #if __ppc__ || __ppc64__ | |
155 | case PPC_RELOC_PB_LA_PTR: | |
156 | #elif __i386__ | |
157 | case GENERIC_RELOC_PB_LA_PTR: | |
158 | #endif | |
159 | // Note the use of PB_LA_PTR is unique here. Seems like ld should strip out all lazy pointers | |
160 | // but it does not. But, since all lazy-pointers point within dyld, they can be slid too | |
161 | *locationToFix += slide; | |
162 | break; | |
163 | } | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | // rebase non-lazy pointers (which all point internal to dyld, since dyld uses no shared libraries) | |
169 | if ( nonLazySection != NULL ) { | |
170 | const uint32_t pointerCount = nonLazySection->size / sizeof(uintptr_t); | |
171 | uintptr_t* const symbolPointers = (uintptr_t*)(nonLazySection->addr + slide); | |
172 | for (uint32_t j=0; j < pointerCount; ++j) { | |
173 | symbolPointers[j] += slide; | |
174 | } | |
175 | } | |
176 | ||
177 | ||
178 | } | |
179 | ||
180 | // | |
181 | // For some reason the kernel loads dyld with __TEXT and __LINKEDIT writable | |
182 | // rdar://problem/3702311 | |
183 | // | |
184 | static void segmentProtectDyld(const struct macho_header* mh, intptr_t slide) | |
185 | { | |
186 | const uint32_t cmd_count = mh->ncmds; | |
187 | const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header)); | |
188 | const struct load_command* cmd = cmds; | |
189 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
190 | switch (cmd->cmd) { | |
191 | case LC_SEGMENT_COMMAND: | |
192 | { | |
193 | const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; | |
194 | vm_address_t addr = seg->vmaddr + slide; | |
195 | vm_size_t size = seg->vmsize; | |
196 | const bool setCurrentPermissions = false; | |
197 | vm_protect(mach_task_self(), addr, size, setCurrentPermissions, seg->initprot); | |
198 | //fprintf(stderr, "dyld: segment %s, 0x%08X -> 0x%08X, set to %d\n", seg->segname, addr, addr+size-1, seg->initprot); | |
199 | } | |
200 | break; | |
201 | } | |
202 | cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); | |
203 | } | |
204 | ||
205 | } | |
206 | ||
207 | extern "C" void dyld_exceptions_init(const struct macho_header*, uintptr_t slide); // in dyldExceptions.cpp | |
208 | extern "C" void mach_init(); | |
209 | ||
210 | // | |
211 | // This is code to bootstrap dyld. This work in normally done for a program by dyld and crt. | |
212 | // In dyld we have to do this manually. | |
213 | // | |
214 | uintptr_t start(const struct mach_header* appsMachHeader, int argc, const char* argv[], intptr_t slide) | |
215 | { | |
216 | // _mh_dylinker_header is magic symbol defined by static linker (ld), see <mach-o/ldsyms.h> | |
217 | const struct macho_header* dyldsMachHeader = (const struct macho_header*)(((char*)&_mh_dylinker_header)+slide); | |
218 | ||
219 | // if kernel had to slide dyld, we need to fix up load sensitive locations | |
220 | // we have to do this before using any global variables | |
221 | if ( slide != 0 ) { | |
222 | rebaseDyld(dyldsMachHeader, slide); | |
223 | } | |
224 | ||
225 | // enable C++ exceptions to work inside dyld | |
226 | dyld_exceptions_init(dyldsMachHeader, slide); | |
227 | ||
228 | // allow dyld to use mach messaging | |
229 | mach_init(); | |
230 | ||
231 | // set protection on segments (has to be done after mach_init) | |
232 | segmentProtectDyld(dyldsMachHeader, slide); | |
233 | ||
234 | // kernel sets up env pointer to be just past end of agv array | |
235 | const char** envp = &argv[argc+1]; | |
236 | ||
237 | // kernel sets up apple pointer to be just past end of envp array | |
238 | const char** apple = envp; | |
239 | while(*apple != NULL) { ++apple; } | |
240 | ++apple; | |
241 | ||
242 | // run all C++ initializers inside dyld | |
243 | runDyldInitializers(dyldsMachHeader, slide, argc, argv, envp, apple); | |
244 | ||
245 | // now that we are done bootstrapping dyld, call dyld's main | |
246 | return dyld::_main(appsMachHeader, argc, argv, envp, apple); | |
247 | } | |
248 | ||
249 | ||
250 | ||
251 | ||
252 | } // end of namespace | |
253 | ||
254 | ||
255 | ||
256 |