2 * Copyright (c) 2007-2008 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
) { kext
=
358 kxld_array_get_item(&context
->dependencies
, i
); kext_object
= NULL
;
359 interface_object
= NULL
;
361 kext_object
= get_object_for_file(context
, dependencies
[i
].kext
,
362 dependencies
[i
].kext_size
, dependencies
[i
].kext_name
);
363 require_action(kext_object
, finish
, rval
=KERN_FAILURE
);
365 if (dependencies
[i
].interface
) {
366 interface_object
= get_object_for_file(context
,
367 dependencies
[i
].interface
, dependencies
[i
].interface_size
,
368 dependencies
[i
].interface_name
);
369 require_action(interface_object
, finish
, rval
=KERN_FAILURE
);
372 rval
= kxld_kext_init(kext
, kext_object
, interface_object
);
373 require_noerr(rval
, finish
);
375 if (dependencies
[i
].is_direct_dependency
) {
376 rval
= kxld_kext_export_symbols(kext
,
377 &context
->defined_symbols_by_name
,
378 &context
->obsolete_symbols_by_name
,
379 &context
->defined_cxx_symbols_by_value
);
380 require_noerr(rval
, finish
);
382 rval
= kxld_kext_export_symbols(kext
,
383 /* defined_symbols */ NULL
, /* obsolete_symbols */ NULL
,
384 &context
->defined_cxx_symbols_by_value
);
385 require_noerr(rval
, finish
);
389 /* Export the vtables for all of the dependencies. */
390 for (i
= 0; i
< context
->dependencies
.nitems
; ++i
) {
391 kext
= kxld_array_get_item(&context
->dependencies
, i
);
393 rval
= kxld_kext_export_vtables(kext
,
394 &context
->defined_cxx_symbols_by_value
,
395 &context
->defined_symbols_by_name
,
396 &context
->vtables_by_name
);
397 require_noerr(rval
, finish
);
400 /* Create a kext object for the kext we're linking and export its locally
401 * defined C++ symbols.
403 kext_object
= get_object_for_file(context
, file
, size
, name
);
404 require_action(kext_object
, finish
, rval
=KERN_FAILURE
);
406 rval
= kxld_kext_init(context
->kext
, kext_object
, /* interface */ NULL
);
407 require_noerr(rval
, finish
);
409 rval
= kxld_kext_export_symbols(context
->kext
,
410 /* defined_symbols */ NULL
, /* obsolete_symbols */ NULL
,
411 &context
->defined_cxx_symbols_by_value
);
412 require_noerr(rval
, finish
);
419 /*******************************************************************************
420 *******************************************************************************/
422 get_object_for_file(KXLDContext
*context
, u_char
*file
, u_long size
,
425 KXLDObject
*rval
= NULL
;
426 KXLDObject
*object
= NULL
;
427 kern_return_t result
= 0;
430 for (i
= 0; i
< context
->objects
.nitems
; ++i
) {
431 object
= kxld_array_get_item(&context
->objects
, i
);
433 if (!kxld_object_get_file(object
)) {
434 result
= kxld_object_init_from_macho(object
, file
, size
, name
,
435 context
->section_order
, context
->cputype
, context
->cpusubtype
);
436 require_noerr(result
, finish
);
442 if (kxld_object_get_file(object
) == file
) {
452 /*******************************************************************************
453 *******************************************************************************/
455 allocate_kext(KXLDContext
*context
, void *callback_data
,
456 kxld_addr_t
*vmaddr_out
, u_long
*vmsize_out
,
457 u_char
**linked_object_alloc_out
)
459 KXLDAllocateFlags flags
= 0;
460 kxld_addr_t vmaddr
= 0;
462 u_long header_size
= 0;
463 u_char
* linked_object
= NULL
;
465 *linked_object_alloc_out
= NULL
;
467 kxld_kext_get_vmsize(context
->kext
, &header_size
, &vmsize
);
468 vmaddr
= context
->allocate_callback(vmsize
, &flags
, callback_data
);
469 require_action(!(vmaddr
& (PAGE_SIZE
-1)), finish
,
470 kxld_log(kKxldLogLinking
, kKxldLogErr
,
471 "Load address %p is not page-aligned.",
472 (void *) (uintptr_t) vmaddr
));
474 if (flags
& kKxldAllocateWritable
) {
475 linked_object
= (u_char
*) (u_long
) vmaddr
;
477 linked_object
= kxld_page_alloc_untracked(vmsize
);
478 require(linked_object
, finish
);
480 *linked_object_alloc_out
= linked_object
;
483 /* Zero out the memory before we fill it. We fill this buffer in a
484 * sparse fashion, and it's simpler to clear it now rather than
485 * track and zero any pieces we didn't touch after we've written
486 * all of the sections to memory.
488 bzero(linked_object
, vmsize
);
489 *vmaddr_out
= vmaddr
;
490 *vmsize_out
= vmsize
;
493 return linked_object
;
496 /*******************************************************************************
497 *******************************************************************************/
499 clear_context(KXLDContext
*context
)
501 KXLDObject
* object
= NULL
;
502 KXLDKext
* dep
= NULL
;
507 kxld_kext_clear(context
->kext
);
509 for (i
= 0; i
< context
->objects
.nitems
; ++i
) {
510 object
= kxld_array_get_item(&context
->objects
, i
);
511 kxld_object_clear(object
);
513 kxld_array_reset(&context
->objects
);
515 for (i
= 0; i
< context
->dependencies
.nitems
; ++i
) {
516 dep
= kxld_array_get_item(&context
->dependencies
, i
);
517 kxld_kext_clear(dep
);
519 kxld_array_reset(&context
->dependencies
);
521 kxld_dict_clear(&context
->defined_symbols_by_name
);
522 kxld_dict_clear(&context
->defined_cxx_symbols_by_value
);
523 kxld_dict_clear(&context
->obsolete_symbols_by_name
);
524 kxld_dict_clear(&context
->vtables_by_name
);