2 * Copyright (c) 2007-2008, 2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/types.h>
30 #include <mach/vm_param.h> /* For PAGE_SIZE */
32 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
33 #include <AssertMacros.h>
37 #include "kxld_types.h"
39 #include <libkern/kxld.h>
40 #include <libkern/kxld_types.h>
43 #include "kxld_array.h"
44 #include "kxld_dict.h"
45 #include "kxld_kext.h"
46 #include "kxld_object.h"
48 #include "kxld_symtab.h"
49 #include "kxld_util.h"
50 #include "kxld_vtable.h"
56 KXLDArray
*section_order
;
58 KXLDArray dependencies
;
59 KXLDDict defined_symbols_by_name
;
60 KXLDDict defined_cxx_symbols_by_value
;
61 KXLDDict obsolete_symbols_by_name
;
62 KXLDDict vtables_by_name
;
64 KXLDAllocateCallback allocate_callback
;
66 cpu_subtype_t cpusubtype
;
69 /*******************************************************************************
71 *******************************************************************************/
73 /* Certain architectures alter the order of a kext's sections from its input
74 * binary, so we track that order in a dictionary of arrays, with one array for
75 * each architecture. Since the kernel only has one architecture, we can
76 * eliminate the dictionary and use a simple array.
77 * XXX: If we ever use the linker in a multithreaded environment, we will need
78 * locks around these global structures.
80 #if KXLD_USER_OR_OBJECT
82 static KXLDArray
*s_section_order
;
84 static KXLDDict
*s_order_dict
;
88 /*******************************************************************************
90 *******************************************************************************/
92 static kern_return_t
init_context(KXLDContext
*context
, u_int ndependencies
);
93 static kern_return_t
init_kext_objects(KXLDContext
*context
, u_char
*file
,
94 u_long size
, const char *name
, KXLDDependency
*dependencies
,
96 static KXLDObject
* get_object_for_file(KXLDContext
*context
,
97 u_char
*file
, u_long size
, const char *name
);
98 static u_char
* allocate_kext(KXLDContext
*context
, void *callback_data
,
99 kxld_addr_t
*vmaddr
, u_long
*vmsize
, u_char
**linked_object_alloc_out
);
100 static void clear_context(KXLDContext
*context
);
102 /*******************************************************************************
103 *******************************************************************************/
105 kxld_create_context(KXLDContext
**_context
,
106 KXLDAllocateCallback allocate_callback
, KXLDLoggingCallback logging_callback
,
107 KXLDFlags flags
, cpu_type_t cputype
, cpu_subtype_t cpusubtype
)
109 kern_return_t rval
= KERN_FAILURE
;
110 KXLDContext
* context
= NULL
;
111 KXLDArray
* section_order
= NULL
;
113 cpu_type_t
* cputype_p
= NULL
;
117 check(allocate_callback
);
118 check(logging_callback
);
121 context
= kxld_alloc(sizeof(*context
));
122 require_action(context
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
123 bzero(context
, sizeof(*context
));
125 context
->flags
= flags
;
126 context
->allocate_callback
= allocate_callback
;
127 context
->cputype
= cputype
;
128 context
->cpusubtype
= cpusubtype
;
130 kxld_set_logging_callback(logging_callback
);
132 context
->kext
= kxld_alloc(kxld_kext_sizeof());
133 require_action(context
->kext
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
134 bzero(context
->kext
, kxld_kext_sizeof());
136 /* Check if we already have an order array for this arch */
138 #if KXLD_USER_OR_OBJECT
140 context
->section_order
= s_section_order
;
142 /* In userspace, create the dictionary if it doesn't already exist */
144 s_order_dict
= kxld_alloc(sizeof(*s_order_dict
));
145 require_action(s_order_dict
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
146 bzero(s_order_dict
, sizeof(*s_order_dict
));
148 rval
= kxld_dict_init(s_order_dict
, kxld_dict_uint32_hash
,
149 kxld_dict_uint32_cmp
, 0);
150 require_noerr(rval
, finish
);
153 context
->section_order
= kxld_dict_find(s_order_dict
, &cputype
);
156 /* Create an order array for this arch if needed */
158 if (!context
->section_order
) {
160 section_order
= kxld_alloc(sizeof(*section_order
));
161 require_action(section_order
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
162 bzero(section_order
, sizeof(*section_order
));
165 s_section_order
= section_order
;
167 /* In userspace, add the new array to the order dictionary */
168 cputype_p
= kxld_alloc(sizeof(*cputype_p
));
169 require_action(cputype_p
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
170 *cputype_p
= cputype
;
172 rval
= kxld_dict_insert(s_order_dict
, cputype_p
, section_order
);
173 require_noerr(rval
, finish
);
178 context
->section_order
= section_order
;
180 section_order
= NULL
;
182 #endif /* KXLD_USER_OR_OBJECT */
189 if (context
) kxld_destroy_context(context
);
190 if (section_order
) kxld_free(section_order
, sizeof(*section_order
));
192 if (cputype_p
) kxld_free(cputype_p
, sizeof(*cputype_p
));
198 /*******************************************************************************
199 *******************************************************************************/
201 kxld_destroy_context(KXLDContext
*context
)
203 KXLDObject
*object
= NULL
;
204 KXLDKext
*dep
= NULL
;
209 kxld_kext_deinit(context
->kext
);
211 for (i
= 0; i
< context
->objects
.maxitems
; ++i
) {
212 object
= kxld_array_get_slot(&context
->objects
, i
);
213 kxld_object_deinit(object
);
215 kxld_array_deinit(&context
->objects
);
217 for (i
= 0; i
< context
->dependencies
.maxitems
; ++i
) {
218 dep
= kxld_array_get_slot(&context
->dependencies
, i
);
219 kxld_kext_deinit(dep
);
221 kxld_array_deinit(&context
->dependencies
);
223 kxld_dict_deinit(&context
->defined_symbols_by_name
);
224 kxld_dict_deinit(&context
->defined_cxx_symbols_by_value
);
225 kxld_dict_deinit(&context
->obsolete_symbols_by_name
);
226 kxld_dict_deinit(&context
->vtables_by_name
);
228 kxld_free(context
->kext
, kxld_kext_sizeof());
229 kxld_free(context
, sizeof(*context
));
231 kxld_print_memory_report();
234 /*******************************************************************************
235 *******************************************************************************/
238 KXLDContext
* context
,
242 void * callback_data
,
243 KXLDDependency
* dependencies
,
245 u_char
** linked_object_out
,
246 kxld_addr_t
* kmod_info_kern
)
248 kern_return_t rval
= KERN_FAILURE
;
249 kxld_addr_t vmaddr
= 0;
251 u_char
* linked_object
= NULL
;
252 u_char
* linked_object_alloc
= NULL
;
254 kxld_set_logging_callback_data(name
, callback_data
);
256 kxld_log(kKxldLogLinking
, kKxldLogBasic
, "Linking kext %s", name
);
258 require_action(context
, finish
, rval
=KERN_INVALID_ARGUMENT
);
259 require_action(file
, finish
, rval
=KERN_INVALID_ARGUMENT
);
260 require_action(size
, finish
, rval
=KERN_INVALID_ARGUMENT
);
261 require_action(dependencies
, finish
, rval
=KERN_INVALID_ARGUMENT
);
262 require_action(ndependencies
, finish
, rval
=KERN_INVALID_ARGUMENT
);
263 require_action(linked_object_out
, finish
, rval
=KERN_INVALID_ARGUMENT
);
264 require_action(kmod_info_kern
, finish
, rval
=KERN_INVALID_ARGUMENT
);
266 rval
= init_context(context
, ndependencies
);
267 require_noerr(rval
, finish
);
269 rval
= init_kext_objects(context
, file
, size
, name
,
270 dependencies
, ndependencies
);
271 require_noerr(rval
, finish
);
273 linked_object
= allocate_kext(context
, callback_data
,
274 &vmaddr
, &vmsize
, &linked_object_alloc
);
275 require_action(linked_object
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
277 rval
= kxld_kext_relocate(context
->kext
, vmaddr
,
278 &context
->vtables_by_name
,
279 &context
->defined_symbols_by_name
,
280 &context
->obsolete_symbols_by_name
,
281 &context
->defined_cxx_symbols_by_value
);
282 require_noerr(rval
, finish
);
284 rval
= kxld_kext_export_linked_object(context
->kext
,
285 linked_object
, kmod_info_kern
);
286 require_noerr(rval
, finish
);
288 *linked_object_out
= linked_object
;
289 linked_object_alloc
= NULL
;
293 if (linked_object_alloc
) {
294 kxld_page_free_untracked(linked_object_alloc
, vmsize
);
297 clear_context(context
);
298 kxld_set_logging_callback_data(NULL
, NULL
);
303 /*******************************************************************************
304 *******************************************************************************/
306 init_context(KXLDContext
*context
, u_int ndependencies
)
308 kern_return_t rval
= KERN_FAILURE
;
310 /* Create an array of objects large enough to hold an object
311 * for every dependency, an interface for each dependency, and a kext. */
312 rval
= kxld_array_init(&context
->objects
,
313 kxld_object_sizeof(), 2 * ndependencies
+ 1);
314 require_noerr(rval
, finish
);
316 rval
= kxld_array_init(&context
->dependencies
,
317 kxld_kext_sizeof(), ndependencies
);
318 require_noerr(rval
, finish
);
320 rval
= kxld_dict_init(&context
->defined_symbols_by_name
,
321 kxld_dict_string_hash
, kxld_dict_string_cmp
, 0);
322 require_noerr(rval
, finish
);
324 rval
= kxld_dict_init(&context
->defined_cxx_symbols_by_value
,
325 kxld_dict_kxldaddr_hash
, kxld_dict_kxldaddr_cmp
, 0);
326 require_noerr(rval
, finish
);
328 rval
= kxld_dict_init(&context
->obsolete_symbols_by_name
,
329 kxld_dict_string_hash
, kxld_dict_string_cmp
, 0);
330 require_noerr(rval
, finish
);
332 rval
= kxld_dict_init(&context
->vtables_by_name
, kxld_dict_string_hash
,
333 kxld_dict_string_cmp
, 0);
334 require_noerr(rval
, finish
);
341 /*******************************************************************************
342 *******************************************************************************/
344 init_kext_objects(KXLDContext
*context
, u_char
*file
, u_long size
,
345 const char *name
, KXLDDependency
*dependencies
, u_int ndependencies
)
347 kern_return_t rval
= KERN_FAILURE
;
348 KXLDKext
*kext
= NULL
;
349 KXLDObject
*kext_object
= NULL
;
350 KXLDObject
*interface_object
= NULL
;
353 /* Create a kext object for each dependency. If it's a direct dependency,
354 * export its symbols by name by value. If it's indirect, just export the
355 * C++ symbols by value.
357 for (i
= 0; i
< ndependencies
; ++i
) {
358 kext
= kxld_array_get_item(&context
->dependencies
, i
);
360 interface_object
= NULL
;
362 kext_object
= get_object_for_file(context
, dependencies
[i
].kext
,
363 dependencies
[i
].kext_size
, dependencies
[i
].kext_name
);
364 require_action(kext_object
, finish
, rval
=KERN_FAILURE
);
366 if (dependencies
[i
].interface
) {
367 interface_object
= get_object_for_file(context
,
368 dependencies
[i
].interface
, dependencies
[i
].interface_size
,
369 dependencies
[i
].interface_name
);
370 require_action(interface_object
, finish
, rval
=KERN_FAILURE
);
373 rval
= kxld_kext_init(kext
, kext_object
, interface_object
);
374 require_noerr(rval
, finish
);
376 if (dependencies
[i
].is_direct_dependency
) {
377 rval
= kxld_kext_export_symbols(kext
,
378 &context
->defined_symbols_by_name
,
379 &context
->obsolete_symbols_by_name
,
380 &context
->defined_cxx_symbols_by_value
);
381 require_noerr(rval
, finish
);
383 rval
= kxld_kext_export_symbols(kext
,
384 /* defined_symbols */ NULL
, /* obsolete_symbols */ NULL
,
385 &context
->defined_cxx_symbols_by_value
);
386 require_noerr(rval
, finish
);
390 /* Export the vtables for all of the dependencies. */
391 for (i
= 0; i
< context
->dependencies
.nitems
; ++i
) {
392 kext
= kxld_array_get_item(&context
->dependencies
, i
);
394 rval
= kxld_kext_export_vtables(kext
,
395 &context
->defined_cxx_symbols_by_value
,
396 &context
->defined_symbols_by_name
,
397 &context
->vtables_by_name
);
398 require_noerr(rval
, finish
);
401 /* Create a kext object for the kext we're linking and export its locally
402 * defined C++ symbols.
404 kext_object
= get_object_for_file(context
, file
, size
, name
);
405 require_action(kext_object
, finish
, rval
=KERN_FAILURE
);
407 rval
= kxld_kext_init(context
->kext
, kext_object
, /* interface */ NULL
);
408 require_noerr(rval
, finish
);
410 rval
= kxld_kext_export_symbols(context
->kext
,
411 /* defined_symbols */ NULL
, /* obsolete_symbols */ NULL
,
412 &context
->defined_cxx_symbols_by_value
);
413 require_noerr(rval
, finish
);
420 /*******************************************************************************
421 *******************************************************************************/
423 get_object_for_file(KXLDContext
*context
, u_char
*file
, u_long size
,
426 KXLDObject
*rval
= NULL
;
427 KXLDObject
*object
= NULL
;
428 kern_return_t result
= 0;
431 for (i
= 0; i
< context
->objects
.nitems
; ++i
) {
432 object
= kxld_array_get_item(&context
->objects
, i
);
434 if (!kxld_object_get_file(object
)) {
435 result
= kxld_object_init_from_macho(object
, file
, size
, name
,
436 context
->section_order
, context
->cputype
, context
->cpusubtype
, context
->flags
);
437 require_noerr(result
, finish
);
443 if (kxld_object_get_file(object
) == file
) {
453 /*******************************************************************************
454 *******************************************************************************/
456 allocate_kext(KXLDContext
*context
, void *callback_data
,
457 kxld_addr_t
*vmaddr_out
, u_long
*vmsize_out
,
458 u_char
**linked_object_alloc_out
)
460 KXLDAllocateFlags flags
= 0;
461 kxld_addr_t vmaddr
= 0;
463 u_long header_size
= 0;
464 u_char
* linked_object
= NULL
;
466 *linked_object_alloc_out
= NULL
;
468 kxld_kext_get_vmsize(context
->kext
, &header_size
, &vmsize
);
469 vmaddr
= context
->allocate_callback(vmsize
, &flags
, callback_data
);
470 require_action(!(vmaddr
& (PAGE_SIZE
-1)), finish
,
471 kxld_log(kKxldLogLinking
, kKxldLogErr
,
472 "Load address %p is not page-aligned.",
473 (void *) (uintptr_t) vmaddr
));
475 if (flags
& kKxldAllocateWritable
) {
476 linked_object
= (u_char
*) (u_long
) vmaddr
;
478 linked_object
= kxld_page_alloc_untracked(vmsize
);
479 require(linked_object
, finish
);
481 *linked_object_alloc_out
= linked_object
;
484 kxld_kext_set_linked_object_size(context
->kext
, vmsize
);
486 /* Zero out the memory before we fill it. We fill this buffer in a
487 * sparse fashion, and it's simpler to clear it now rather than
488 * track and zero any pieces we didn't touch after we've written
489 * all of the sections to memory.
491 bzero(linked_object
, vmsize
);
492 *vmaddr_out
= vmaddr
;
493 *vmsize_out
= vmsize
;
496 return linked_object
;
499 /*******************************************************************************
500 *******************************************************************************/
502 clear_context(KXLDContext
*context
)
504 KXLDObject
* object
= NULL
;
505 KXLDKext
* dep
= NULL
;
510 kxld_kext_clear(context
->kext
);
512 for (i
= 0; i
< context
->objects
.nitems
; ++i
) {
513 object
= kxld_array_get_item(&context
->objects
, i
);
514 kxld_object_clear(object
);
516 kxld_array_reset(&context
->objects
);
518 for (i
= 0; i
< context
->dependencies
.nitems
; ++i
) {
519 dep
= kxld_array_get_item(&context
->dependencies
, i
);
520 kxld_kext_clear(dep
);
522 kxld_array_reset(&context
->dependencies
);
524 kxld_dict_clear(&context
->defined_symbols_by_name
);
525 kxld_dict_clear(&context
->defined_cxx_symbols_by_value
);
526 kxld_dict_clear(&context
->obsolete_symbols_by_name
);
527 kxld_dict_clear(&context
->vtables_by_name
);