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