]> git.saurik.com Git - apple/xnu.git/blob - libkern/kxld/kxld_util.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_util.c
1 /*
2 * Copyright (c) 2007-2016 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 <stdarg.h>
29 #include <string.h>
30 #include <mach-o/loader.h>
31 #include <mach-o/nlist.h>
32 #include <mach-o/reloc.h>
33 #if KERNEL
34 #include <kern/kalloc.h>
35 #include <libkern/libkern.h>
36 #include <mach/vm_param.h>
37 #include <vm/vm_kern.h>
38 #else
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <mach/mach_init.h>
42 #include <mach-o/swap.h>
43 #endif
44
45 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
46 #include <AssertMacros.h>
47
48 #include "kxld_util.h"
49
50 #if !KERNEL
51 static void unswap_macho_32(u_char *file, enum NXByteOrder host_order,
52 enum NXByteOrder target_order);
53 static void unswap_macho_64(u_char *file, enum NXByteOrder host_order,
54 enum NXByteOrder target_order);
55 #endif /* !KERNEL */
56
57 #if DEBUG
58 static unsigned long num_allocations = 0;
59 static unsigned long num_frees = 0;
60 static unsigned long bytes_allocated = 0;
61 static unsigned long bytes_freed = 0;
62 #endif
63
64 static KXLDLoggingCallback s_logging_callback = NULL;
65 static char s_callback_name[64] = "internal";
66 static void *s_callback_data = NULL;
67
68 #if !KERNEL
69 static boolean_t s_cross_link_enabled = FALSE;
70 static kxld_size_t s_cross_link_page_size = PAGE_SIZE;
71 #endif
72
73
74 /*******************************************************************************
75 *******************************************************************************/
76 void
77 kxld_set_logging_callback(KXLDLoggingCallback logging_callback)
78 {
79 s_logging_callback = logging_callback;
80 }
81
82 /*******************************************************************************
83 *******************************************************************************/
84 void
85 kxld_set_logging_callback_data(const char *name, void *user_data)
86 {
87 if (name) {
88 (void)strlcpy(s_callback_name, name, sizeof(s_callback_name));
89 /* disallow format strings in the kxld logging callback name */
90 for (size_t i = 0; i < sizeof(s_callback_name); i++) {
91 if (s_callback_name[i] == '%') {
92 s_callback_name[i] = '.';
93 }
94 }
95 } else {
96 (void)strlcpy(s_callback_name, "internal", sizeof(s_callback_name));
97 }
98
99 s_callback_data = user_data;
100 }
101
102 /*******************************************************************************
103 *******************************************************************************/
104 void
105 kxld_log(KXLDLogSubsystem subsystem, KXLDLogLevel level,
106 const char *in_format, ...)
107 {
108 char stack_buffer[256];
109 char *alloc_buffer = NULL;
110 char *format = stack_buffer;
111 u_int length = 0;
112 va_list ap;
113
114 if (s_logging_callback) {
115 length = snprintf(stack_buffer, sizeof(stack_buffer), "kxld[%s]: %s",
116 s_callback_name, in_format);
117
118 if (length >= sizeof(stack_buffer)) {
119 length += 1;
120 alloc_buffer = kxld_alloc(length);
121 if (!alloc_buffer) {
122 return;
123 }
124
125 snprintf(alloc_buffer, length, "kxld[%s]: %s",
126 s_callback_name, in_format);
127 format = alloc_buffer;
128 }
129
130 va_start(ap, in_format);
131 s_logging_callback(subsystem, level, format, ap, s_callback_data);
132 va_end(ap);
133
134 if (alloc_buffer) {
135 kxld_free(alloc_buffer, length);
136 }
137 }
138 }
139
140 /* We'll use kalloc for any page-based allocations under this threshold, and
141 * kmem_alloc otherwise.
142 */
143 #define KALLOC_MAX 16 * 1024
144
145 /*******************************************************************************
146 *******************************************************************************/
147 void *
148 kxld_calloc(size_t size)
149 {
150 void * ptr = NULL;
151
152 #if KERNEL
153 ptr = kalloc(size);
154 if (ptr) {
155 bzero(ptr, size);
156 }
157 #else
158 ptr = calloc(1, size);
159 #endif
160
161 #if DEBUG
162 if (ptr) {
163 ++num_allocations;
164 bytes_allocated += size;
165 }
166 #endif
167
168 return ptr;
169 }
170
171 void *
172 kxld_alloc(size_t size)
173 {
174 void * ptr = NULL;
175
176 #if KERNEL
177 ptr = kalloc(size);
178 #else
179 ptr = malloc(size);
180 #endif
181
182 #if DEBUG
183 if (ptr) {
184 ++num_allocations;
185 bytes_allocated += size;
186 }
187 #endif
188
189 return ptr;
190 }
191
192 /*******************************************************************************
193 *******************************************************************************/
194 void *
195 kxld_page_alloc_untracked(size_t size)
196 {
197 void * ptr = NULL;
198 #if KERNEL
199 kern_return_t rval = 0;
200 vm_offset_t addr = 0;
201 #endif /* KERNEL */
202
203 size = round_page(size);
204
205 #if KERNEL
206 if (size < KALLOC_MAX) {
207 ptr = kalloc(size);
208 } else {
209 rval = kmem_alloc(kernel_map, &addr, size, VM_KERN_MEMORY_OSKEXT);
210 if (!rval) {
211 ptr = (void *) addr;
212 }
213 }
214 if (ptr) {
215 bzero(ptr, size);
216 }
217 #else /* !KERNEL */
218 ptr = calloc(1, size);
219 #endif /* KERNEL */
220
221 return ptr;
222 }
223
224 /*******************************************************************************
225 *******************************************************************************/
226 void *
227 kxld_page_alloc(size_t size)
228 {
229 void * ptr = NULL;
230
231 ptr = kxld_page_alloc_untracked(size);
232 #if DEBUG
233 if (ptr) {
234 ++num_allocations;
235 bytes_allocated += round_page(size);
236 }
237 #endif /* DEBUG */
238
239 return ptr;
240 }
241
242 /*******************************************************************************
243 *******************************************************************************/
244 void *
245 kxld_alloc_pageable(size_t size)
246 {
247 size = round_page(size);
248
249 #if KERNEL
250 kern_return_t rval = 0;
251 vm_offset_t ptr = 0;
252
253 rval = kmem_alloc_pageable(kernel_map, &ptr, size, VM_KERN_MEMORY_OSKEXT);
254 if (rval) {
255 ptr = 0;
256 }
257
258 return (void *) ptr;
259 #else
260 return kxld_page_alloc_untracked(size);
261 #endif
262 }
263
264 /*******************************************************************************
265 *******************************************************************************/
266 void
267 kxld_free(void *ptr, size_t size __unused)
268 {
269 #if DEBUG
270 ++num_frees;
271 bytes_freed += size;
272 #endif
273
274 #if KERNEL
275 kfree(ptr, size);
276 #else
277 free(ptr);
278 #endif
279 }
280
281 /*******************************************************************************
282 *******************************************************************************/
283 void
284 kxld_page_free_untracked(void *ptr, size_t size __unused)
285 {
286 #if KERNEL
287 size = round_page(size);
288
289 if (size < KALLOC_MAX) {
290 kfree(ptr, size);
291 } else {
292 kmem_free(kernel_map, (vm_offset_t) ptr, size);
293 }
294 #else /* !KERNEL */
295 free(ptr);
296 #endif /* KERNEL */
297 }
298
299
300 /*******************************************************************************
301 *******************************************************************************/
302 void
303 kxld_page_free(void *ptr, size_t size)
304 {
305 #if DEBUG
306 ++num_frees;
307 bytes_freed += round_page(size);
308 #endif /* DEBUG */
309 kxld_page_free_untracked(ptr, size);
310 }
311
312 /*******************************************************************************
313 *******************************************************************************/
314 kern_return_t
315 validate_and_swap_macho_32(u_char *file, u_long size
316 #if !KERNEL
317 , enum NXByteOrder host_order
318 #endif /* !KERNEL */
319 )
320 {
321 kern_return_t rval = KERN_FAILURE;
322 struct mach_header *mach_hdr = (struct mach_header *) ((void *) file);
323 struct load_command *load_hdr = NULL;
324 struct segment_command *seg_hdr = NULL;
325 struct section *sects = NULL;
326 struct relocation_info *relocs = NULL;
327 struct symtab_command *symtab_hdr = NULL;
328 struct nlist *symtab = NULL;
329 u_long offset = 0;
330 u_int cmd = 0;
331 u_int cmdsize = 0;
332 u_int i = 0;
333 u_int j = 0;
334 #if !KERNEL
335 boolean_t swap = FALSE;
336 #endif /* !KERNEL */
337
338 check(file);
339 check(size);
340
341 /* Verify that the file is big enough for the mach header */
342 require_action(size >= sizeof(*mach_hdr), finish,
343 rval = KERN_FAILURE;
344 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
345 offset = sizeof(*mach_hdr);
346
347 #if !KERNEL
348 /* Swap the mach header if necessary */
349 if (mach_hdr->magic == MH_CIGAM) {
350 swap = TRUE;
351 (void) swap_mach_header(mach_hdr, host_order);
352 }
353 #endif /* !KERNEL */
354
355 /* Validate the mach_header's magic number */
356 require_action(mach_hdr->magic == MH_MAGIC, finish,
357 rval = KERN_FAILURE;
358 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO
359 "Invalid magic number: 0x%x.", mach_hdr->magic));
360
361 /* If in the running kernel, and asked to validate the kernel
362 * (which is the only file of type MH_EXECUTE we should ever see),
363 * then just assume it's ok or we wouldn't be running to begin with.
364 */
365 #if KERNEL
366 if (mach_hdr->filetype == MH_EXECUTE) {
367 rval = KERN_SUCCESS;
368 goto finish;
369 }
370 #endif /* KERNEL */
371
372 /* Validate and potentially swap the load commands */
373 for (i = 0; i < mach_hdr->ncmds; ++i, offset += cmdsize) {
374 /* Get the load command and size */
375 load_hdr = (struct load_command *) ((void *) (file + offset));
376 cmd = load_hdr->cmd;
377 cmdsize = load_hdr->cmdsize;
378
379 #if !KERNEL
380 if (swap) {
381 cmd = OSSwapInt32(load_hdr->cmd);
382 cmdsize = OSSwapInt32(load_hdr->cmdsize);
383 }
384 #endif /* !KERNEL */
385
386 /* Verify that the file is big enough to contain the load command */
387 require_action(size >= offset + cmdsize, finish,
388 rval = KERN_FAILURE;
389 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
390
391 switch (cmd) {
392 case LC_SEGMENT:
393 /* Get and swap the segment header */
394 seg_hdr = (struct segment_command *) load_hdr;
395 #if !KERNEL
396 if (swap) {
397 swap_segment_command(seg_hdr, host_order);
398 }
399 #endif /* !KERNEL */
400
401 /* Get and swap the section headers */
402 sects = (struct section *) &seg_hdr[1];
403 #if !KERNEL
404 if (swap) {
405 swap_section(sects, seg_hdr->nsects, host_order);
406 }
407 #endif /* !KERNEL */
408
409 /* Ignore segments with no vm size */
410 if (!seg_hdr->vmsize) {
411 continue;
412 }
413
414 /* Verify that the file is big enough for the segment data. */
415 require_action(size >= seg_hdr->fileoff + seg_hdr->filesize, finish,
416 rval = KERN_FAILURE;
417 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
418
419 for (j = 0; j < seg_hdr->nsects; ++j) {
420 /* Verify that, if the section is not to be zero filled on
421 * demand, that file is big enough for the section's data.
422 */
423 require_action((sects[j].flags & S_ZEROFILL) ||
424 (size >= sects[j].offset + sects[j].size), finish,
425 rval = KERN_FAILURE;
426 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
427
428 /* Verify that the file is big enough for the section's
429 * relocation entries.
430 */
431 require_action(size >=
432 sects[j].reloff + sects[j].nreloc * sizeof(*relocs), finish,
433 rval = KERN_FAILURE;
434 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
435
436 /* Swap the relocation entries */
437 relocs = (struct relocation_info *) ((void *) (file + sects[j].reloff));
438 #if !KERNEL
439 if (swap) {
440 swap_relocation_info(relocs, sects[j].nreloc,
441 host_order);
442 }
443 #endif /* !KERNEL */
444 }
445
446 break;
447 case LC_SYMTAB:
448 /* Get and swap the symtab header */
449 symtab_hdr = (struct symtab_command *) load_hdr;
450 #if !KERNEL
451 if (swap) {
452 swap_symtab_command(symtab_hdr, host_order);
453 }
454 #endif /* !KERNEL */
455
456 /* Verify that the file is big enough for the symbol table */
457 require_action(size >=
458 symtab_hdr->symoff + symtab_hdr->nsyms * sizeof(*symtab), finish,
459 rval = KERN_FAILURE;
460 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
461
462 /* Verify that the file is big enough for the string table */
463 require_action(size >= symtab_hdr->stroff + symtab_hdr->strsize, finish,
464 rval = KERN_FAILURE;
465 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
466
467 #if !KERNEL
468 /* Swap the symbol table entries */
469 symtab = (struct nlist *) ((void *) (file + symtab_hdr->symoff));
470 if (swap) {
471 swap_nlist(symtab, symtab_hdr->nsyms, host_order);
472 }
473 #endif /* !KERNEL */
474
475 break;
476 default:
477 #if !KERNEL
478 /* Swap the load command */
479 if (swap) {
480 swap_load_command(load_hdr, host_order);
481 }
482 #endif /* !KERNEL */
483 break;
484 }
485 }
486
487 rval = KERN_SUCCESS;
488
489 finish:
490 return rval;
491 }
492
493 /*******************************************************************************
494 *******************************************************************************/
495 kern_return_t
496 validate_and_swap_macho_64(u_char *file, u_long size
497 #if !KERNEL
498 , enum NXByteOrder host_order
499 #endif /* !KERNEL */
500 )
501 {
502 kern_return_t rval = KERN_FAILURE;
503 struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) file);
504 struct load_command *load_hdr = NULL;
505 struct segment_command_64 *seg_hdr = NULL;
506 struct section_64 *sects = NULL;
507 struct relocation_info *relocs = NULL;
508 struct symtab_command *symtab_hdr = NULL;
509 struct nlist_64 *symtab = NULL;
510 u_long offset = 0;
511 u_int cmd = 0;
512 u_int cmdsize = 0;
513 u_int i = 0;
514 u_int j = 0;
515 #if !KERNEL
516 boolean_t swap = FALSE;
517 #endif /* !KERNEL */
518
519 check(file);
520 check(size);
521
522 /* Verify that the file is big enough for the mach header */
523 require_action(size >= sizeof(*mach_hdr), finish,
524 rval = KERN_FAILURE;
525 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
526 offset = sizeof(*mach_hdr);
527
528 #if !KERNEL
529 /* Swap the mach header if necessary */
530 if (mach_hdr->magic == MH_CIGAM_64) {
531 swap = TRUE;
532 (void) swap_mach_header_64(mach_hdr, host_order);
533 }
534 #endif /* !KERNEL */
535
536 /* Validate the mach_header's magic number */
537 require_action(mach_hdr->magic == MH_MAGIC_64, finish,
538 rval = KERN_FAILURE;
539 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO
540 "Invalid magic number: 0x%x.", mach_hdr->magic));
541
542 /* If in the running kernel, and asked to validate the kernel
543 * (which is the only file of type MH_EXECUTE we should ever see),
544 * then just assume it's ok or we wouldn't be running to begin with.
545 */
546 #if KERNEL
547 if (mach_hdr->filetype == MH_EXECUTE) {
548 rval = KERN_SUCCESS;
549 goto finish;
550 }
551 #endif /* KERNEL */
552
553 /* Validate and potentially swap the load commands */
554 for (i = 0; i < mach_hdr->ncmds; ++i, offset += cmdsize) {
555 /* Get the load command and size */
556 load_hdr = (struct load_command *) ((void *) (file + offset));
557 cmd = load_hdr->cmd;
558 cmdsize = load_hdr->cmdsize;
559
560 #if !KERNEL
561 if (swap) {
562 cmd = OSSwapInt32(load_hdr->cmd);
563 cmdsize = OSSwapInt32(load_hdr->cmdsize);
564 }
565 #endif /* !KERNEL */
566
567 /* Verify that the file is big enough to contain the load command */
568 require_action(size >= offset + cmdsize, finish,
569 rval = KERN_FAILURE;
570 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
571 switch (cmd) {
572 case LC_SEGMENT_64:
573 /* Get and swap the segment header */
574 seg_hdr = (struct segment_command_64 *) ((void *) load_hdr);
575 #if !KERNEL
576 if (swap) {
577 swap_segment_command_64(seg_hdr, host_order);
578 }
579 #endif /* !KERNEL */
580
581 /* Get and swap the section headers */
582 sects = (struct section_64 *) &seg_hdr[1];
583 #if !KERNEL
584 if (swap) {
585 swap_section_64(sects, seg_hdr->nsects, host_order);
586 }
587 #endif /* !KERNEL */
588
589 /* If the segment has no vm footprint, skip it */
590 if (!seg_hdr->vmsize) {
591 continue;
592 }
593
594 /* Verify that the file is big enough for the segment data. */
595 require_action(size >= seg_hdr->fileoff + seg_hdr->filesize, finish,
596 rval = KERN_FAILURE;
597 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
598
599 for (j = 0; j < seg_hdr->nsects; ++j) {
600 /* Verify that, if the section is not to be zero filled on
601 * demand, that file is big enough for the section's data.
602 */
603 require_action((sects[j].flags & S_ZEROFILL) ||
604 (size >= sects[j].offset + sects[j].size), finish,
605 rval = KERN_FAILURE;
606 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
607
608 /* Verify that the file is big enough for the section's
609 * relocation entries.
610 */
611 require_action(size >=
612 sects[j].reloff + sects[j].nreloc * sizeof(*relocs), finish,
613 rval = KERN_FAILURE;
614 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
615
616 /* Swap the relocation entries */
617 relocs = (struct relocation_info *) ((void *) (file + sects[j].reloff));
618 #if !KERNEL
619 if (swap) {
620 swap_relocation_info(relocs, sects[j].nreloc,
621 host_order);
622 }
623 #endif /* !KERNEL */
624 }
625
626 break;
627 case LC_SYMTAB:
628 /* Get and swap the symtab header */
629 symtab_hdr = (struct symtab_command *) load_hdr;
630 #if !KERNEL
631 if (swap) {
632 swap_symtab_command(symtab_hdr, host_order);
633 }
634 #endif /* !KERNEL */
635
636 /* Verify that the file is big enough for the symbol table */
637 require_action(size >=
638 symtab_hdr->symoff + symtab_hdr->nsyms * sizeof(*symtab), finish,
639 rval = KERN_FAILURE;
640 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
641
642 /* Verify that the file is big enough for the string table */
643 require_action(size >= symtab_hdr->stroff + symtab_hdr->strsize, finish,
644 rval = KERN_FAILURE;
645 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO));
646
647 #if !KERNEL
648 /* Swap the symbol table entries */
649 symtab = (struct nlist_64 *) ((void *) (file + symtab_hdr->symoff));
650 if (swap) {
651 swap_nlist_64(symtab, symtab_hdr->nsyms, host_order);
652 }
653 #endif /* !KERNEL */
654
655 break;
656 default:
657 #if !KERNEL
658 /* Swap the load command */
659 if (swap) {
660 swap_load_command(load_hdr, host_order);
661 }
662 #endif /* !KERNEL */
663 break;
664 }
665 }
666
667 rval = KERN_SUCCESS;
668
669 finish:
670 return rval;
671 }
672
673 #if !KERNEL
674 /*******************************************************************************
675 *******************************************************************************/
676 void
677 unswap_macho(u_char *file, enum NXByteOrder host_order,
678 enum NXByteOrder target_order)
679 {
680 struct mach_header *hdr = (struct mach_header *) ((void *) file);
681
682 if (!hdr) {
683 return;
684 }
685
686 if (hdr->magic == MH_MAGIC) {
687 unswap_macho_32(file, host_order, target_order);
688 } else if (hdr->magic == MH_MAGIC_64) {
689 unswap_macho_64(file, host_order, target_order);
690 }
691 }
692
693 /*******************************************************************************
694 *******************************************************************************/
695 static void
696 unswap_macho_32(u_char *file, enum NXByteOrder host_order,
697 enum NXByteOrder target_order)
698 {
699 struct mach_header *mach_hdr = (struct mach_header *) ((void *) file);
700 struct load_command *load_hdr = NULL;
701 struct segment_command *seg_hdr = NULL;
702 struct section *sects = NULL;
703 struct symtab_command *symtab_hdr = NULL;
704 struct nlist *symtab = NULL;
705 u_long offset = 0;
706 u_int cmd = 0;
707 u_int size = 0;
708 u_int i = 0;
709
710 check(file);
711
712 if (target_order == host_order) {
713 return;
714 }
715
716 offset = sizeof(*mach_hdr);
717 for (i = 0; i < mach_hdr->ncmds; ++i, offset += size) {
718 load_hdr = (struct load_command *) ((void *) (file + offset));
719 cmd = load_hdr->cmd;
720 size = load_hdr->cmdsize;
721
722 switch (cmd) {
723 case LC_SEGMENT:
724 seg_hdr = (struct segment_command *) load_hdr;
725 sects = (struct section *) &seg_hdr[1];
726
727 /* We don't need to unswap relocations because this function is
728 * called when linking is completed (so there are no relocations).
729 */
730
731 swap_section(sects, seg_hdr->nsects, target_order);
732 swap_segment_command(seg_hdr, target_order);
733 break;
734 case LC_SYMTAB:
735 symtab_hdr = (struct symtab_command *) load_hdr;
736 symtab = (struct nlist*) ((void *) (file + symtab_hdr->symoff));
737
738 swap_nlist(symtab, symtab_hdr->nsyms, target_order);
739 swap_symtab_command(symtab_hdr, target_order);
740
741 break;
742 default:
743 swap_load_command(load_hdr, target_order);
744 break;
745 }
746 }
747
748 (void) swap_mach_header(mach_hdr, target_order);
749 }
750
751 /*******************************************************************************
752 *******************************************************************************/
753 static void
754 unswap_macho_64(u_char *file, enum NXByteOrder host_order,
755 enum NXByteOrder target_order)
756 {
757 struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) file);
758 struct load_command *load_hdr = NULL;
759 struct segment_command_64 *seg_hdr = NULL;
760 struct section_64 *sects = NULL;
761 struct symtab_command *symtab_hdr = NULL;
762 struct nlist_64 *symtab = NULL;
763 u_long offset = 0;
764 u_int cmd = 0;
765 u_int size = 0;
766 u_int i = 0;
767
768 check(file);
769
770 if (target_order == host_order) {
771 return;
772 }
773
774 offset = sizeof(*mach_hdr);
775 for (i = 0; i < mach_hdr->ncmds; ++i, offset += size) {
776 load_hdr = (struct load_command *) ((void *) (file + offset));
777 cmd = load_hdr->cmd;
778 size = load_hdr->cmdsize;
779
780 switch (cmd) {
781 case LC_SEGMENT_64:
782 seg_hdr = (struct segment_command_64 *) ((void *) load_hdr);
783 sects = (struct section_64 *) &seg_hdr[1];
784
785 /* We don't need to unswap relocations because this function is
786 * called when linking is completed (so there are no relocations).
787 */
788
789 swap_section_64(sects, seg_hdr->nsects, target_order);
790 swap_segment_command_64(seg_hdr, target_order);
791 break;
792 case LC_SYMTAB:
793 symtab_hdr = (struct symtab_command *) load_hdr;
794 symtab = (struct nlist_64 *) ((void *) (file + symtab_hdr->symoff));
795
796 swap_nlist_64(symtab, symtab_hdr->nsyms, target_order);
797 swap_symtab_command(symtab_hdr, target_order);
798
799 break;
800 default:
801 swap_load_command(load_hdr, target_order);
802 break;
803 }
804 }
805
806 (void) swap_mach_header_64(mach_hdr, target_order);
807 }
808 #endif /* !KERNEL */
809
810 /*******************************************************************************
811 *******************************************************************************/
812 kxld_addr_t
813 kxld_align_address(kxld_addr_t address, u_int align)
814 {
815 kxld_addr_t alignment = (1 << align);
816 kxld_addr_t low_bits = 0;
817
818 if (!align) {
819 return address;
820 }
821
822 low_bits = (address) & (alignment - 1);
823 if (low_bits) {
824 address += (alignment - low_bits);
825 }
826
827 return address;
828 }
829
830 /*******************************************************************************
831 *******************************************************************************/
832 boolean_t
833 kxld_is_32_bit(cpu_type_t cputype)
834 {
835 return !(cputype & CPU_ARCH_ABI64);
836 }
837
838 /*******************************************************************************
839 * Borrowed (and slightly modified) the libc implementation for the kernel
840 * until the kernel has a supported strstr().
841 * Find the first occurrence of find in s.
842 *******************************************************************************/
843 const char *
844 kxld_strstr(const char *s, const char *find)
845 {
846 #if KERNEL
847 char c, sc;
848 size_t len;
849 if (!s || !find) {
850 return s;
851 }
852 if ((c = *find++) != 0) {
853 len = strlen(find);
854 do {
855 do {
856 if ((sc = *s++) == 0) {
857 return NULL;
858 }
859 } while (sc != c);
860 } while (strncmp(s, find, len) != 0);
861 s--;
862 }
863 return s;
864 #else
865 return strstr(s, find);
866 #endif /* KERNEL */
867 }
868
869 /*******************************************************************************
870 *******************************************************************************/
871 void
872 kxld_print_memory_report(void)
873 {
874 #if DEBUG
875 kxld_log(kKxldLogLinking, kKxldLogExplicit, "kxld memory usage report:\n"
876 "\tNumber of allocations: %8lu\n"
877 "\tNumber of frees: %8lu\n"
878 "\tAverage allocation size: %8lu\n"
879 "\tTotal bytes allocated: %8lu\n"
880 "\tTotal bytes freed: %8lu\n"
881 "\tTotal bytes leaked: %8lu",
882 num_allocations, num_frees, bytes_allocated / num_allocations,
883 bytes_allocated, bytes_freed, bytes_allocated - bytes_freed);
884 #endif
885 }
886
887 /*********************************************************************
888 *********************************************************************/
889 #if !KERNEL
890 boolean_t
891 kxld_set_cross_link_page_size(kxld_size_t target_page_size)
892 {
893 // verify radix 2
894 if ((target_page_size != 0) &&
895 ((target_page_size & (target_page_size - 1)) == 0)) {
896 s_cross_link_enabled = TRUE;
897 s_cross_link_page_size = target_page_size;
898
899 return TRUE;
900 } else {
901 return FALSE;
902 }
903 }
904 #endif /* !KERNEL */
905
906 /*********************************************************************
907 *********************************************************************/
908 kxld_size_t
909 kxld_get_effective_page_size(void)
910 {
911 #if KERNEL
912 return PAGE_SIZE;
913 #else
914 if (s_cross_link_enabled) {
915 return s_cross_link_page_size;
916 } else {
917 return PAGE_SIZE;
918 }
919 #endif /* KERNEL */
920 }
921
922 /*********************************************************************
923 *********************************************************************/
924 kxld_addr_t
925 kxld_round_page_cross_safe(kxld_addr_t offset)
926 {
927 #if KERNEL
928 return round_page(offset);
929 #else
930 // assume s_cross_link_page_size is power of 2
931 if (s_cross_link_enabled) {
932 return (offset + (s_cross_link_page_size - 1)) &
933 (~(s_cross_link_page_size - 1));
934 } else {
935 return round_page(offset);
936 }
937 #endif /* KERNEL */
938 }
939
940 #if SPLIT_KEXTS_DEBUG
941
942 void
943 kxld_show_split_info(splitKextLinkInfo *info)
944 {
945 kxld_log(kKxldLogLinking, kKxldLogErr,
946 "splitKextLinkInfo: \n"
947 "kextExecutable %p to %p kextSize %lu \n"
948 "linkedKext %p to %p linkedKextSize %lu \n"
949 "vmaddr_TEXT %p vmaddr_TEXT_EXEC %p "
950 "vmaddr_DATA %p vmaddr_DATA_CONST %p "
951 "vmaddr_LLVM_COV %p vmaddr_LINKEDIT %p",
952 (void *) info->kextExecutable,
953 (void *) (info->kextExecutable + info->kextSize),
954 info->kextSize,
955 (void*) info->linkedKext,
956 (void*) (info->linkedKext + info->linkedKextSize),
957 info->linkedKextSize,
958 (void *) info->vmaddr_TEXT,
959 (void *) info->vmaddr_TEXT_EXEC,
960 (void *) info->vmaddr_DATA,
961 (void *) info->vmaddr_DATA_CONST,
962 (void *) info->vmaddr_LLVM_COV,
963 (void *) info->vmaddr_LINKEDIT);
964 }
965
966 boolean_t
967 isTargetKextName(const char * the_name)
968 {
969 if (the_name && 0 == strcmp(the_name, KXLD_TARGET_KEXT)) {
970 return TRUE;
971 }
972 return FALSE;
973 }
974 #endif