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>
36 #define __KXLD_KERNEL_UNUSED __unused
38 #define __KXLD_KERNEL_UNUSED
43 #include "kxld_types.h"
45 #include <libkern/kxld.h>
46 #include <libkern/kxld_types.h>
49 #include "kxld_array.h"
50 #include "kxld_dict.h"
51 #include "kxld_kext.h"
52 #include "kxld_object.h"
54 #include "kxld_symtab.h"
55 #include "kxld_util.h"
56 #include "kxld_vtable.h"
62 KXLDArray
*section_order
;
64 KXLDArray dependencies
;
65 KXLDDict defined_symbols_by_name
;
66 KXLDDict defined_cxx_symbols_by_value
;
67 KXLDDict obsolete_symbols_by_name
;
68 KXLDDict vtables_by_name
;
70 KXLDAllocateCallback allocate_callback
;
72 cpu_subtype_t cpusubtype
;
75 /*******************************************************************************
77 *******************************************************************************/
79 /* Certain architectures alter the order of a kext's sections from its input
80 * binary, so we track that order in a dictionary of arrays, with one array for
81 * each architecture. Since the kernel only has one architecture, we can
82 * eliminate the dictionary and use a simple array.
83 * XXX: If we ever use the linker in a multithreaded environment, we will need
84 * locks around these global structures.
86 #if KXLD_USER_OR_OBJECT
88 static KXLDArray
*s_section_order
;
90 static KXLDDict
*s_order_dict
;
94 /*******************************************************************************
96 *******************************************************************************/
98 static kern_return_t
init_context(KXLDContext
*context
, u_int ndependencies
);
99 static kern_return_t
init_kext_objects(KXLDContext
*context
, u_char
*file
,
100 u_long size
, const char *name
, KXLDDependency
*dependencies
,
101 u_int ndependencies
);
102 static KXLDObject
* get_object_for_file(KXLDContext
*context
,
103 u_char
*file
, u_long size
, const char *name
);
104 static u_char
* allocate_kext(KXLDContext
*context
, void *callback_data
,
105 kxld_addr_t
*vmaddr
, u_long
*vmsize
, u_char
**linked_object_alloc_out
);
106 static void clear_context(KXLDContext
*context
);
108 /*******************************************************************************
109 *******************************************************************************/
111 kxld_create_context(KXLDContext
**_context
,
112 KXLDAllocateCallback allocate_callback
, KXLDLoggingCallback logging_callback
,
113 KXLDFlags flags
, cpu_type_t cputype
, cpu_subtype_t cpusubtype
,
114 vm_size_t pagesize __KXLD_KERNEL_UNUSED
)
116 kern_return_t rval
= KERN_FAILURE
;
117 KXLDContext
* context
= NULL
;
118 KXLDArray
* section_order
= NULL
;
120 cpu_type_t
* cputype_p
= NULL
;
124 check(allocate_callback
);
125 check(logging_callback
);
128 context
= kxld_alloc(sizeof(*context
));
129 require_action(context
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
130 bzero(context
, sizeof(*context
));
132 context
->flags
= flags
;
133 context
->allocate_callback
= allocate_callback
;
134 context
->cputype
= cputype
;
135 context
->cpusubtype
= cpusubtype
;
139 kxld_set_cross_link_page_size(pagesize
);
143 kxld_set_logging_callback(logging_callback
);
145 context
->kext
= kxld_alloc(kxld_kext_sizeof());
146 require_action(context
->kext
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
147 bzero(context
->kext
, kxld_kext_sizeof());
149 /* Check if we already have an order array for this arch */
151 #if KXLD_USER_OR_OBJECT
153 context
->section_order
= s_section_order
;
155 /* In userspace, create the dictionary if it doesn't already exist */
157 s_order_dict
= kxld_alloc(sizeof(*s_order_dict
));
158 require_action(s_order_dict
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
159 bzero(s_order_dict
, sizeof(*s_order_dict
));
161 rval
= kxld_dict_init(s_order_dict
, kxld_dict_uint32_hash
,
162 kxld_dict_uint32_cmp
, 0);
163 require_noerr(rval
, finish
);
166 context
->section_order
= kxld_dict_find(s_order_dict
, &cputype
);
169 /* Create an order array for this arch if needed */
171 if (!context
->section_order
) {
173 section_order
= kxld_alloc(sizeof(*section_order
));
174 require_action(section_order
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
175 bzero(section_order
, sizeof(*section_order
));
178 s_section_order
= section_order
;
180 /* In userspace, add the new array to the order dictionary */
181 cputype_p
= kxld_alloc(sizeof(*cputype_p
));
182 require_action(cputype_p
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
183 *cputype_p
= cputype
;
185 rval
= kxld_dict_insert(s_order_dict
, cputype_p
, section_order
);
186 require_noerr(rval
, finish
);
191 context
->section_order
= section_order
;
193 section_order
= NULL
;
195 #endif /* KXLD_USER_OR_OBJECT */
202 if (context
) kxld_destroy_context(context
);
203 if (section_order
) kxld_free(section_order
, sizeof(*section_order
));
205 if (cputype_p
) kxld_free(cputype_p
, sizeof(*cputype_p
));
211 /*******************************************************************************
212 *******************************************************************************/
214 kxld_destroy_context(KXLDContext
*context
)
216 KXLDObject
*object
= NULL
;
217 KXLDKext
*dep
= NULL
;
222 kxld_kext_deinit(context
->kext
);
224 for (i
= 0; i
< context
->objects
.maxitems
; ++i
) {
225 object
= kxld_array_get_slot(&context
->objects
, i
);
226 kxld_object_deinit(object
);
228 kxld_array_deinit(&context
->objects
);
230 for (i
= 0; i
< context
->dependencies
.maxitems
; ++i
) {
231 dep
= kxld_array_get_slot(&context
->dependencies
, i
);
232 kxld_kext_deinit(dep
);
234 kxld_array_deinit(&context
->dependencies
);
236 kxld_dict_deinit(&context
->defined_symbols_by_name
);
237 kxld_dict_deinit(&context
->defined_cxx_symbols_by_value
);
238 kxld_dict_deinit(&context
->obsolete_symbols_by_name
);
239 kxld_dict_deinit(&context
->vtables_by_name
);
241 kxld_free(context
->kext
, kxld_kext_sizeof());
242 kxld_free(context
, sizeof(*context
));
244 kxld_print_memory_report();
247 /*******************************************************************************
248 *******************************************************************************/
251 KXLDContext
* context
,
255 void * callback_data
,
256 KXLDDependency
* dependencies
,
258 u_char
** linked_object_out
,
259 kxld_addr_t
* kmod_info_kern
)
261 kern_return_t rval
= KERN_FAILURE
;
262 kxld_addr_t vmaddr
= 0;
264 u_char
* linked_object
= NULL
;
265 u_char
* linked_object_alloc
= NULL
;
267 kxld_set_logging_callback_data(name
, callback_data
);
269 kxld_log(kKxldLogLinking
, kKxldLogBasic
, "Linking kext %s", name
);
271 require_action(context
, finish
, rval
=KERN_INVALID_ARGUMENT
);
272 require_action(file
, finish
, rval
=KERN_INVALID_ARGUMENT
);
273 require_action(size
, finish
, rval
=KERN_INVALID_ARGUMENT
);
274 require_action(dependencies
, finish
, rval
=KERN_INVALID_ARGUMENT
);
275 require_action(ndependencies
, finish
, rval
=KERN_INVALID_ARGUMENT
);
276 require_action(linked_object_out
, finish
, rval
=KERN_INVALID_ARGUMENT
);
277 require_action(kmod_info_kern
, finish
, rval
=KERN_INVALID_ARGUMENT
);
279 rval
= init_context(context
, ndependencies
);
280 require_noerr(rval
, finish
);
282 rval
= init_kext_objects(context
, file
, size
, name
,
283 dependencies
, ndependencies
);
284 require_noerr(rval
, finish
);
286 linked_object
= allocate_kext(context
, callback_data
,
287 &vmaddr
, &vmsize
, &linked_object_alloc
);
288 require_action(linked_object
, finish
, rval
=KERN_RESOURCE_SHORTAGE
);
290 rval
= kxld_kext_relocate(context
->kext
, vmaddr
,
291 &context
->vtables_by_name
,
292 &context
->defined_symbols_by_name
,
293 &context
->obsolete_symbols_by_name
,
294 &context
->defined_cxx_symbols_by_value
);
295 require_noerr(rval
, finish
);
297 rval
= kxld_kext_export_linked_object(context
->kext
,
298 linked_object
, kmod_info_kern
);
299 require_noerr(rval
, finish
);
301 *linked_object_out
= linked_object
;
302 linked_object_alloc
= NULL
;
306 if (linked_object_alloc
) {
307 kxld_page_free_untracked(linked_object_alloc
, vmsize
);
310 clear_context(context
);
311 kxld_set_logging_callback_data(NULL
, NULL
);
316 /*******************************************************************************
317 *******************************************************************************/
319 init_context(KXLDContext
*context
, u_int ndependencies
)
321 kern_return_t rval
= KERN_FAILURE
;
323 /* Create an array of objects large enough to hold an object
324 * for every dependency, an interface for each dependency, and a kext. */
325 rval
= kxld_array_init(&context
->objects
,
326 kxld_object_sizeof(), 2 * ndependencies
+ 1);
327 require_noerr(rval
, finish
);
329 rval
= kxld_array_init(&context
->dependencies
,
330 kxld_kext_sizeof(), ndependencies
);
331 require_noerr(rval
, finish
);
333 rval
= kxld_dict_init(&context
->defined_symbols_by_name
,
334 kxld_dict_string_hash
, kxld_dict_string_cmp
, 0);
335 require_noerr(rval
, finish
);
337 rval
= kxld_dict_init(&context
->defined_cxx_symbols_by_value
,
338 kxld_dict_kxldaddr_hash
, kxld_dict_kxldaddr_cmp
, 0);
339 require_noerr(rval
, finish
);
341 rval
= kxld_dict_init(&context
->obsolete_symbols_by_name
,
342 kxld_dict_string_hash
, kxld_dict_string_cmp
, 0);
343 require_noerr(rval
, finish
);
345 rval
= kxld_dict_init(&context
->vtables_by_name
, kxld_dict_string_hash
,
346 kxld_dict_string_cmp
, 0);
347 require_noerr(rval
, finish
);
354 /*******************************************************************************
355 *******************************************************************************/
357 init_kext_objects(KXLDContext
*context
, u_char
*file
, u_long size
,
358 const char *name
, KXLDDependency
*dependencies
, u_int ndependencies
)
360 kern_return_t rval
= KERN_FAILURE
;
361 KXLDKext
*kext
= NULL
;
362 KXLDObject
*kext_object
= NULL
;
363 KXLDObject
*interface_object
= NULL
;
366 /* Create a kext object for each dependency. If it's a direct dependency,
367 * export its symbols by name by value. If it's indirect, just export the
368 * C++ symbols by value.
370 for (i
= 0; i
< ndependencies
; ++i
) {
371 kext
= kxld_array_get_item(&context
->dependencies
, i
);
373 interface_object
= NULL
;
375 kext_object
= get_object_for_file(context
, dependencies
[i
].kext
,
376 dependencies
[i
].kext_size
, dependencies
[i
].kext_name
);
377 require_action(kext_object
, finish
, rval
=KERN_FAILURE
);
379 if (dependencies
[i
].interface
) {
380 interface_object
= get_object_for_file(context
,
381 dependencies
[i
].interface
, dependencies
[i
].interface_size
,
382 dependencies
[i
].interface_name
);
383 require_action(interface_object
, finish
, rval
=KERN_FAILURE
);
386 rval
= kxld_kext_init(kext
, kext_object
, interface_object
);
387 require_noerr(rval
, finish
);
389 if (dependencies
[i
].is_direct_dependency
) {
390 rval
= kxld_kext_export_symbols(kext
,
391 &context
->defined_symbols_by_name
,
392 &context
->obsolete_symbols_by_name
,
393 &context
->defined_cxx_symbols_by_value
);
394 require_noerr(rval
, finish
);
396 rval
= kxld_kext_export_symbols(kext
,
397 /* defined_symbols */ NULL
, /* obsolete_symbols */ NULL
,
398 &context
->defined_cxx_symbols_by_value
);
399 require_noerr(rval
, finish
);
403 /* Export the vtables for all of the dependencies. */
404 for (i
= 0; i
< context
->dependencies
.nitems
; ++i
) {
405 kext
= kxld_array_get_item(&context
->dependencies
, i
);
407 rval
= kxld_kext_export_vtables(kext
,
408 &context
->defined_cxx_symbols_by_value
,
409 &context
->defined_symbols_by_name
,
410 &context
->vtables_by_name
);
411 require_noerr(rval
, finish
);
414 /* Create a kext object for the kext we're linking and export its locally
415 * defined C++ symbols.
417 kext_object
= get_object_for_file(context
, file
, size
, name
);
418 require_action(kext_object
, finish
, rval
=KERN_FAILURE
);
420 rval
= kxld_kext_init(context
->kext
, kext_object
, /* interface */ NULL
);
421 require_noerr(rval
, finish
);
423 rval
= kxld_kext_export_symbols(context
->kext
,
424 /* defined_symbols */ NULL
, /* obsolete_symbols */ NULL
,
425 &context
->defined_cxx_symbols_by_value
);
426 require_noerr(rval
, finish
);
433 /*******************************************************************************
434 *******************************************************************************/
436 get_object_for_file(KXLDContext
*context
, u_char
*file
, u_long size
,
439 KXLDObject
*rval
= NULL
;
440 KXLDObject
*object
= NULL
;
441 kern_return_t result
= 0;
444 for (i
= 0; i
< context
->objects
.nitems
; ++i
) {
445 object
= kxld_array_get_item(&context
->objects
, i
);
447 if (!kxld_object_get_file(object
)) {
448 result
= kxld_object_init_from_macho(object
, file
, size
, name
,
449 context
->section_order
, context
->cputype
, context
->cpusubtype
, context
->flags
);
450 require_noerr(result
, finish
);
456 if (kxld_object_get_file(object
) == file
) {
466 /*******************************************************************************
467 *******************************************************************************/
469 allocate_kext(KXLDContext
*context
, void *callback_data
,
470 kxld_addr_t
*vmaddr_out
, u_long
*vmsize_out
,
471 u_char
**linked_object_alloc_out
)
473 KXLDAllocateFlags flags
= 0;
474 kxld_addr_t vmaddr
= 0;
476 u_long header_size
= 0;
477 u_char
* linked_object
= NULL
;
479 *linked_object_alloc_out
= NULL
;
481 kxld_kext_get_vmsize(context
->kext
, &header_size
, &vmsize
);
482 vmaddr
= context
->allocate_callback(vmsize
, &flags
, callback_data
);
483 require_action(!(vmaddr
& (kxld_get_effective_page_size()-1)), finish
,
484 kxld_log(kKxldLogLinking
, kKxldLogErr
,
485 "Load address %p is not page-aligned.",
486 (void *) (uintptr_t) vmaddr
));
488 if (flags
& kKxldAllocateWritable
) {
489 linked_object
= (u_char
*) (u_long
) vmaddr
;
491 linked_object
= kxld_page_alloc_untracked(vmsize
);
492 require(linked_object
, finish
);
494 *linked_object_alloc_out
= linked_object
;
497 kxld_kext_set_linked_object_size(context
->kext
, vmsize
);
499 /* Zero out the memory before we fill it. We fill this buffer in a
500 * sparse fashion, and it's simpler to clear it now rather than
501 * track and zero any pieces we didn't touch after we've written
502 * all of the sections to memory.
504 bzero(linked_object
, vmsize
);
505 *vmaddr_out
= vmaddr
;
506 *vmsize_out
= vmsize
;
509 return linked_object
;
512 /*******************************************************************************
513 *******************************************************************************/
515 clear_context(KXLDContext
*context
)
517 KXLDObject
* object
= NULL
;
518 KXLDKext
* dep
= NULL
;
523 kxld_kext_clear(context
->kext
);
525 for (i
= 0; i
< context
->objects
.nitems
; ++i
) {
526 object
= kxld_array_get_item(&context
->objects
, i
);
527 kxld_object_clear(object
);
529 kxld_array_reset(&context
->objects
);
531 for (i
= 0; i
< context
->dependencies
.nitems
; ++i
) {
532 dep
= kxld_array_get_item(&context
->dependencies
, i
);
533 kxld_kext_clear(dep
);
535 kxld_array_reset(&context
->dependencies
);
537 kxld_dict_clear(&context
->defined_symbols_by_name
);
538 kxld_dict_clear(&context
->defined_cxx_symbols_by_value
);
539 kxld_dict_clear(&context
->obsolete_symbols_by_name
);
540 kxld_dict_clear(&context
->vtables_by_name
);