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