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