The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libkern/kxld/kxld_reloc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 <string.h>
   29 #include <mach/boolean.h>
   30 #include <mach/machine.h>
   31 #include <sys/types.h>
   32 
   33 #if KERNEL
   34     #include <libkern/libkern.h>
   35 #else
   36     #include <libkern/OSByteOrder.h>
   37     #include <stdlib.h>
   38 #endif
   39 
   40 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
   41 #include <AssertMacros.h>
   42 
   43 #include "kxld_array.h"
   44 #include "kxld_reloc.h"
   45 #include "kxld_sect.h"
   46 #include "kxld_seg.h"
   47 #include "kxld_sym.h"
   48 #include "kxld_symtab.h"
   49 #include "kxld_util.h"
   50 
   51 /* include target-specific relocation prototypes */
   52 #include <mach-o/reloc.h>
   53 #if KXLD_USER_OR_PPC
   54 #include <mach-o/ppc/reloc.h>
   55 #endif
   56 #if KXLD_USER_OR_X86_64
   57 #include <mach-o/x86_64/reloc.h>
   58 #endif
   59 #if KXLD_USER_OR_ARM
   60 #include <mach-o/arm/reloc.h>
   61 #endif
   62 
   63 #define KXLD_TARGET_NONE        (u_int) 0x0
   64 #define KXLD_TARGET_VALUE       (u_int) 0x1
   65 #define KXLD_TARGET_SECTNUM     (u_int) 0x2
   66 #define KXLD_TARGET_SYMBOLNUM   (u_int) 0x3
   67 #define KXLD_TARGET_LOOKUP      (u_int) 0x4
   68 #define KXLD_TARGET_GOT         (u_int) 0x5
   69 
   70 #define ABSOLUTE_VALUE(x) (((x) < 0) ? -(x) : (x))
   71 
   72 #define LO16(x) (0x0000FFFF & x)
   73 #define LO16S(x) ((0x0000FFFF & x) << 16)
   74 #define HI16(x) (0xFFFF0000 & x)
   75 #define HI16S(x) ((0xFFFF0000 & x) >> 16)
   76 #define BIT15(x) (0x00008000 & x)
   77 #define BR14I(x) (0xFFFF0003 & x)
   78 #define BR14D(x) (0x0000FFFC & x)
   79 #define BR24I(x) (0xFC000003 & x)
   80 #define BR24D(x) (0x03FFFFFC & x)
   81 #define HADISP 0x00010000
   82 #define BR14_LIMIT 0x00008000
   83 #define BR24_LIMIT 0x02000000
   84 #define IS_COND_BR_INSTR(x) ((x & 0xFC000000) == 0x40000000)
   85 #define IS_NOT_ALWAYS_TAKEN(x) ((x & 0x03E00000) != 0x02800000)
   86 #define FLIP_PREDICT_BIT(x) x ^= 0x00200000
   87 
   88 #define SIGN_EXTEND_MASK(n) (1 << ((n) - 1))
   89 #define SIGN_EXTEND(x,n) (((x) ^ SIGN_EXTEND_MASK(n)) - SIGN_EXTEND_MASK(n))
   90 #define BR14_NBITS_DISPLACEMENT 16
   91 #define BR24_NBITS_DISPLACEMENT 26
   92 
   93 #define X86_64_RIP_RELATIVE_LIMIT 0x80000000UL
   94 
   95 /*******************************************************************************
   96 * Prototypes
   97 *******************************************************************************/
   98 #if KXLD_USER_OR_I386
   99 static boolean_t generic_reloc_has_pair(u_int _type) 
  100     __attribute__((const));
  101 static boolean_t generic_reloc_is_pair(u_int _type, u_int _prev_type)
  102     __attribute__((const));
  103 static boolean_t generic_reloc_has_got(u_int _type)
  104     __attribute__((const));
  105 static kern_return_t generic_process_reloc(u_char *instruction, u_int length, 
  106     u_int pcrel, kxld_addr_t base_pc, kxld_addr_t link_pc, kxld_addr_t link_disp,
  107     u_int type, kxld_addr_t target, kxld_addr_t pair_target, boolean_t swap);
  108 #endif /* KXLD_USER_OR_I386 */
  109 
  110 #if KXLD_USER_OR_PPC 
  111 static boolean_t ppc_reloc_has_pair(u_int _type) 
  112     __attribute__((const));
  113 static boolean_t ppc_reloc_is_pair(u_int _type, u_int _prev_type) 
  114     __attribute__((const));
  115 static boolean_t ppc_reloc_has_got(u_int _type)
  116     __attribute__((const));
  117 static kern_return_t ppc_process_reloc(u_char *instruction, u_int length, 
  118     u_int pcrel, kxld_addr_t base_pc, kxld_addr_t link_pc, kxld_addr_t link_disp,
  119     u_int type, kxld_addr_t target, kxld_addr_t pair_target, boolean_t swap);
  120 #endif /* KXLD_USER_OR_PPC */
  121 
  122 #if KXLD_USER_OR_X86_64 
  123 static boolean_t x86_64_reloc_has_pair(u_int _type) 
  124     __attribute__((const));
  125 static boolean_t x86_64_reloc_is_pair(u_int _type, u_int _prev_type) 
  126     __attribute__((const));
  127 static boolean_t x86_64_reloc_has_got(u_int _type)
  128     __attribute__((const));
  129 static kern_return_t x86_64_process_reloc(u_char *instruction, u_int length, 
  130     u_int pcrel, kxld_addr_t base_pc, kxld_addr_t link_pc, kxld_addr_t link_disp,
  131     u_int type, kxld_addr_t target, kxld_addr_t pair_target, boolean_t swap);
  132 static kern_return_t calculate_displacement_x86_64(uint64_t target, 
  133     uint64_t adjustment, int32_t *instr32);
  134 #endif /* KXLD_USER_OR_X86_64 */
  135 
  136 #if KXLD_USER_OR_ARM
  137 static boolean_t arm_reloc_has_pair(u_int _type) 
  138     __attribute__((const));
  139 static boolean_t arm_reloc_is_pair(u_int _type, u_int _prev_type) 
  140     __attribute__((const));
  141 static boolean_t arm_reloc_has_got(u_int _type)
  142     __attribute__((const));
  143 static kern_return_t arm_process_reloc(u_char *instruction, u_int length, 
  144     u_int pcrel, kxld_addr_t base_pc, kxld_addr_t link_pc, kxld_addr_t link_disp,
  145     u_int type, kxld_addr_t target, kxld_addr_t pair_target, boolean_t swap);
  146 #endif /* KXLD_USER_OR_ARM */
  147 
  148 #if KXLD_USER_OR_ILP32
  149 static kxld_addr_t get_pointer_at_addr_32(u_char *data, u_long offset,
  150     const KXLDRelocator *relocator __unused)
  151     __attribute__((pure, nonnull));
  152 #endif /* KXLD_USER_OR_ILP32 */
  153 #if KXLD_USER_OR_LP64
  154 static kxld_addr_t get_pointer_at_addr_64(u_char *data, u_long offset,
  155     const KXLDRelocator *relocator __unused)
  156     __attribute__((pure, nonnull));
  157 #endif /* KXLD_USER_OR_LP64 */
  158 
  159 static u_int count_relocatable_relocs(const KXLDRelocator *relocator, 
  160     const struct relocation_info *relocs, u_int nrelocs)
  161     __attribute__((pure));
  162 
  163 static kern_return_t calculate_targets(kxld_addr_t *_target, 
  164     kxld_addr_t *_pair_target, const KXLDReloc *reloc, 
  165     const KXLDArray *sectarray, const KXLDSymtab *symtab);
  166 static kern_return_t get_target_by_address_lookup(kxld_addr_t *target, 
  167     kxld_addr_t addr, const KXLDArray *sectarray);
  168 
  169 /*******************************************************************************
  170 *******************************************************************************/
  171 kern_return_t 
  172 kxld_relocator_init(KXLDRelocator *relocator, cpu_type_t cputype, 
  173     cpu_subtype_t cpusubtype __unused, boolean_t swap)
  174 {
  175     kern_return_t rval = KERN_FAILURE;
  176 
  177     check(relocator);
  178     
  179     switch(cputype) {
  180 #if KXLD_USER_OR_I386
  181     case CPU_TYPE_I386:
  182         relocator->reloc_has_pair = generic_reloc_has_pair;
  183         relocator->reloc_is_pair = generic_reloc_is_pair;
  184         relocator->reloc_has_got = generic_reloc_has_got;
  185         relocator->process_reloc = generic_process_reloc;
  186         relocator->is_32_bit = TRUE;
  187         break;
  188 #endif /* KXLD_USER_OR_I386 */
  189 #if KXLD_USER_OR_PPC
  190     case CPU_TYPE_POWERPC:
  191         relocator->reloc_has_pair = ppc_reloc_has_pair;
  192         relocator->reloc_is_pair = ppc_reloc_is_pair;
  193         relocator->reloc_has_got = ppc_reloc_has_got;
  194         relocator->process_reloc = ppc_process_reloc;
  195         relocator->is_32_bit = TRUE;
  196         break;
  197 #endif /* KXLD_USER_OR_PPC */
  198 #if KXLD_USER_OR_X86_64
  199     case CPU_TYPE_X86_64:
  200         relocator->reloc_has_pair = x86_64_reloc_has_pair;
  201         relocator->reloc_is_pair = x86_64_reloc_is_pair;
  202         relocator->reloc_has_got = x86_64_reloc_has_got;
  203         relocator->process_reloc = x86_64_process_reloc;
  204         relocator->is_32_bit = FALSE;
  205         break;
  206 #endif /* KXLD_USER_OR_X86_64 */
  207 #if KXLD_USER_OR_ARM
  208     case CPU_TYPE_ARM:
  209         relocator->reloc_has_pair = arm_reloc_has_pair;
  210         relocator->reloc_is_pair = arm_reloc_is_pair;
  211         relocator->reloc_has_got = arm_reloc_has_got;
  212         relocator->process_reloc = arm_process_reloc;
  213         relocator->is_32_bit = TRUE;
  214         break;
  215 #endif /* KXLD_USER_OR_ARM */
  216     default:
  217         rval = KERN_FAILURE;
  218         kxld_log(kKxldLogLinking, kKxldLogErr,
  219             kKxldLogArchNotSupported, cputype);
  220         goto finish;
  221     }
  222 
  223     relocator->is_32_bit = kxld_is_32_bit(cputype);
  224     relocator->swap = swap;
  225 
  226     rval = KERN_SUCCESS;
  227 
  228 finish:
  229     return rval;
  230 }
  231 
  232 /*******************************************************************************
  233 *******************************************************************************/
  234 kern_return_t
  235 kxld_reloc_create_macho(KXLDArray *relocarray, const KXLDRelocator *relocator, 
  236     const struct relocation_info *srcs, u_int nsrcs)
  237 {
  238     kern_return_t rval = KERN_FAILURE;
  239     KXLDReloc *reloc = NULL;
  240     u_int nrelocs = 0;
  241     const struct relocation_info *src = NULL, *prev_src = NULL;
  242     const struct scattered_relocation_info *scatsrc = NULL, *prev_scatsrc = NULL;
  243     u_int i = 0;
  244     u_int reloc_index = 0;
  245 
  246     check(relocarray);
  247     check(srcs);
  248 
  249     /* If there are no relocation entries, just return */
  250     if (!nsrcs) {
  251         rval = KERN_SUCCESS;
  252         goto finish;
  253     }
  254 
  255     /* Count the number of non-pair relocs */
  256     nrelocs = count_relocatable_relocs(relocator, srcs, nsrcs);
  257 
  258     if (nrelocs) {
  259 
  260         /* Allocate the array of relocation entries */
  261 
  262         rval = kxld_array_init(relocarray, sizeof(KXLDReloc), nrelocs);
  263         require_noerr(rval, finish);
  264 
  265         /* Initialize the relocation entries */
  266         
  267         for (i = 0; i < nsrcs; ++i) {
  268             src = srcs + i;
  269             scatsrc = (const struct scattered_relocation_info *) src;
  270 
  271             /* A section-based relocation entry can be skipped for absolute 
  272              * symbols.
  273              */
  274 
  275             if (!(src->r_address & R_SCATTERED) && !(src->r_extern) && 
  276                 (R_ABS == src->r_symbolnum))
  277             {
  278                 continue;
  279             }
  280             
  281             /* Pull out the data from the relocation entries.  The target_type
  282              * depends on the r_extern bit:
  283              *  Scattered -> Section Lookup by Address
  284              *  Local (not extern) -> Section by Index
  285              *  Extern -> Symbolnum by Index
  286              */
  287             reloc = kxld_array_get_item(relocarray, reloc_index++);
  288             if (src->r_address & R_SCATTERED) {
  289                 reloc->address = scatsrc->r_address;
  290                 reloc->pcrel = scatsrc->r_pcrel;
  291                 reloc->length = scatsrc->r_length;
  292                 reloc->reloc_type = scatsrc->r_type;
  293                 reloc->target = scatsrc->r_value;
  294                 reloc->target_type = KXLD_TARGET_LOOKUP;
  295             } else {
  296                 reloc->address = src->r_address;
  297                 reloc->pcrel = src->r_pcrel;
  298                 reloc->length = src->r_length;
  299                 reloc->reloc_type = src->r_type;
  300                 reloc->target = src->r_symbolnum;
  301 
  302                 if (0 == src->r_extern) {
  303                     reloc->target_type = KXLD_TARGET_SECTNUM;
  304                     reloc->target -= 1;
  305                 } else {
  306                     reloc->target_type = KXLD_TARGET_SYMBOLNUM;
  307                 }
  308             }
  309             
  310             /* Find the pair entry if it exists */
  311 
  312             if (relocator->reloc_has_pair(reloc->reloc_type)) {
  313                 ++i;
  314                 require_action(i < nsrcs, finish, rval=KERN_FAILURE);
  315 
  316                 prev_src = src;
  317                 src = srcs + i;
  318                 prev_scatsrc = (const struct scattered_relocation_info *) prev_src;
  319                 scatsrc = (const struct scattered_relocation_info *) src;
  320                  
  321                 if (src->r_address & R_SCATTERED) {
  322                     require_action(relocator->reloc_is_pair(
  323                         scatsrc->r_type, reloc->reloc_type), 
  324                         finish, rval=KERN_FAILURE);
  325                     reloc->pair_target = scatsrc->r_value;
  326                     reloc->pair_target_type = KXLD_TARGET_LOOKUP;
  327                 } else {
  328                     require_action(relocator->reloc_is_pair(src->r_type, 
  329                         reloc->reloc_type), finish, rval=KERN_FAILURE);
  330 
  331                     if (src->r_extern) {
  332                         reloc->pair_target = src->r_symbolnum;
  333                         reloc->pair_target_type = KXLD_TARGET_SYMBOLNUM;
  334                     } else {
  335                         reloc->pair_target = src->r_address;
  336                         reloc->pair_target_type = KXLD_TARGET_VALUE;
  337                     }
  338                 }
  339             } else {
  340                 reloc->pair_target = 0;
  341                 if (relocator->reloc_has_got(reloc->reloc_type)) {
  342                    reloc->pair_target_type = KXLD_TARGET_GOT;
  343                 } else {
  344                    reloc->pair_target_type = KXLD_TARGET_NONE;
  345                 }
  346             }
  347         }
  348     }
  349 
  350     rval = KERN_SUCCESS;
  351 
  352 finish:
  353     return rval;
  354 }
  355 
  356 
  357 /*******************************************************************************
  358 * Relocatable relocs :
  359 *   1) Are not _PAIR_ relocs
  360 *   2) Don't reference N_ABS symbols
  361 *******************************************************************************/
  362 static u_int
  363 count_relocatable_relocs(const KXLDRelocator *relocator, 
  364     const struct relocation_info *relocs, u_int nrelocs)
  365 {
  366     u_int num_nonpair_relocs = 0;
  367     u_int i = 0;
  368     u_int prev_type = 0;
  369     const struct relocation_info *reloc = NULL;
  370     const struct scattered_relocation_info *sreloc = NULL;
  371 
  372     check(relocator);
  373     check(relocs);
  374 
  375     /* Loop over all of the relocation entries */
  376 
  377     num_nonpair_relocs = 1;
  378     prev_type = relocs->r_type;
  379     for (i = 1; i < nrelocs; ++i) {
  380         reloc = relocs + i;
  381 
  382         if (reloc->r_address & R_SCATTERED) {
  383             /* A scattered relocation entry is relocatable as long as it's not a
  384              * pair.
  385              */
  386             sreloc = (const struct scattered_relocation_info *) reloc;
  387 
  388             num_nonpair_relocs += 
  389                 (!relocator->reloc_is_pair(sreloc->r_type, prev_type));
  390 
  391             prev_type = sreloc->r_type;
  392         } else {
  393             /* A normal relocation entry is relocatable if it is not a pair and
  394              * if it is not a section-based relocation for an absolute symbol.
  395              */
  396             num_nonpair_relocs += 
  397                 !(relocator->reloc_is_pair(reloc->r_type, prev_type)
  398                  || (0 == reloc->r_extern && R_ABS == reloc->r_symbolnum));
  399 
  400             prev_type = reloc->r_type;
  401         }
  402 
  403     }
  404     
  405     return num_nonpair_relocs;
  406 }
  407 
  408 /*******************************************************************************
  409 *******************************************************************************/
  410 void
  411 kxld_relocator_clear(KXLDRelocator *relocator)
  412 {
  413     bzero(relocator, sizeof(*relocator));
  414 }
  415 
  416 /*******************************************************************************
  417 *******************************************************************************/
  418 boolean_t 
  419 kxld_relocator_has_pair(const KXLDRelocator *relocator, u_int r_type)
  420 {
  421     check(relocator);
  422 
  423     return relocator->reloc_has_pair(r_type);
  424 }
  425 
  426 /*******************************************************************************
  427 *******************************************************************************/
  428 boolean_t 
  429 kxld_relocator_is_pair(const KXLDRelocator *relocator, u_int r_type, 
  430     u_int prev_r_type)
  431 {
  432     check(relocator);
  433 
  434     return relocator->reloc_is_pair(r_type, prev_r_type);
  435 }
  436 
  437 /*******************************************************************************
  438 *******************************************************************************/
  439 boolean_t 
  440 kxld_relocator_has_got(const KXLDRelocator *relocator, u_int r_type)
  441 {
  442     check(relocator);
  443 
  444     return relocator->reloc_has_got(r_type);
  445 }
  446 
  447 /*******************************************************************************
  448 *******************************************************************************/
  449 KXLDSym *
  450 kxld_reloc_get_symbol(const KXLDRelocator *relocator, const KXLDReloc *reloc, 
  451     u_char *data, const KXLDSymtab *symtab)
  452 {
  453     KXLDSym *sym = NULL;
  454     kxld_addr_t value = 0;
  455 
  456     check(reloc);
  457     check(symtab);
  458 
  459     switch (reloc->target_type) {
  460     case KXLD_TARGET_SYMBOLNUM:
  461         sym = kxld_symtab_get_symbol_by_index(symtab, reloc->target);
  462         break;
  463     case KXLD_TARGET_SECTNUM:
  464         if (data) {
  465             KXLD_3264_FUNC(relocator->is_32_bit, value,
  466                 get_pointer_at_addr_32, get_pointer_at_addr_64,
  467                 data, reloc->address, relocator);
  468             sym = kxld_symtab_get_cxx_symbol_by_value(symtab, value);           
  469         }
  470         break;
  471     default:
  472         sym = NULL;
  473         break;
  474     }
  475 
  476     return sym;
  477 }
  478 
  479 /*******************************************************************************
  480 *******************************************************************************/
  481 kern_return_t
  482 kxld_reloc_get_reloc_index_by_offset(const KXLDArray *relocs, 
  483     kxld_size_t offset, u_int *idx)
  484 {
  485     kern_return_t rval = KERN_FAILURE;
  486     KXLDReloc *reloc = NULL;
  487     u_int i = 0;
  488 
  489     for (i = 0; i < relocs->nitems; ++i) {
  490         reloc = kxld_array_get_item(relocs, i);
  491         if (reloc->address == offset) break;
  492     }
  493     
  494     if (i >= relocs->nitems) {
  495         rval = KERN_FAILURE;
  496         goto finish;
  497     }
  498 
  499     *idx = i;
  500     rval = KERN_SUCCESS;
  501 
  502 finish:
  503     return rval;
  504 }
  505 
  506 /*******************************************************************************
  507 *******************************************************************************/
  508 KXLDReloc *
  509 kxld_reloc_get_reloc_by_offset(const KXLDArray *relocs, kxld_addr_t offset)
  510 {
  511     kern_return_t rval = KERN_FAILURE;
  512     KXLDReloc *reloc = NULL;
  513     u_int i = 0;
  514 
  515     rval = kxld_reloc_get_reloc_index_by_offset(relocs, offset, &i);
  516     if (rval) goto finish;
  517 
  518     reloc = kxld_array_get_item(relocs, i);
  519     
  520 finish:
  521     return reloc;
  522 }
  523 
  524 #if KXLD_USER_OR_ILP32
  525 /*******************************************************************************
  526 *******************************************************************************/
  527 static kxld_addr_t
  528 get_pointer_at_addr_32(u_char *data, u_long offset,
  529     const KXLDRelocator *relocator __unused)
  530 {
  531     uint32_t addr = 0;
  532     
  533     check(relocator);
  534     check(data);
  535 
  536     addr = *(uint32_t *) (data + offset);
  537 #if !KERNEL
  538     if (relocator->swap) {
  539         addr = OSSwapInt32(addr);
  540     }
  541 #endif
  542 
  543     return (kxld_addr_t) addr;
  544 }
  545 #endif /* KXLD_USER_OR_ILP32 */
  546 
  547 #if KXLD_USER_OR_LP64
  548 /*******************************************************************************
  549 *******************************************************************************/
  550 static kxld_addr_t
  551 get_pointer_at_addr_64(u_char *data, u_long offset,
  552     const KXLDRelocator *relocator __unused)
  553 {
  554     uint64_t addr = 0;
  555     
  556     check(relocator);
  557     check(data);
  558 
  559     addr = *(uint64_t *) (data + offset);
  560 #if !KERNEL
  561     if (relocator->swap) {
  562         addr = OSSwapInt64(addr);
  563     }
  564 #endif
  565 
  566     return (kxld_addr_t) addr;
  567 }
  568 #endif /* KXLD_USER_OR_LP64 */
  569 
  570 /*******************************************************************************
  571 *******************************************************************************/
  572 kern_return_t 
  573 kxld_relocator_process_sect_reloc(const KXLDRelocator *relocator,
  574     const KXLDReloc *reloc, const struct kxld_sect *sect,
  575     const KXLDArray *sectarray, const struct kxld_symtab *symtab)
  576 {
  577     kern_return_t rval = KERN_FAILURE;
  578     u_char *instruction = NULL;
  579     kxld_addr_t target = 0;
  580     kxld_addr_t pair_target = 0;
  581     kxld_addr_t base_pc = 0;
  582     kxld_addr_t link_pc = 0;
  583     kxld_addr_t link_disp = 0;
  584 
  585     check(relocator);
  586     check(reloc);
  587     check(sect);
  588     check(sectarray);
  589     check(symtab);
  590 
  591     /* Find the instruction */
  592 
  593     instruction = sect->data + reloc->address;
  594 
  595     /* Calculate the target */
  596 
  597     rval = calculate_targets(&target, &pair_target, reloc, sectarray, symtab);
  598     require_noerr(rval, finish);
  599 
  600     base_pc = reloc->address;
  601     link_pc = base_pc + sect->link_addr;
  602     link_disp = sect->link_addr - sect->base_addr;
  603 
  604     /* Relocate */
  605 
  606     rval = relocator->process_reloc(instruction, reloc->length, reloc->pcrel,
  607         base_pc, link_pc, link_disp, reloc->reloc_type, target, pair_target, 
  608         relocator->swap);
  609     require_noerr(rval, finish);
  610     
  611     /* Return */
  612 
  613     rval = KERN_SUCCESS;
  614 
  615 finish:
  616     return rval;
  617 }
  618 
  619 /*******************************************************************************
  620 *******************************************************************************/
  621 kern_return_t 
  622 kxld_reloc_update_symindex(KXLDReloc *reloc, u_int symindex)
  623 {
  624     kern_return_t rval = KERN_FAILURE;
  625 
  626     require_action(reloc->target_type == KXLD_TARGET_SYMBOLNUM, 
  627         finish, rval = KERN_FAILURE);
  628 
  629     reloc->target = symindex;
  630 
  631     rval = KERN_SUCCESS;
  632 
  633 finish:
  634     return rval;
  635 }
  636 
  637 /*******************************************************************************
  638 *******************************************************************************/
  639 kern_return_t 
  640 kxld_relocator_process_table_reloc(const KXLDRelocator *relocator,
  641     const KXLDReloc *reloc, const KXLDSeg *seg, u_char *file, 
  642     const struct kxld_array *sectarray, const struct kxld_symtab *symtab)
  643 {
  644     kern_return_t rval = KERN_FAILURE;
  645     u_char *instruction = NULL;
  646     kxld_addr_t target = 0;
  647     kxld_addr_t pair_target = 0;
  648     kxld_addr_t base_pc = 0;
  649     kxld_addr_t link_pc = 0;
  650     kxld_addr_t link_disp = 0;
  651 
  652     check(relocator);
  653     check(reloc);
  654     check(file);
  655     check(sectarray);
  656     check(symtab);
  657 
  658     /* Find the instruction */
  659 
  660     instruction = file + seg->fileoff + reloc->address;
  661 
  662     /* Calculate the target */
  663 
  664     rval = calculate_targets(&target, &pair_target, reloc, sectarray, symtab);
  665     require_noerr(rval, finish);
  666 
  667     base_pc = reloc->address;
  668     link_pc = base_pc + seg->link_addr;
  669     link_disp = seg->link_addr - seg->base_addr;
  670 
  671     /* Relocate */
  672 
  673     rval = relocator->process_reloc(instruction, reloc->length, reloc->pcrel,
  674         base_pc, link_pc, link_disp, reloc->reloc_type, target, pair_target, 
  675         relocator->swap);
  676     require_noerr(rval, finish);
  677     
  678     /* Return */
  679 
  680     rval = KERN_SUCCESS;
  681 
  682 finish:
  683     return rval;
  684 }
  685 
  686 /*******************************************************************************
  687 *******************************************************************************/
  688 static kern_return_t
  689 calculate_targets(kxld_addr_t *_target, kxld_addr_t *_pair_target,
  690     const KXLDReloc *reloc, const KXLDArray *sectarray, const KXLDSymtab *symtab)
  691 {
  692     kern_return_t rval = KERN_FAILURE;
  693     const KXLDSect *sect = NULL;
  694     const KXLDSym *sym = NULL;
  695     kxld_addr_t target = 0;
  696     kxld_addr_t pair_target = 0;
  697 
  698     check(_target);
  699     check(_pair_target);
  700     check(sectarray);
  701     check(symtab);
  702     *_target = 0;
  703     *_pair_target = 0;
  704 
  705     /* Find the target based on the lookup type */
  706 
  707     switch(reloc->target_type) {
  708     case KXLD_TARGET_LOOKUP:
  709         require_action(reloc->pair_target_type == KXLD_TARGET_NONE ||
  710             reloc->pair_target_type == KXLD_TARGET_LOOKUP ||
  711             reloc->pair_target_type == KXLD_TARGET_VALUE,
  712             finish, rval=KERN_FAILURE);
  713 
  714         rval = get_target_by_address_lookup(&target, reloc->target, sectarray);
  715         require_noerr(rval, finish);
  716 
  717         if (reloc->pair_target_type == KXLD_TARGET_LOOKUP) {
  718             rval = get_target_by_address_lookup(&pair_target,
  719                 reloc->pair_target, sectarray);
  720             require_noerr(rval, finish);
  721         } else if (reloc->pair_target_type == KXLD_TARGET_VALUE) {
  722             pair_target = reloc->pair_target;
  723         }
  724         break;
  725     case KXLD_TARGET_SECTNUM:
  726         require_action(reloc->pair_target_type == KXLD_TARGET_NONE ||
  727             reloc->pair_target_type == KXLD_TARGET_VALUE, 
  728             finish, rval=KERN_FAILURE);
  729 
  730         /* Get the target's section by section number */
  731         sect = kxld_array_get_item(sectarray, reloc->target);
  732         require_action(sect, finish, rval=KERN_FAILURE);
  733 
  734         /* target is the change in the section's address */
  735         target = sect->link_addr - sect->base_addr;
  736 
  737         if (reloc->pair_target_type) {
  738             pair_target = reloc->pair_target;
  739         } else {
  740             /* x86_64 needs to know when we have a non-external relocation,
  741              * so we hack that information in here.
  742              */
  743             pair_target = TRUE;
  744         }
  745         break;
  746     case KXLD_TARGET_SYMBOLNUM:
  747         require_action(reloc->pair_target_type == KXLD_TARGET_NONE ||
  748             reloc->pair_target_type == KXLD_TARGET_GOT ||
  749             reloc->pair_target_type == KXLD_TARGET_SYMBOLNUM ||
  750             reloc->pair_target_type == KXLD_TARGET_VALUE, finish,
  751             rval=KERN_FAILURE);
  752 
  753         /* Get the target's symbol by symbol number */
  754         sym = kxld_symtab_get_symbol_by_index(symtab, reloc->target);
  755         require_action(sym, finish, rval=KERN_FAILURE);
  756         target = sym->link_addr;
  757 
  758         /* Some relocation types need the GOT entry address instead of the
  759          * symbol's actual address.  These types don't have pair relocation
  760          * entries, so we store the GOT entry address as the pair target.
  761          */
  762         if (reloc->pair_target_type == KXLD_TARGET_VALUE) {
  763             pair_target = reloc->pair_target;
  764         } else if (reloc->pair_target_type == KXLD_TARGET_SYMBOLNUM ) {
  765             sym = kxld_symtab_get_symbol_by_index(symtab, reloc->pair_target);
  766             require_action(sym, finish, rval=KERN_FAILURE);
  767             pair_target = sym->link_addr;
  768         } else if (reloc->pair_target_type == KXLD_TARGET_GOT) {
  769             pair_target = sym->got_addr;
  770         }
  771         break;
  772     default:
  773         rval = KERN_FAILURE;
  774         goto finish;
  775     }
  776 
  777     *_target = target;
  778     *_pair_target = pair_target;
  779     rval = KERN_SUCCESS;
  780 
  781 finish:
  782     return rval;
  783 }
  784 
  785 /*******************************************************************************
  786 *******************************************************************************/
  787 static kern_return_t
  788 get_target_by_address_lookup(kxld_addr_t *target, kxld_addr_t addr,
  789     const KXLDArray *sectarray)
  790 {
  791     kern_return_t rval = KERN_FAILURE;
  792     const KXLDSect *sect = NULL;
  793     kxld_addr_t start = 0;
  794     kxld_addr_t end = 0;
  795     u_int i = 0;
  796 
  797     check(target);
  798     check(sectarray);
  799     *target = 0;
  800 
  801     for (i = 0; i < sectarray->nitems; ++i) {
  802         sect = kxld_array_get_item(sectarray, i);
  803         start = sect->base_addr;
  804         end = start + sect->size;
  805 
  806         if (start <= addr && addr < end) break;
  807     }
  808     require_action(i < sectarray->nitems, finish, 
  809         rval=KERN_FAILURE);
  810 
  811     *target = sect->link_addr - sect->base_addr;
  812     rval = KERN_SUCCESS;
  813 
  814 finish:
  815     return rval;
  816 }
  817 
  818 #if KXLD_USER_OR_I386 
  819 /*******************************************************************************
  820 *******************************************************************************/
  821 static boolean_t
  822 generic_reloc_has_pair(u_int _type)
  823 {
  824     enum reloc_type_generic type = _type;
  825 
  826     return (type == GENERIC_RELOC_SECTDIFF || 
  827         type == GENERIC_RELOC_LOCAL_SECTDIFF);
  828 }
  829 
  830 /*******************************************************************************
  831 *******************************************************************************/
  832 static boolean_t 
  833 generic_reloc_is_pair(u_int _type, u_int _prev_type __unused)
  834 {
  835     enum reloc_type_generic type = _type;
  836 
  837     return (type == GENERIC_RELOC_PAIR);
  838 }
  839 
  840 /*******************************************************************************
  841 *******************************************************************************/
  842 static boolean_t generic_reloc_has_got(u_int _type __unused)
  843 {
  844     return FALSE;
  845 }
  846 
  847 /*******************************************************************************
  848 *******************************************************************************/
  849 static kern_return_t 
  850 generic_process_reloc(u_char *instruction, u_int length, u_int pcrel,
  851     kxld_addr_t _base_pc, kxld_addr_t _link_pc, kxld_addr_t _link_disp __unused, 
  852     u_int _type, kxld_addr_t _target, kxld_addr_t _pair_target, 
  853     boolean_t swap __unused)
  854 {
  855     kern_return_t rval = KERN_FAILURE;
  856     uint32_t base_pc = (uint32_t) _base_pc;
  857     uint32_t link_pc = (uint32_t) _link_pc;
  858     uint32_t *instr_addr = NULL;
  859     uint32_t instr_data = 0;
  860     uint32_t target = (uint32_t) _target;
  861     uint32_t pair_target = (uint32_t) _pair_target;
  862     enum reloc_type_generic type = _type;
  863 
  864     check(instruction);
  865     require_action(length == 2, finish, rval=KERN_FAILURE);
  866 
  867     if (pcrel) target = target + base_pc - link_pc;
  868 
  869     instr_addr = (uint32_t *)instruction;
  870     instr_data = *instr_addr;
  871 
  872 #if !KERNEL
  873     if (swap) instr_data = OSSwapInt32(instr_data);
  874 #endif
  875 
  876     switch (type) {
  877     case GENERIC_RELOC_VANILLA:
  878         instr_data += target;
  879         break;
  880     case GENERIC_RELOC_SECTDIFF:
  881     case GENERIC_RELOC_LOCAL_SECTDIFF:
  882         instr_data = instr_data + target - pair_target;
  883         break;
  884     case GENERIC_RELOC_PB_LA_PTR:
  885         rval = KERN_FAILURE;
  886         goto finish;
  887     case GENERIC_RELOC_PAIR:
  888     default:
  889         rval = KERN_FAILURE;
  890         goto finish;
  891     }
  892 
  893 #if !KERNEL
  894     if (swap) instr_data = OSSwapInt32(instr_data);
  895 #endif
  896 
  897     *instr_addr = instr_data;
  898 
  899     rval = KERN_SUCCESS;
  900 
  901 finish:
  902     return rval;
  903 }
  904 #endif /* KXLD_USER_OR_I386 */
  905 
  906 #if KXLD_USER_OR_PPC
  907 /*******************************************************************************
  908 *******************************************************************************/
  909 static boolean_t
  910 ppc_reloc_has_pair(u_int _type)
  911 {
  912     enum reloc_type_ppc type = _type;
  913 
  914     switch(type) {
  915     case PPC_RELOC_HI16:
  916     case PPC_RELOC_LO16:
  917     case PPC_RELOC_HA16:
  918     case PPC_RELOC_LO14:
  919     case PPC_RELOC_JBSR:
  920     case PPC_RELOC_SECTDIFF:
  921         return TRUE;
  922     default:
  923         return FALSE;
  924     }
  925 }
  926 
  927 /*******************************************************************************
  928 *******************************************************************************/
  929 static boolean_t
  930 ppc_reloc_is_pair(u_int _type, u_int _prev_type __unused)
  931 {
  932     enum reloc_type_ppc type = _type;
  933 
  934     return (type == PPC_RELOC_PAIR);
  935 }
  936 
  937 /*******************************************************************************
  938 *******************************************************************************/
  939 static boolean_t ppc_reloc_has_got(u_int _type __unused)
  940 {
  941     return FALSE;
  942 }
  943 
  944 /*******************************************************************************
  945 *******************************************************************************/
  946 static kern_return_t
  947 ppc_process_reloc(u_char *instruction, u_int length, u_int pcrel,
  948     kxld_addr_t _base_pc, kxld_addr_t _link_pc, kxld_addr_t _link_disp __unused,
  949     u_int _type, kxld_addr_t _target, kxld_addr_t _pair_target __unused,
  950     boolean_t swap __unused)
  951 {
  952     kern_return_t rval = KERN_FAILURE;
  953     uint32_t *instr_addr = NULL;
  954     uint32_t instr_data = 0;
  955     uint32_t base_pc = (uint32_t) _base_pc;
  956     uint32_t link_pc = (uint32_t) _link_pc;
  957     uint32_t target = (uint32_t) _target;
  958     uint32_t pair_target = (uint32_t) _pair_target;
  959     int32_t addend = 0;
  960     int32_t displacement = 0;
  961     uint32_t difference = 0;
  962     uint32_t br14_disp_sign = 0;
  963     enum reloc_type_ppc type = _type;
  964 
  965     check(instruction);
  966     require_action(length == 2 || length == 3, finish, 
  967         rval=KERN_FAILURE);
  968 
  969     if (pcrel) displacement = target + base_pc - link_pc;
  970 
  971     instr_addr = (uint32_t *)instruction;
  972     instr_data = *instr_addr;
  973     
  974 #if !KERNEL
  975     if (swap) instr_data = OSSwapInt32(instr_data);
  976 #endif
  977 
  978     switch (type) {
  979     case PPC_RELOC_VANILLA:
  980         require_action(!pcrel, finish, rval=KERN_FAILURE);
  981 
  982         instr_data += target;
  983         break;
  984     case PPC_RELOC_BR14:
  985         require_action(pcrel, finish, rval=KERN_FAILURE);
  986 
  987         addend = BR14D(instr_data);
  988         displacement += SIGN_EXTEND(addend, BR14_NBITS_DISPLACEMENT);
  989         difference = ABSOLUTE_VALUE(displacement);
  990         require_action(difference < BR14_LIMIT, finish, 
  991             rval=KERN_FAILURE;
  992             kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogRelocationOverflow));
  993 
  994 
  995         br14_disp_sign = BIT15(instr_data);
  996         instr_data = BR14I(instr_data) | BR14D(displacement);
  997         
  998         /* If this is a predicted conditional branch (signified by an
  999          * instruction length of 3) that is not branch-always, and the sign of
 1000          * the displacement is different after relocation, then flip the y-bit
 1001          * to preserve the branch prediction
 1002          */
 1003         if ((length == 3) && 
 1004             IS_COND_BR_INSTR(instr_data) &&
 1005             IS_NOT_ALWAYS_TAKEN(instr_data) && 
 1006             (BIT15(instr_data) != br14_disp_sign))
 1007         {     
 1008             FLIP_PREDICT_BIT(instr_data);
 1009         }
 1010         break;
 1011     case PPC_RELOC_BR24:
 1012         require_action(pcrel, finish, rval=KERN_FAILURE);
 1013 
 1014         addend = BR24D(instr_data);
 1015         displacement += SIGN_EXTEND(addend, BR24_NBITS_DISPLACEMENT);
 1016         difference = ABSOLUTE_VALUE(displacement);
 1017         require_action(difference < BR24_LIMIT, finish, 
 1018             rval=KERN_FAILURE;
 1019             kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogRelocationOverflow));
 1020 
 1021         instr_data = BR24I(instr_data) | BR24D(displacement);
 1022         break;
 1023     case PPC_RELOC_HI16:
 1024         require_action(!pcrel, finish, rval=KERN_FAILURE);
 1025 
 1026         target += LO16S(instr_data) | LO16(pair_target);
 1027         instr_data = HI16(instr_data) | HI16S(target);
 1028         break;
 1029     case PPC_RELOC_LO16:
 1030         require_action(!pcrel, finish, rval=KERN_FAILURE);
 1031 
 1032         target += LO16S(pair_target) | LO16(instr_data);
 1033         instr_data = HI16(instr_data) | LO16(target);
 1034         break;
 1035     case PPC_RELOC_HA16:
 1036         require_action(!pcrel, finish, rval=KERN_FAILURE);
 1037 
 1038         instr_data -= BIT15(pair_target) ? 1 : 0;
 1039         target += LO16S(instr_data) | LO16(pair_target);
 1040         instr_data = HI16(instr_data) | HI16S(target);
 1041         instr_data += BIT15(target) ? 1 : 0;
 1042         break;
 1043     case PPC_RELOC_JBSR:
 1044         require_action(!pcrel, finish, rval=KERN_FAILURE);
 1045 
 1046         /* The generated code as written branches to an island that loads the
 1047          * absolute address of the target.  If we can branch to the target 
 1048          * directly with less than 24 bits of displacement, we modify the branch
 1049          * instruction to do so which avoids the cost of the island.
 1050          */
 1051 
 1052         displacement = target + pair_target - link_pc;
 1053         difference = ABSOLUTE_VALUE(displacement);
 1054         if (difference < BR24_LIMIT) {
 1055             instr_data = BR24I(instr_data) | BR24D(displacement);
 1056         }
 1057         break;
 1058     case PPC_RELOC_SECTDIFF:
 1059         require_action(!pcrel, finish, rval=KERN_FAILURE);
 1060         
 1061         instr_data = instr_data + target - pair_target;
 1062         break;
 1063     case PPC_RELOC_LO14:
 1064     case PPC_RELOC_PB_LA_PTR:
 1065     case PPC_RELOC_HI16_SECTDIFF:
 1066     case PPC_RELOC_LO16_SECTDIFF:
 1067     case PPC_RELOC_HA16_SECTDIFF:
 1068     case PPC_RELOC_LO14_SECTDIFF:
 1069     case PPC_RELOC_LOCAL_SECTDIFF:
 1070         rval = KERN_FAILURE;
 1071         goto finish;
 1072     case PPC_RELOC_PAIR:
 1073     default:
 1074         rval = KERN_FAILURE;
 1075         goto finish;
 1076     }
 1077 
 1078 #if !KERNEL
 1079     if (swap) instr_data = OSSwapInt32(instr_data);
 1080 #endif
 1081 
 1082     *instr_addr = instr_data;
 1083 
 1084     rval = KERN_SUCCESS;
 1085 finish:
 1086 
 1087     return rval;
 1088 }
 1089 #endif /* KXLD_USER_OR_PPC */
 1090 
 1091 #if KXLD_USER_OR_X86_64
 1092 /*******************************************************************************
 1093 *******************************************************************************/
 1094 static boolean_t 
 1095 x86_64_reloc_has_pair(u_int _type)
 1096 {
 1097     enum reloc_type_x86_64 type = _type;
 1098 
 1099     return (type == X86_64_RELOC_SUBTRACTOR);
 1100 }
 1101 
 1102 /*******************************************************************************
 1103 *******************************************************************************/
 1104 static boolean_t 
 1105 x86_64_reloc_is_pair(u_int _type, u_int _prev_type)
 1106 {
 1107     enum reloc_type_x86_64 type = _type;
 1108     enum reloc_type_x86_64 prev_type = _prev_type;
 1109 
 1110     return (x86_64_reloc_has_pair(prev_type) && type == X86_64_RELOC_UNSIGNED);
 1111 }
 1112 
 1113 /*******************************************************************************
 1114 *******************************************************************************/
 1115 static boolean_t 
 1116 x86_64_reloc_has_got(u_int _type)
 1117 {
 1118     enum reloc_type_x86_64 type = _type;
 1119 
 1120     return (type == X86_64_RELOC_GOT_LOAD || type == X86_64_RELOC_GOT);
 1121 }
 1122 
 1123 /*******************************************************************************
 1124 *******************************************************************************/
 1125 static kern_return_t 
 1126 x86_64_process_reloc(u_char *instruction, u_int length, u_int pcrel,
 1127     kxld_addr_t _base_pc __unused, kxld_addr_t _link_pc, kxld_addr_t _link_disp,
 1128     u_int _type, kxld_addr_t _target, kxld_addr_t _pair_target, 
 1129     boolean_t swap __unused)
 1130 {
 1131     kern_return_t rval = KERN_FAILURE;
 1132     enum reloc_type_x86_64 type = _type;
 1133     int32_t *instr32p = NULL;
 1134     int32_t instr32 = 0;
 1135     uint64_t *instr64p = NULL;
 1136     uint64_t instr64 = 0;
 1137     uint64_t target = _target;
 1138     uint64_t pair_target = _pair_target;
 1139     uint64_t link_pc = (uint64_t) _link_pc;
 1140     uint64_t link_disp = (uint64_t) _link_disp;
 1141     uint64_t adjustment = 0;
 1142 
 1143     check(instruction);
 1144     require_action(length == 2 || length == 3, 
 1145         finish, rval=KERN_FAILURE);
 1146 
 1147     if (length == 2) {
 1148         instr32p = (int32_t *) instruction;
 1149         instr32 = *instr32p;
 1150 
 1151 #if !KERNEL
 1152         if (swap) instr32 = OSSwapInt32(instr32);
 1153 #endif
 1154 
 1155         /* There are a number of different small adjustments for pc-relative
 1156          * relocation entries.  The general case is to subtract the size of the
 1157          * relocation (represented by the length parameter), and it applies to
 1158          * the GOT types and external SIGNED types.  The non-external signed types
 1159          * have a different adjustment corresponding to the specific type.
 1160          */
 1161         switch (type) {
 1162         case X86_64_RELOC_SIGNED:
 1163             if (pair_target) {
 1164                 adjustment = 0;    
 1165                 break;
 1166             }
 1167             /* Fall through */
 1168         case X86_64_RELOC_SIGNED_1:
 1169             if (pair_target) {
 1170                 adjustment = 1;
 1171                 break;
 1172             }
 1173             /* Fall through */
 1174         case X86_64_RELOC_SIGNED_2:
 1175             if (pair_target) {
 1176                 adjustment = 2;
 1177                 break;
 1178             }
 1179             /* Fall through */
 1180         case X86_64_RELOC_SIGNED_4:
 1181             if (pair_target) {
 1182                 adjustment = 4;
 1183                 break;
 1184             }
 1185             /* Fall through */
 1186         case X86_64_RELOC_BRANCH:
 1187         case X86_64_RELOC_GOT:
 1188         case X86_64_RELOC_GOT_LOAD:
 1189             adjustment = (1 << length);
 1190             break;
 1191         default:
 1192             break;
 1193         }
 1194 
 1195         /* Perform the actual relocation.  All of the 32-bit relocations are 
 1196          * pc-relative except for SUBTRACTOR, so a good chunk of the logic is
 1197          * stuck in calculate_displacement_x86_64.  The signed relocations are
 1198          * a special case, because when they are non-external, the instruction
 1199          * already contains the pre-relocation displacement, so we only need to
 1200          * find the difference between how far the PC was relocated, and how
 1201          * far the target is relocated.  Since the target variable already
 1202          * contains the difference between the target's base and link
 1203          * addresses, we add the difference between the PC's base and link
 1204          * addresses to the adjustment variable.  This will yield the
 1205          * appropriate displacement in calculate_displacement.
 1206          */
 1207         switch (type) {
 1208         case X86_64_RELOC_BRANCH:
 1209             require_action(pcrel, finish, rval=KERN_FAILURE);
 1210             adjustment += link_pc;
 1211             break;
 1212         case X86_64_RELOC_SIGNED:
 1213         case X86_64_RELOC_SIGNED_1:
 1214         case X86_64_RELOC_SIGNED_2:
 1215         case X86_64_RELOC_SIGNED_4:
 1216             require_action(pcrel, finish, rval=KERN_FAILURE);
 1217             adjustment += (pair_target) ? (link_disp) : (link_pc);
 1218             break;
 1219         case X86_64_RELOC_GOT:
 1220         case X86_64_RELOC_GOT_LOAD:
 1221             require_action(pcrel, finish, rval=KERN_FAILURE);
 1222             adjustment += link_pc;
 1223             target = pair_target;
 1224             break;
 1225         case X86_64_RELOC_SUBTRACTOR:
 1226             require_action(!pcrel, finish, rval=KERN_FAILURE);
 1227             instr32 = (int32_t) (target - pair_target);
 1228             break;
 1229         case X86_64_RELOC_UNSIGNED:
 1230         default:
 1231             rval = KERN_FAILURE;
 1232             goto finish;
 1233         }
 1234 
 1235         /* Call calculate_displacement for the pc-relative relocations */
 1236         if (pcrel) {
 1237             rval = calculate_displacement_x86_64(target, adjustment, &instr32); 
 1238             require_noerr(rval, finish);
 1239         }
 1240 
 1241 #if !KERNEL
 1242         if (swap) instr32 = OSSwapInt32(instr32);
 1243 #endif
 1244 
 1245         *instr32p = instr32;
 1246     } else {
 1247         instr64p = (uint64_t *) instruction;
 1248         instr64 = *instr64p;
 1249 
 1250 #if !KERNEL
 1251         if (swap) instr64 = OSSwapInt64(instr64);
 1252 #endif
 1253 
 1254         switch (type) {
 1255         case X86_64_RELOC_UNSIGNED:
 1256             require_action(!pcrel, finish, rval=KERN_FAILURE);
 1257             
 1258             instr64 += target;
 1259             break;
 1260         case X86_64_RELOC_SUBTRACTOR:
 1261             require_action(!pcrel, finish, rval=KERN_FAILURE);
 1262 
 1263             instr64 = target - pair_target;
 1264             break;
 1265         case X86_64_RELOC_SIGNED_1:
 1266         case X86_64_RELOC_SIGNED_2:
 1267         case X86_64_RELOC_SIGNED_4:
 1268         case X86_64_RELOC_GOT_LOAD:
 1269         case X86_64_RELOC_BRANCH:
 1270         case X86_64_RELOC_SIGNED:
 1271         case X86_64_RELOC_GOT:
 1272         default:
 1273             rval = KERN_FAILURE;
 1274             goto finish;
 1275         }
 1276 
 1277 #if !KERNEL
 1278         if (swap) instr64 = OSSwapInt64(instr64);
 1279 #endif
 1280 
 1281         *instr64p = instr64;
 1282     }
 1283 
 1284     rval = KERN_SUCCESS;
 1285 
 1286 finish:
 1287     return rval;
 1288 }
 1289 
 1290 /*******************************************************************************
 1291 *******************************************************************************/
 1292 static kern_return_t
 1293 calculate_displacement_x86_64(uint64_t target, uint64_t adjustment, 
 1294     int32_t *instr32)
 1295 {
 1296     kern_return_t rval = KERN_FAILURE;
 1297     int64_t displacement;
 1298     uint64_t difference;
 1299 
 1300     displacement = *instr32 + target - adjustment;
 1301     difference = ABSOLUTE_VALUE(displacement);
 1302     require_action(difference < X86_64_RIP_RELATIVE_LIMIT, finish, 
 1303         rval=KERN_FAILURE;
 1304         kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogRelocationOverflow));
 1305 
 1306     *instr32 = (int32_t) displacement;
 1307     rval = KERN_SUCCESS;
 1308 
 1309 finish:
 1310     return rval;
 1311 }
 1312 #endif /* KXLD_USER_OR_X86_64 */
 1313 
 1314 #if KXLD_USER_OR_ARM
 1315 /*******************************************************************************
 1316 *******************************************************************************/
 1317 static boolean_t 
 1318 arm_reloc_has_pair(u_int _type)
 1319 {
 1320     enum reloc_type_arm type = _type;
 1321 
 1322     switch(type) {
 1323     case ARM_RELOC_SECTDIFF:
 1324         return TRUE;
 1325     default:
 1326         return FALSE;
 1327     }
 1328     return FALSE;
 1329 }
 1330 
 1331 /*******************************************************************************
 1332 *******************************************************************************/
 1333 static boolean_t 
 1334 arm_reloc_is_pair(u_int _type, u_int _prev_type __unused)
 1335 {
 1336     enum reloc_type_arm type = _type;
 1337 
 1338     return (type == ARM_RELOC_PAIR);
 1339 }
 1340 
 1341 /*******************************************************************************
 1342 *******************************************************************************/
 1343 static boolean_t 
 1344 arm_reloc_has_got(u_int _type __unused)
 1345 {
 1346     return FALSE;
 1347 }
 1348 
 1349 /*******************************************************************************
 1350 *******************************************************************************/
 1351 static kern_return_t 
 1352 arm_process_reloc(u_char *instruction, u_int length, u_int pcrel,
 1353     kxld_addr_t _base_pc __unused, kxld_addr_t _link_pc __unused, kxld_addr_t _link_disp __unused,
 1354     u_int _type __unused, kxld_addr_t _target __unused, kxld_addr_t _pair_target __unused, 
 1355     boolean_t swap __unused)
 1356 {
 1357     kern_return_t rval = KERN_FAILURE;
 1358     uint32_t *instr_addr = NULL;
 1359     uint32_t instr_data = 0;
 1360     uint32_t base_pc = (uint32_t) _base_pc;
 1361     uint32_t link_pc = (uint32_t) _link_pc;
 1362     uint32_t target = (uint32_t) _target;
 1363     int32_t displacement = 0;
 1364     enum reloc_type_arm type = _type;
 1365 
 1366     check(instruction);
 1367     require_action(length == 2, finish, rval=KERN_FAILURE);
 1368 
 1369     if (pcrel) displacement = target + base_pc - link_pc;
 1370 
 1371     instr_addr = (uint32_t *)instruction;
 1372     instr_data = *instr_addr;
 1373     
 1374 #if !KERNEL
 1375     if (swap) instr_data = OSSwapInt32(instr_data);
 1376 #endif
 1377 
 1378     switch (type) {
 1379     case ARM_RELOC_VANILLA:
 1380         require_action(!pcrel, finish, rval=KERN_FAILURE);
 1381         instr_data += target;
 1382         break;
 1383 
 1384     /*
 1385      * If the displacement is 0 (the offset between the pc and the target has
 1386      * not changed), then we don't need to do anything for BR24 and BR22
 1387      * relocs.  As it turns out, because kexts build with -mlong-calls all
 1388      * relocations currently end up being either vanilla (handled above) or 
 1389      * BR22/BR24 with a displacement of 0.
 1390      * We could handle other displacements here but to keep things simple, we
 1391      * won't until it is needed (at which point the kernelcache will fail to
 1392      * link)
 1393      */
 1394     case ARM_RELOC_BR24:
 1395         require_action(pcrel, finish, rval=KERN_FAILURE);
 1396         require_action(displacement == 0, finish, rval=KERN_FAILURE);
 1397         break;
 1398     case ARM_THUMB_RELOC_BR22:
 1399         require_action(pcrel, finish, rval=KERN_FAILURE);
 1400         require_action(displacement == 0, finish, rval=KERN_FAILURE);
 1401         break;
 1402 
 1403     case ARM_RELOC_SECTDIFF:
 1404     case ARM_RELOC_LOCAL_SECTDIFF:
 1405     case ARM_RELOC_PB_LA_PTR:
 1406         rval = KERN_FAILURE;
 1407         goto finish;
 1408 
 1409     case ARM_RELOC_PAIR:
 1410     default:
 1411         rval = KERN_FAILURE;
 1412         goto finish;
 1413     }
 1414 
 1415 #if !KERNEL
 1416     if (swap) instr_data = OSSwapInt32(instr_data);
 1417 #endif
 1418 
 1419     *instr_addr = instr_data;
 1420 
 1421     rval = KERN_SUCCESS;
 1422 
 1423 finish:
 1424     return rval;
 1425 }
 1426 
 1427 #endif /* KXLD_USER_OR_ARM */
 1428 

Cache object: 0d05eacc37b436da8b7f8f7e259c0200


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.