]> git.saurik.com Git - apple/xnu.git/blob - libkern/kxld/kxld.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / libkern / kxld / kxld.c
1 /*
2 * Copyright (c) 2007-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <string.h>
29 #include <sys/types.h>
30 #include <mach/vm_param.h> /* For PAGE_SIZE */
31
32 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
33 #include <AssertMacros.h>
34
35 #if !KERNEL
36 #include "kxld.h"
37 #include "kxld_types.h"
38 #else
39 #include <libkern/kxld.h>
40 #include <libkern/kxld_types.h>
41 #endif /* KERNEL */
42
43 #include "kxld_array.h"
44 #include "kxld_dict.h"
45 #include "kxld_kext.h"
46 #include "kxld_state.h"
47 #include "kxld_sym.h"
48 #include "kxld_symtab.h"
49 #include "kxld_util.h"
50 #include "kxld_vtable.h"
51
52 struct kxld_vtable;
53
54 struct kxld_context {
55 KXLDKext *kext;
56 KXLDArray *section_order;
57 KXLDArray deps;
58 KXLDArray tmps;
59 KXLDDict defined_symbols;
60 KXLDDict obsolete_symbols;
61 KXLDDict vtables;
62 KXLDFlags flags;
63 KXLDAllocateCallback allocate_callback;
64 cpu_type_t cputype;
65 cpu_subtype_t cpusubtype;
66 };
67
68 /*******************************************************************************
69 * Globals
70 *******************************************************************************/
71
72 /* Certain architectures alter the order of a kext's sections from its input
73 * binary, so we track that order in a dictionary of arrays, with one array for
74 * each architecture. Since the kernel only has one architecture, we can
75 * eliminate the dictionary and use a simple array.
76 * XXX: If we ever use the linker in a multithreaded environment, we will need
77 * locks around these global structures.
78 */
79 #if KXLD_USER_OR_OBJECT
80 #if KERNEL
81 static KXLDArray *s_section_order;
82 #else
83 static KXLDDict *s_order_dict;
84 #endif
85 #endif
86
87 /*******************************************************************************
88 * Prototypes
89 *******************************************************************************/
90
91 static void clear_context(KXLDContext *context);
92
93 /*******************************************************************************
94 *******************************************************************************/
95 kern_return_t
96 kxld_create_context(KXLDContext **_context,
97 KXLDAllocateCallback allocate_callback, KXLDLoggingCallback logging_callback,
98 KXLDFlags flags, cpu_type_t cputype, cpu_subtype_t cpusubtype)
99 {
100 kern_return_t rval = KERN_FAILURE;
101 KXLDContext *context = NULL;
102 KXLDArray *section_order = NULL;
103 #if !KERNEL
104 cpu_type_t *cputype_p = NULL;
105 #endif
106
107 check(_context);
108 check(allocate_callback);
109 check(logging_callback);
110 *_context = NULL;
111
112 context = kxld_alloc(sizeof(*context));
113 require_action(context, finish, rval=KERN_RESOURCE_SHORTAGE);
114 bzero(context, sizeof(*context));
115
116 context->flags = flags;
117 context->allocate_callback = allocate_callback;
118 context->cputype = cputype;
119 context->cpusubtype = cpusubtype;
120
121 kxld_set_logging_callback(logging_callback);
122
123 context->kext = kxld_alloc(kxld_kext_sizeof());
124 require_action(context->kext, finish, rval=KERN_RESOURCE_SHORTAGE);
125 bzero(context->kext, kxld_kext_sizeof());
126
127 /* Check if we already have an order array for this arch */
128
129 #if KXLD_USER_OR_OBJECT
130 #if KERNEL
131 context->section_order = s_section_order;
132 #else
133 /* In userspace, create the dictionary if it doesn't already exist */
134 if (!s_order_dict) {
135 s_order_dict = kxld_alloc(sizeof(*s_order_dict));
136 require_action(s_order_dict, finish, rval=KERN_RESOURCE_SHORTAGE);
137 bzero(s_order_dict, sizeof(*s_order_dict));
138
139 rval = kxld_dict_init(s_order_dict, kxld_dict_uint32_hash,
140 kxld_dict_uint32_cmp, 0);
141 require_noerr(rval, finish);
142 }
143
144 context->section_order = kxld_dict_find(s_order_dict, &cputype);
145 #endif /* KERNEL */
146
147 /* Create an order array for this arch if needed */
148
149 if (!context->section_order) {
150
151 section_order = kxld_alloc(sizeof(*section_order));
152 require_action(section_order, finish, rval=KERN_RESOURCE_SHORTAGE);
153 bzero(section_order, sizeof(*section_order));
154
155 #if KERNEL
156 s_section_order = section_order;
157 #else
158 /* In userspace, add the new array to the order dictionary */
159 cputype_p = kxld_alloc(sizeof(*cputype_p));
160 require_action(cputype_p, finish, rval=KERN_RESOURCE_SHORTAGE);
161 *cputype_p = cputype;
162
163 rval = kxld_dict_insert(s_order_dict, cputype_p, section_order);
164 require_noerr(rval, finish);
165
166 cputype_p = NULL;
167 #endif /* KERNEL */
168
169 context->section_order = section_order;
170
171 section_order = NULL;
172 }
173 #endif /* KXLD_USER_OR_OBJECT */
174
175 rval = KERN_SUCCESS;
176 *_context = context;
177 context = NULL;
178
179 finish:
180 if (context) kxld_free(context, sizeof(*context));
181 if (section_order) kxld_free(section_order, sizeof(*section_order));
182 #if !KERNEL
183 if (cputype_p) kxld_free(cputype_p, sizeof(*cputype_p));
184 #endif
185
186 return rval;
187 }
188
189 /*******************************************************************************
190 *******************************************************************************/
191 void
192 kxld_destroy_context(KXLDContext *context)
193 {
194 KXLDState *dep = NULL;
195 u_int i = 0;
196
197 check(context);
198
199 kxld_kext_deinit(context->kext);
200
201 for (i = 0; i < context->deps.maxitems; ++i) {
202 dep = kxld_array_get_slot(&context->deps, i);
203 kxld_state_deinit(dep);
204 }
205
206 kxld_array_deinit(&context->deps);
207 kxld_array_deinit(&context->tmps);
208
209 kxld_dict_deinit(&context->defined_symbols);
210 kxld_dict_deinit(&context->obsolete_symbols);
211 kxld_dict_deinit(&context->vtables);
212
213 kxld_free(context->kext, kxld_kext_sizeof());
214 kxld_free(context, sizeof(*context));
215
216 kxld_print_memory_report();
217 }
218
219 /*******************************************************************************
220 *******************************************************************************/
221 kern_return_t
222 kxld_link_file(
223 KXLDContext *context,
224 u_char *file,
225 u_long size,
226 const char *name,
227 void *callback_data,
228 u_char **deps,
229 u_int ndeps,
230 u_char **_linked_object,
231 kxld_addr_t *kmod_info_kern,
232 u_char **_link_state,
233 u_long *_link_state_size,
234 u_char **_symbol_file __unused,
235 u_long *_symbol_file_size __unused)
236 {
237 kern_return_t rval = KERN_FAILURE;
238 KXLDState *state = NULL;
239 KXLDAllocateFlags flags = 0;
240 kxld_addr_t vmaddr = 0;
241 u_long header_size = 0;
242 u_long vmsize = 0;
243 u_int nsyms = 0;
244 u_int nvtables = 0;
245 u_int i = 0;
246 u_char *linked_object = NULL;
247 u_char *linked_object_alloc = NULL;
248 u_char *link_state = NULL;
249 u_char *symbol_file = NULL;
250 u_long link_state_size = 0;
251 u_long symbol_file_size = 0;
252
253 kxld_set_logging_callback_data(name, callback_data);
254
255 require_action(context, finish, rval=KERN_INVALID_ARGUMENT);
256 require_action(file, finish, rval=KERN_INVALID_ARGUMENT);
257 require_action(size, finish, rval=KERN_INVALID_ARGUMENT);
258
259 rval = kxld_array_init(&context->deps, sizeof(struct kxld_state), ndeps);
260 require_noerr(rval, finish);
261
262 if (deps) {
263 /* Initialize the dependencies */
264 for (i = 0; i < ndeps; ++i) {
265 state = kxld_array_get_item(&context->deps, i);
266
267 rval = kxld_state_init_from_file(state, deps[i],
268 context->section_order);
269 require_noerr(rval, finish);
270 }
271 }
272
273 rval = kxld_kext_init(context->kext, file, size, name,
274 context->flags, (deps == 0) /* is_kernel */, context->section_order,
275 context->cputype, context->cpusubtype);
276 require_noerr(rval, finish);
277
278 if (deps) {
279
280 /* Calculate the base number of symbols and vtables in the kext */
281
282 nsyms += kxld_kext_get_num_symbols(context->kext);
283 nvtables += kxld_kext_get_num_vtables(context->kext);
284
285 /* Extract the symbol and vtable counts from the dependencies.
286 */
287
288 for (i = 0; i < ndeps; ++i) {
289 cpu_type_t cputype;
290 cpu_subtype_t cpusubtype;
291
292 state = kxld_array_get_item(&context->deps, i);
293
294 kxld_state_get_cputype(state, &cputype, &cpusubtype);
295
296 rval = kxld_kext_validate_cputype(context->kext,
297 cputype, cpusubtype);
298 require_noerr(rval, finish);
299
300 nsyms += kxld_state_get_num_symbols(state);
301 nvtables += kxld_state_get_num_vtables(state);
302 }
303
304 /* Create the global symbol and vtable tables */
305
306 rval = kxld_dict_init(&context->defined_symbols, kxld_dict_string_hash,
307 kxld_dict_string_cmp, nsyms);
308 require_noerr(rval, finish);
309
310 rval = kxld_dict_init(&context->obsolete_symbols, kxld_dict_string_hash,
311 kxld_dict_string_cmp, 0);
312 require_noerr(rval, finish);
313
314 rval = kxld_dict_init(&context->vtables, kxld_dict_string_hash,
315 kxld_dict_string_cmp, nvtables);
316 require_noerr(rval, finish);
317
318 /* Populate the global tables */
319
320 for (i = 0; i < ndeps; ++i) {
321 state = kxld_array_get_item(&context->deps, i);
322
323 rval = kxld_state_get_symbols(state, &context->defined_symbols,
324 &context->obsolete_symbols);
325 require_noerr(rval, finish);
326
327 rval = kxld_state_get_vtables(state, &context->vtables);
328 require_noerr(rval, finish);
329 }
330
331 if (kxld_kext_is_true_kext(context->kext)) {
332
333 /* Allocate the kext object */
334
335 kxld_kext_get_vmsize(context->kext, &header_size, &vmsize);
336 vmaddr = context->allocate_callback(vmsize, &flags, callback_data);
337 require_action(!(vmaddr & (PAGE_SIZE-1)), finish, rval=KERN_FAILURE;
338 kxld_log(kKxldLogLinking, kKxldLogErr,
339 "Load address %p is not page-aligned.",
340 (void *) (uintptr_t) vmaddr));
341
342 if (flags & kKxldAllocateWritable) {
343 linked_object = (u_char *) (u_long) vmaddr;
344 } else {
345 linked_object_alloc = kxld_page_alloc_untracked(vmsize);
346 require_action(linked_object_alloc, finish, rval=KERN_RESOURCE_SHORTAGE);
347 linked_object = linked_object_alloc;
348 }
349
350 /* Zero out the memory before we fill it. We fill this buffer in a
351 * sparse fashion, and it's simpler to clear it now rather than
352 * track and zero any pieces we didn't touch after we've written
353 * all of the sections to memory.
354 */
355 bzero(linked_object, vmsize);
356
357 /* Relocate to the new link address */
358
359 rval = kxld_kext_relocate(context->kext, vmaddr, &context->vtables,
360 &context->defined_symbols, &context->obsolete_symbols);
361 require_noerr(rval, finish);
362
363 /* Generate linked object if requested */
364
365 if (_linked_object) {
366 check(kmod_info_kern);
367 *_linked_object = NULL;
368 *kmod_info_kern = 0;
369
370 rval = kxld_kext_export_linked_object(context->kext, linked_object,
371 kmod_info_kern);
372 require_noerr(rval, finish);
373 }
374
375 } else {
376 /* Resolve the pseudokext's symbols */
377
378 rval = kxld_kext_resolve(context->kext, &context->vtables,
379 &context->defined_symbols);
380 require_noerr(rval, finish);
381 }
382 }
383
384 /* Generate link state if requested */
385
386 if (_link_state) {
387 check(_link_state_size);
388 *_link_state = NULL;
389 *_link_state_size = 0;
390
391 kxld_dict_clear(&context->defined_symbols);
392 rval = kxld_state_export_kext_to_file(context->kext, &link_state,
393 &link_state_size, &context->defined_symbols, &context->tmps);
394 require_noerr(rval, finish);
395 }
396
397 #if !KERNEL
398 /* Generate symbol file if requested */
399
400 if (_symbol_file) {
401 check(_symbol_file_size);
402 *_symbol_file = NULL;
403 *_symbol_file_size = 0;
404
405 rval = kxld_kext_export_symbol_file(context->kext, &symbol_file,
406 &symbol_file_size);
407 require_noerr(rval, finish);
408 }
409 #endif /* !KERNEL */
410
411 /* Commit output to return variables */
412
413 if (_linked_object) {
414 *_linked_object = linked_object;
415 linked_object = NULL;
416 linked_object_alloc = NULL;
417 }
418
419 if (_link_state) {
420 *_link_state = link_state;
421 *_link_state_size = link_state_size;
422 link_state = NULL;
423 }
424
425 #if !KERNEL
426 if (_symbol_file) {
427 *_symbol_file = symbol_file;
428 *_symbol_file_size = symbol_file_size;
429 symbol_file = NULL;
430 }
431 #endif
432
433 rval = KERN_SUCCESS;
434
435 finish:
436
437 if (linked_object_alloc) kxld_page_free_untracked(linked_object_alloc, vmsize);
438 if (link_state) kxld_page_free_untracked(link_state, link_state_size);
439 if (symbol_file) kxld_page_free_untracked(symbol_file, symbol_file_size);
440
441 clear_context(context);
442
443 kxld_set_logging_callback_data(NULL, NULL);
444
445 return rval;
446 }
447
448 /*******************************************************************************
449 *******************************************************************************/
450 static void
451 clear_context(KXLDContext *context)
452 {
453 KXLDState *state = NULL;
454 u_int i = 0;
455
456 check(context);
457
458 kxld_kext_clear(context->kext);
459 for (i = 0; i < context->deps.nitems; ++i) {
460 state = kxld_array_get_item(&context->deps, i);
461 kxld_state_clear(state);
462 }
463 kxld_array_reset(&context->deps);
464
465 kxld_array_clear(&context->tmps);
466 kxld_dict_clear(&context->defined_symbols);
467 kxld_dict_clear(&context->obsolete_symbols);
468 kxld_dict_clear(&context->vtables);
469 }
470