2 * Copyright (c) 2007-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/boolean.h>
30 #include <sys/types.h>
33 #include <libkern/libkern.h>
34 #include <mach/machine.h>
37 #include <libkern/OSByteOrder.h>
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.
42 #include "../../osfmk/mach/machine.h"
45 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
46 #include <AssertMacros.h>
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"
55 #include "kxld_symtab.h"
56 #include "kxld_util.h"
57 #include "kxld_vtable.h"
60 /* This will try to pull in mach/machine.h, so it has to come after the
61 * explicit include above.
63 #include <mach-o/loader.h>
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>
72 #include <mach-o/arm/reloc.h>
74 #if KXLD_USER_OR_ARM64
75 #include <mach-o/arm64/reloc.h>
78 #define KXLD_TARGET_NONE (u_int) 0x0
79 #define KXLD_TARGET_VALUE (u_int) 0x1
80 #define KXLD_TARGET_SECTNUM (u_int) 0x2
81 #define KXLD_TARGET_SYMBOLNUM (u_int) 0x3
82 #define KXLD_TARGET_LOOKUP (u_int) 0x4
83 #define KXLD_TARGET_GOT (u_int) 0x5
85 #define ABSOLUTE_VALUE(x) (((x) < 0) ? -(x) : (x))
87 #define LO16(x) (0x0000FFFF & x)
88 #define LO16S(x) ((0x0000FFFF & x) << 16)
89 #define HI16(x) (0xFFFF0000 & x)
90 #define HI16S(x) ((0xFFFF0000 & x) >> 16)
91 #define BIT15(x) (0x00008000 & x)
92 #define BR14I(x) (0xFFFF0003 & x)
93 #define BR14D(x) (0x0000FFFC & x)
94 #define BR24I(x) (0xFC000003 & x)
95 #define BR24D(x) (0x03FFFFFC & x)
96 #define HADISP 0x00010000
97 #define BR14_LIMIT 0x00008000
98 #define BR24_LIMIT 0x02000000
99 #define IS_COND_BR_INSTR(x) ((x & 0xFC000000) == 0x40000000)
100 #define IS_NOT_ALWAYS_TAKEN(x) ((x & 0x03E00000) != 0x02800000)
101 #define FLIP_PREDICT_BIT(x) x ^= 0x00200000
103 #define SIGN_EXTEND_MASK(n) (1 << ((n) - 1))
104 #define SIGN_EXTEND(x,n) (((x) ^ SIGN_EXTEND_MASK(n)) - SIGN_EXTEND_MASK(n))
105 #define BR14_NBITS_DISPLACEMENT 16
106 #define BR24_NBITS_DISPLACEMENT 26
108 #define X86_64_RIP_RELATIVE_LIMIT 0x80000000UL
110 /*******************************************************************************
112 *******************************************************************************/
113 #if KXLD_USER_OR_I386
114 static boolean_t
generic_reloc_has_pair(u_int _type
)
115 __attribute__((const));
116 static u_int
generic_reloc_get_pair_type(u_int _prev_type
)
117 __attribute__((const));
118 static boolean_t
generic_reloc_has_got(u_int _type
)
119 __attribute__((const));
120 static kern_return_t
generic_process_reloc(const KXLDRelocator
*relocator
,
121 u_char
*instruction
, u_int length
, u_int pcrel
, kxld_addr_t base_pc
,
122 kxld_addr_t link_pc
, kxld_addr_t link_disp
, u_int type
, kxld_addr_t target
,
123 kxld_addr_t pair_target
, boolean_t swap
);
124 #endif /* KXLD_USER_OR_I386 */
126 #if KXLD_USER_OR_X86_64
127 static boolean_t
x86_64_reloc_has_pair(u_int _type
)
128 __attribute__((const));
129 static u_int
x86_64_reloc_get_pair_type(u_int _prev_type
)
130 __attribute__((const));
131 static boolean_t
x86_64_reloc_has_got(u_int _type
)
132 __attribute__((const));
133 static kern_return_t
x86_64_process_reloc(const KXLDRelocator
*relocator
,
134 u_char
*instruction
, u_int length
, u_int pcrel
, kxld_addr_t base_pc
,
135 kxld_addr_t link_pc
, kxld_addr_t link_disp
, u_int type
, kxld_addr_t target
,
136 kxld_addr_t pair_target
, boolean_t swap
);
137 static kern_return_t
calculate_displacement_x86_64(uint64_t target
,
138 uint64_t adjustment
, int32_t *instr32
);
139 #endif /* KXLD_USER_OR_X86_64 */
142 static boolean_t
arm_reloc_has_pair(u_int _type
)
143 __attribute__((const));
144 static u_int
arm_reloc_get_pair_type(u_int _prev_type
)
145 __attribute__((const));
146 static boolean_t
arm_reloc_has_got(u_int _type
)
147 __attribute__((const));
148 static kern_return_t
arm_process_reloc(const KXLDRelocator
*relocator
,
149 u_char
*instruction
, u_int length
, u_int pcrel
, kxld_addr_t base_pc
,
150 kxld_addr_t link_pc
, kxld_addr_t link_disp
, u_int type
, kxld_addr_t target
,
151 kxld_addr_t pair_target
, boolean_t swap
);
152 #endif /* KXLD_USER_OR_ARM */
154 #if KXLD_USER_OR_ARM64
155 static boolean_t
arm64_reloc_has_pair(u_int _type
)
156 __attribute__((const));
157 static u_int
arm64_reloc_get_pair_type(u_int _prev_type
)
158 __attribute__((const));
159 static boolean_t
arm64_reloc_has_got(u_int _type
)
160 __attribute__((const));
161 static kern_return_t
arm64_process_reloc(const KXLDRelocator
*relocator
,
162 u_char
*instruction
, u_int length
, u_int pcrel
, kxld_addr_t base_pc
,
163 kxld_addr_t link_pc
, kxld_addr_t link_disp
, u_int type
, kxld_addr_t target
,
164 kxld_addr_t pair_target
, boolean_t swap
);
165 #endif /* KXLD_USER_OR_ARM64 */
167 #if KXLD_USER_OR_ILP32
168 static kxld_addr_t
get_pointer_at_addr_32(const KXLDRelocator
*relocator
,
169 const u_char
*data
, u_long offset
)
170 __attribute__((pure
, nonnull
));
171 #endif /* KXLD_USER_OR_ILP32 */
172 #if KXLD_USER_OR_LP64
173 static kxld_addr_t
get_pointer_at_addr_64(const KXLDRelocator
*relocator
,
174 const u_char
*data
, u_long offset
)
175 __attribute__((pure
, nonnull
));
176 #endif /* KXLD_USER_OR_LP64 */
178 static u_int
count_relocatable_relocs(const KXLDRelocator
*relocator
,
179 const struct relocation_info
*relocs
, u_int nrelocs
)
180 __attribute__((pure
));
182 static kern_return_t
calculate_targets(KXLDRelocator
*relocator
,
183 kxld_addr_t
*_target
, kxld_addr_t
*_pair_target
, const KXLDReloc
*reloc
);
185 static kxld_addr_t
align_raw_function_address(const KXLDRelocator
*relocator
,
188 static kern_return_t
get_target_by_address_lookup(kxld_addr_t
*target
,
189 kxld_addr_t addr
, const KXLDArray
*sectarray
);
191 static kern_return_t
check_for_direct_pure_virtual_call(
192 const KXLDRelocator
*relocator
, u_long offset
);
195 static u_long
get_macho_data_size_for_array(const KXLDArray
*relocs
);
197 static kern_return_t
export_macho_for_array(const KXLDRelocator
*relocator
,
198 const KXLDArray
*relocs
, struct relocation_info
**dstp
);
199 #endif /* KXLD_PIC_KEXTS */
201 /*******************************************************************************
202 *******************************************************************************/
204 kxld_relocator_init(KXLDRelocator
*relocator
, u_char
*file
,
205 const KXLDSymtab
*symtab
, const KXLDArray
*sectarray
, cpu_type_t cputype
,
206 cpu_subtype_t cpusubtype __unused
, boolean_t swap
)
208 kern_return_t rval
= KERN_FAILURE
;
213 #if KXLD_USER_OR_I386
215 relocator
->reloc_has_pair
= generic_reloc_has_pair
;
216 relocator
->reloc_get_pair_type
= generic_reloc_get_pair_type
;
217 relocator
->reloc_has_got
= generic_reloc_has_got
;
218 relocator
->process_reloc
= generic_process_reloc
;
219 relocator
->function_align
= 0;
220 relocator
->is_32_bit
= TRUE
;
221 relocator
->may_scatter
= TRUE
;
223 #endif /* KXLD_USER_OR_I386 */
224 #if KXLD_USER_OR_X86_64
225 case CPU_TYPE_X86_64
:
226 relocator
->reloc_has_pair
= x86_64_reloc_has_pair
;
227 relocator
->reloc_get_pair_type
= x86_64_reloc_get_pair_type
;
228 relocator
->reloc_has_got
= x86_64_reloc_has_got
;
229 relocator
->process_reloc
= x86_64_process_reloc
;
230 relocator
->function_align
= 0;
231 relocator
->is_32_bit
= FALSE
;
232 relocator
->may_scatter
= FALSE
;
234 #endif /* KXLD_USER_OR_X86_64 */
237 relocator
->reloc_has_pair
= arm_reloc_has_pair
;
238 relocator
->reloc_get_pair_type
= arm_reloc_get_pair_type
;
239 relocator
->reloc_has_got
= arm_reloc_has_got
;
240 relocator
->process_reloc
= arm_process_reloc
;
241 relocator
->function_align
= 1;
242 relocator
->is_32_bit
= TRUE
;
243 relocator
->may_scatter
= FALSE
;
245 #endif /* KXLD_USER_OR_ARM */
246 #if KXLD_USER_OR_ARM64
248 relocator
->reloc_has_pair
= arm64_reloc_has_pair
;
249 relocator
->reloc_get_pair_type
= arm64_reloc_get_pair_type
;
250 relocator
->reloc_has_got
= arm64_reloc_has_got
;
251 relocator
->process_reloc
= arm64_process_reloc
;
252 relocator
->function_align
= 0;
253 relocator
->is_32_bit
= FALSE
;
254 relocator
->may_scatter
= FALSE
;
256 #endif /* KXLD_USER_OR_ARM64 */
260 kxld_log(kKxldLogLinking
, kKxldLogErr
,
261 kKxldLogArchNotSupported
, cputype
);
265 relocator
->file
= file
;
266 relocator
->symtab
= symtab
;
267 relocator
->sectarray
= sectarray
;
268 relocator
->is_32_bit
= kxld_is_32_bit(cputype
);
269 relocator
->swap
= swap
;
277 /*******************************************************************************
278 *******************************************************************************/
280 kxld_reloc_create_macho(KXLDArray
*relocarray
, const KXLDRelocator
*relocator
,
281 const struct relocation_info
*srcs
, u_int nsrcs
)
283 kern_return_t rval
= KERN_FAILURE
;
284 KXLDReloc
*reloc
= NULL
;
286 const struct relocation_info
*src
= NULL
;
287 const struct scattered_relocation_info
*scatsrc
= NULL
;
289 u_int reloc_index
= 0;
294 /* If there are no relocation entries, just return */
300 /* Count the number of non-pair relocs */
301 nrelocs
= count_relocatable_relocs(relocator
, srcs
, nsrcs
);
305 /* Allocate the array of relocation entries */
307 rval
= kxld_array_init(relocarray
, sizeof(KXLDReloc
), nrelocs
);
308 require_noerr(rval
, finish
);
310 /* Initialize the relocation entries */
312 for (i
= 0; i
< nsrcs
; ++i
) {
314 scatsrc
= (const struct scattered_relocation_info
*) src
;
316 /* A section-based relocation entry can be skipped for absolute
320 if (!(relocator
->may_scatter
&& (src
->r_address
& R_SCATTERED
)) &&
321 !(src
->r_extern
) && (R_ABS
== src
->r_symbolnum
))
326 /* Pull out the data from the relocation entries. The target_type
327 * depends on the r_extern bit:
328 * Scattered -> Section Lookup by Address
329 * Local (not extern) -> Section by Index
330 * Extern -> Symbolnum by Index
332 reloc
= kxld_array_get_item(relocarray
, reloc_index
++);
333 if (relocator
->may_scatter
&& (src
->r_address
& R_SCATTERED
)) {
334 reloc
->address
= scatsrc
->r_address
;
335 reloc
->pcrel
= scatsrc
->r_pcrel
;
336 reloc
->length
= scatsrc
->r_length
;
337 reloc
->reloc_type
= scatsrc
->r_type
;
338 reloc
->target
= scatsrc
->r_value
;
339 reloc
->target_type
= KXLD_TARGET_LOOKUP
;
341 reloc
->address
= src
->r_address
;
342 reloc
->pcrel
= src
->r_pcrel
;
343 reloc
->length
= src
->r_length
;
344 reloc
->reloc_type
= src
->r_type
;
345 reloc
->target
= src
->r_symbolnum
;
347 if (0 == src
->r_extern
) {
348 reloc
->target_type
= KXLD_TARGET_SECTNUM
;
351 reloc
->target_type
= KXLD_TARGET_SYMBOLNUM
;
355 /* Find the pair entry if it exists */
357 if (relocator
->reloc_has_pair(reloc
->reloc_type
)) {
359 require_action(i
< nsrcs
, finish
, rval
=KERN_FAILURE
);
362 scatsrc
= (const struct scattered_relocation_info
*) src
;
364 if (relocator
->may_scatter
&& (src
->r_address
& R_SCATTERED
)) {
365 require_action(relocator
->reloc_get_pair_type(
366 reloc
->reloc_type
) == scatsrc
->r_type
,
367 finish
, rval
=KERN_FAILURE
);
368 reloc
->pair_address
= scatsrc
->r_address
;
369 reloc
->pair_target
= scatsrc
->r_value
;
370 reloc
->pair_target_type
= KXLD_TARGET_LOOKUP
;
372 require_action(relocator
->reloc_get_pair_type(
373 reloc
->reloc_type
) == scatsrc
->r_type
,
374 finish
, rval
=KERN_FAILURE
);
375 reloc
->pair_address
= scatsrc
->r_address
;
377 reloc
->pair_target
= src
->r_symbolnum
;
378 reloc
->pair_target_type
= KXLD_TARGET_SYMBOLNUM
;
380 reloc
->pair_target
= src
->r_address
;
381 reloc
->pair_target_type
= KXLD_TARGET_VALUE
;
385 reloc
->pair_target
= 0;
386 if (relocator
->reloc_has_got(reloc
->reloc_type
)) {
387 reloc
->pair_target_type
= KXLD_TARGET_GOT
;
389 reloc
->pair_target_type
= KXLD_TARGET_NONE
;
402 /*******************************************************************************
403 * Relocatable relocs :
404 * 1) Are not _PAIR_ relocs
405 * 2) Don't reference N_ABS symbols
406 *******************************************************************************/
408 count_relocatable_relocs(const KXLDRelocator
*relocator
,
409 const struct relocation_info
*relocs
, u_int nrelocs
)
411 u_int num_nonpair_relocs
= 0;
413 const struct relocation_info
*reloc
= NULL
;
414 const struct scattered_relocation_info
*sreloc
= NULL
;
419 /* Loop over all of the relocation entries */
421 num_nonpair_relocs
= 1;
422 for (i
= 1; i
< nrelocs
; ++i
) {
425 if (reloc
->r_address
& R_SCATTERED
) {
426 /* A scattered relocation entry is relocatable as long as it's not a
429 sreloc
= (const struct scattered_relocation_info
*) reloc
;
431 num_nonpair_relocs
+=
432 !relocator
->reloc_has_pair(sreloc
->r_type
);
434 /* A normal relocation entry is relocatable if it is not a pair and
435 * if it is not a section-based relocation for an absolute symbol.
437 num_nonpair_relocs
+=
438 !(relocator
->reloc_has_pair(reloc
->r_type
)
439 || (0 == reloc
->r_extern
&& R_ABS
== reloc
->r_symbolnum
));
444 return num_nonpair_relocs
;
447 /*******************************************************************************
448 *******************************************************************************/
450 kxld_relocator_clear(KXLDRelocator
*relocator
)
452 bzero(relocator
, sizeof(*relocator
));
455 /*******************************************************************************
456 *******************************************************************************/
458 kxld_relocator_has_pair(const KXLDRelocator
*relocator
, u_int r_type
)
462 return relocator
->reloc_has_pair(r_type
);
465 /*******************************************************************************
466 *******************************************************************************/
468 kxld_relocator_get_pair_type(const KXLDRelocator
*relocator
,
473 return relocator
->reloc_get_pair_type(prev_r_type
);
476 /*******************************************************************************
477 *******************************************************************************/
479 kxld_relocator_has_got(const KXLDRelocator
*relocator
, u_int r_type
)
483 return relocator
->reloc_has_got(r_type
);
486 /*******************************************************************************
487 *******************************************************************************/
489 kxld_reloc_get_symbol(const KXLDRelocator
*relocator
, const KXLDReloc
*reloc
,
493 kxld_addr_t value
= 0;
497 switch (reloc
->target_type
) {
498 case KXLD_TARGET_SYMBOLNUM
:
499 sym
= kxld_symtab_get_symbol_by_index(relocator
->symtab
, reloc
->target
);
501 case KXLD_TARGET_SECTNUM
:
503 value
= kxld_relocator_get_pointer_at_addr(relocator
, data
,
505 sym
= kxld_symtab_get_cxx_symbol_by_value(relocator
->symtab
, value
);
516 /*******************************************************************************
517 *******************************************************************************/
519 kxld_reloc_get_reloc_index_by_offset(const KXLDArray
*relocs
,
520 kxld_size_t offset
, u_int
*idx
)
522 kern_return_t rval
= KERN_FAILURE
;
523 KXLDReloc
*reloc
= NULL
;
526 for (i
= 0; i
< relocs
->nitems
; ++i
) {
527 reloc
= kxld_array_get_item(relocs
, i
);
528 if (reloc
->address
== offset
) break;
531 if (i
>= relocs
->nitems
) {
543 /*******************************************************************************
544 *******************************************************************************/
546 kxld_reloc_get_reloc_by_offset(const KXLDArray
*relocs
, kxld_addr_t offset
)
548 kern_return_t rval
= KERN_FAILURE
;
549 KXLDReloc
*reloc
= NULL
;
552 rval
= kxld_reloc_get_reloc_index_by_offset(relocs
, offset
, &i
);
553 if (rval
) goto finish
;
555 reloc
= kxld_array_get_item(relocs
, i
);
562 /*******************************************************************************
563 *******************************************************************************/
565 kxld_reloc_get_macho_header_size()
567 return sizeof(struct dysymtab_command
);
570 /*******************************************************************************
571 *******************************************************************************/
573 kxld_reloc_get_macho_data_size(const KXLDArray
*locrelocs
,
574 const KXLDArray
*extrelocs
)
578 rval
+= get_macho_data_size_for_array(locrelocs
);
579 rval
+= get_macho_data_size_for_array(extrelocs
);
584 /*******************************************************************************
585 *******************************************************************************/
587 kxld_reloc_export_macho(const KXLDRelocator
*relocator
,
588 const KXLDArray
*locrelocs
, const KXLDArray
*extrelocs
,
589 u_char
*buf
, u_long
*header_offset
, u_long header_size
,
590 u_long
*data_offset
, u_long size
)
592 kern_return_t rval
= KERN_FAILURE
;
593 struct dysymtab_command
*dysymtabhdr
= NULL
;
594 struct relocation_info
*start
= NULL
;
595 struct relocation_info
*dst
= NULL
;
597 u_long data_size
= 0;
602 check(header_offset
);
605 require_action(sizeof(*dysymtabhdr
) <= header_size
- *header_offset
, finish
, rval
=KERN_FAILURE
);
606 dysymtabhdr
= (struct dysymtab_command
*) ((void *) (buf
+ *header_offset
));
607 *header_offset
+= sizeof(*dysymtabhdr
);
609 data_size
= kxld_reloc_get_macho_data_size(locrelocs
, extrelocs
);
610 require_action((*data_offset
+ data_size
) <= size
, finish
, rval
=KERN_FAILURE
);
612 start
= dst
= (struct relocation_info
*) ((void *) (buf
+ *data_offset
));
614 rval
= export_macho_for_array(relocator
, locrelocs
, &dst
);
615 require_noerr(rval
, finish
);
617 rval
= export_macho_for_array(relocator
, extrelocs
, &dst
);
618 require_noerr(rval
, finish
);
622 memset(dysymtabhdr
, 0, sizeof(*dysymtabhdr
));
623 dysymtabhdr
->cmd
= LC_DYSYMTAB
;
624 dysymtabhdr
->cmdsize
= (uint32_t) sizeof(*dysymtabhdr
);
625 dysymtabhdr
->locreloff
= (uint32_t) *data_offset
;
626 dysymtabhdr
->nlocrel
= (uint32_t) count
;
628 *data_offset
+= count
* sizeof(struct relocation_info
);
634 #endif /* KXLD_PIC_KEXTS */
636 /*******************************************************************************
637 *******************************************************************************/
639 kxld_relocator_get_pointer_at_addr(const KXLDRelocator
*relocator
,
640 const u_char
*data
, u_long offset
)
644 KXLD_3264_FUNC(relocator
->is_32_bit
, value
,
645 get_pointer_at_addr_32
, get_pointer_at_addr_64
,
646 relocator
, data
, offset
);
651 #if KXLD_USER_OR_ILP32
652 /*******************************************************************************
653 *******************************************************************************/
655 get_pointer_at_addr_32(const KXLDRelocator
*relocator
,
656 const u_char
*data
, u_long offset
)
662 addr
= *(const uint32_t *) ((const void *) (data
+ offset
));
664 if (relocator
->swap
) {
665 addr
= OSSwapInt32(addr
);
669 return align_raw_function_address(relocator
, addr
);
671 #endif /* KXLD_USER_OR_ILP32 */
673 #if KXLD_USER_OR_LP64
674 /*******************************************************************************
675 *******************************************************************************/
677 get_pointer_at_addr_64(const KXLDRelocator
*relocator
,
678 const u_char
*data
, u_long offset
)
684 addr
= *(const uint64_t *) ((const void *) (data
+ offset
));
686 if (relocator
->swap
) {
687 addr
= OSSwapInt64(addr
);
691 return align_raw_function_address(relocator
, addr
);
693 #endif /* KXLD_USER_OR_LP64 */
695 /*******************************************************************************
696 *******************************************************************************/
698 kxld_relocator_set_vtables(KXLDRelocator
*relocator
, const KXLDDict
*vtables
)
700 relocator
->vtables
= vtables
;
703 /*******************************************************************************
704 * When we're inspecting the raw binary and not the symbol table, value may
705 * hold a THUMB address (with bit 0 set to 1) but the index will have the real
706 * address (bit 0 set to 0). So if bit 0 is set here, we clear it. This only
707 * impacts ARM for now, but it's implemented as a generic function alignment
709 *******************************************************************************/
711 align_raw_function_address(const KXLDRelocator
*relocator
, kxld_addr_t value
)
713 if (relocator
->function_align
) {
714 value
&= ~((1ULL << relocator
->function_align
) - 1);
720 /*******************************************************************************
721 *******************************************************************************/
723 kxld_relocator_process_sect_reloc(KXLDRelocator
*relocator
,
724 const KXLDReloc
*reloc
, const KXLDSect
*sect
)
726 kern_return_t rval
= KERN_FAILURE
;
727 u_char
*instruction
= NULL
;
728 kxld_addr_t target
= 0;
729 kxld_addr_t pair_target
= 0;
730 kxld_addr_t base_pc
= 0;
731 kxld_addr_t link_pc
= 0;
732 kxld_addr_t link_disp
= 0;
738 /* Find the instruction */
740 instruction
= sect
->data
+ reloc
->address
;
742 /* Calculate the target */
744 rval
= calculate_targets(relocator
, &target
, &pair_target
, reloc
);
745 require_noerr(rval
, finish
);
747 base_pc
= reloc
->address
;
748 link_pc
= base_pc
+ sect
->link_addr
;
749 link_disp
= sect
->link_addr
- sect
->base_addr
;
753 rval
= relocator
->process_reloc(relocator
, instruction
, reloc
->length
,
754 reloc
->pcrel
, base_pc
, link_pc
, link_disp
, reloc
->reloc_type
, target
,
755 pair_target
, relocator
->swap
);
756 require_noerr(rval
, finish
);
760 relocator
->current_vtable
= NULL
;
767 /*******************************************************************************
768 *******************************************************************************/
770 kxld_reloc_update_symindex(KXLDReloc
*reloc
, u_int symindex
)
772 kern_return_t rval
= KERN_FAILURE
;
774 require_action(reloc
->target_type
== KXLD_TARGET_SYMBOLNUM
,
775 finish
, rval
= KERN_FAILURE
);
777 reloc
->target
= symindex
;
785 /*******************************************************************************
786 *******************************************************************************/
788 kxld_relocator_process_table_reloc(KXLDRelocator
*relocator
,
789 const KXLDReloc
*reloc
, const KXLDSeg
*seg
, kxld_addr_t link_addr
)
791 kern_return_t rval
= KERN_FAILURE
;
792 u_char
*instruction
= NULL
;
793 kxld_addr_t target
= 0;
794 kxld_addr_t pair_target
= 0;
795 kxld_addr_t base_pc
= 0;
796 kxld_addr_t link_pc
= 0;
802 /* Find the instruction */
804 offset
= (u_long
)(seg
->fileoff
+ (reloc
->address
- seg
->base_addr
));
805 instruction
= relocator
->file
+ offset
;
807 /* Calculate the target */
809 rval
= calculate_targets(relocator
, &target
, &pair_target
, reloc
);
810 require_noerr(rval
, finish
);
812 base_pc
= reloc
->address
;
813 link_pc
= base_pc
+ link_addr
;
817 rval
= relocator
->process_reloc(relocator
, instruction
, reloc
->length
,
818 reloc
->pcrel
, base_pc
, link_pc
, link_addr
, reloc
->reloc_type
, target
,
819 pair_target
, relocator
->swap
);
820 require_noerr(rval
, finish
);
824 relocator
->current_vtable
= NULL
;
831 /*******************************************************************************
832 *******************************************************************************/
834 calculate_targets(KXLDRelocator
*relocator
, kxld_addr_t
*_target
,
835 kxld_addr_t
*_pair_target
, const KXLDReloc
*reloc
)
837 kern_return_t rval
= KERN_FAILURE
;
838 const KXLDSect
*sect
= NULL
;
839 const KXLDSym
*sym
= NULL
;
840 kxld_addr_t target
= 0;
841 kxld_addr_t pair_target
= 0;
842 char *demangled_name
= NULL
;
843 size_t demangled_length
= 0;
850 /* Find the target based on the lookup type */
852 switch(reloc
->target_type
) {
853 case KXLD_TARGET_LOOKUP
:
854 require_action(reloc
->pair_target_type
== KXLD_TARGET_NONE
||
855 reloc
->pair_target_type
== KXLD_TARGET_LOOKUP
||
856 reloc
->pair_target_type
== KXLD_TARGET_VALUE
,
857 finish
, rval
=KERN_FAILURE
);
859 rval
= get_target_by_address_lookup(&target
, reloc
->target
,
860 relocator
->sectarray
);
861 require_noerr(rval
, finish
);
863 if (reloc
->pair_target_type
== KXLD_TARGET_LOOKUP
) {
864 rval
= get_target_by_address_lookup(&pair_target
,
865 reloc
->pair_target
, relocator
->sectarray
);
866 require_noerr(rval
, finish
);
867 } else if (reloc
->pair_target_type
== KXLD_TARGET_VALUE
) {
868 pair_target
= reloc
->pair_target
;
871 case KXLD_TARGET_SECTNUM
:
872 require_action(reloc
->pair_target_type
== KXLD_TARGET_NONE
||
873 reloc
->pair_target_type
== KXLD_TARGET_VALUE
,
874 finish
, rval
=KERN_FAILURE
);
876 /* Get the target's section by section number */
877 sect
= kxld_array_get_item(relocator
->sectarray
, reloc
->target
);
878 require_action(sect
, finish
, rval
=KERN_FAILURE
);
880 /* target is the change in the section's address */
881 target
= sect
->link_addr
- sect
->base_addr
;
883 if (reloc
->pair_target_type
) {
884 pair_target
= reloc
->pair_target
;
886 /* x86_64 needs to know when we have a non-external relocation,
887 * so we hack that information in here.
892 case KXLD_TARGET_SYMBOLNUM
:
893 require_action(reloc
->pair_target_type
== KXLD_TARGET_NONE
||
894 reloc
->pair_target_type
== KXLD_TARGET_GOT
||
895 reloc
->pair_target_type
== KXLD_TARGET_SYMBOLNUM
||
896 reloc
->pair_target_type
== KXLD_TARGET_VALUE
, finish
,
899 /* Get the target's symbol by symbol number */
900 sym
= kxld_symtab_get_symbol_by_index(relocator
->symtab
, reloc
->target
);
901 require_action(sym
, finish
, rval
=KERN_FAILURE
);
903 /* If this symbol is a padslot that has already been replaced, then the
904 * only way a relocation entry can still reference it is if there is a
905 * vtable that has not been patched. The vtable patcher uses the
906 * MetaClass structure to find classes for patching, so an unpatched
907 * vtable means that there is an OSObject-dervied class that is missing
908 * its OSDeclare/OSDefine macros.
910 require_action(!kxld_sym_is_padslot(sym
) || !kxld_sym_is_replaced(sym
),
911 finish
, rval
=KERN_FAILURE
;
912 kxld_log(kKxldLogLinking
, kKxldLogErr
, kKxldLogRelocatingPatchedSym
,
913 kxld_demangle(sym
->name
, &demangled_name
, &demangled_length
)));
915 target
= sym
->link_addr
;
917 if (kxld_sym_is_vtable(sym
)) {
918 relocator
->current_vtable
= kxld_dict_find(relocator
->vtables
, sym
->name
);
921 /* Some relocation types need the GOT entry address instead of the
922 * symbol's actual address. These types don't have pair relocation
923 * entries, so we store the GOT entry address as the pair target.
925 if (reloc
->pair_target_type
== KXLD_TARGET_VALUE
) {
926 pair_target
= reloc
->pair_target
;
927 } else if (reloc
->pair_target_type
== KXLD_TARGET_SYMBOLNUM
) {
928 sym
= kxld_symtab_get_symbol_by_index(relocator
->symtab
,
930 require_action(sym
, finish
, rval
=KERN_FAILURE
);
931 pair_target
= sym
->link_addr
;
932 } else if (reloc
->pair_target_type
== KXLD_TARGET_GOT
) {
933 pair_target
= sym
->got_addr
;
942 *_pair_target
= pair_target
;
946 if (demangled_name
) kxld_free(demangled_name
, demangled_length
);
950 /*******************************************************************************
951 *******************************************************************************/
953 get_target_by_address_lookup(kxld_addr_t
*target
, kxld_addr_t addr
,
954 const KXLDArray
*sectarray
)
956 kern_return_t rval
= KERN_FAILURE
;
957 const KXLDSect
*sect
= NULL
;
958 kxld_addr_t start
= 0;
966 for (i
= 0; i
< sectarray
->nitems
; ++i
) {
967 sect
= kxld_array_get_item(sectarray
, i
);
968 start
= sect
->base_addr
;
969 end
= start
+ sect
->size
;
971 if (start
<= addr
&& addr
< end
) break;
975 require_action(sect
, finish
, rval
=KERN_FAILURE
);
977 *target
= sect
->link_addr
- sect
->base_addr
;
984 /*******************************************************************************
985 *******************************************************************************/
987 check_for_direct_pure_virtual_call(const KXLDRelocator
*relocator
, u_long offset
)
989 kern_return_t rval
= KERN_FAILURE
;
990 const KXLDVTableEntry
*entry
= NULL
;
992 if (relocator
->current_vtable
) {
993 entry
= kxld_vtable_get_entry_for_offset(relocator
->current_vtable
,
994 offset
, relocator
->is_32_bit
);
995 require_action(!entry
|| !entry
->patched
.name
||
996 !kxld_sym_name_is_pure_virtual(entry
->patched
.name
),
997 finish
, rval
=KERN_FAILURE
;
998 kxld_log(kKxldLogLinking
, kKxldLogErr
,
999 kKxldLogDirectPureVirtualCall
));
1002 rval
= KERN_SUCCESS
;
1008 /*******************************************************************************
1009 *******************************************************************************/
1011 get_macho_data_size_for_array(const KXLDArray
*relocs
)
1013 const KXLDReloc
*reloc
= NULL
;
1019 for (i
= 0; i
< relocs
->nitems
; ++i
) {
1020 reloc
= kxld_array_get_item(relocs
, i
);
1021 if (!reloc
->pcrel
) {
1022 size
+= sizeof(struct relocation_info
);
1023 if(reloc
->pair_target_type
!= KXLD_TARGET_NONE
) {
1024 size
+= sizeof(struct relocation_info
);
1032 /*******************************************************************************
1033 *******************************************************************************/
1034 static kern_return_t
1035 export_macho_for_array(const KXLDRelocator
*relocator
,
1036 const KXLDArray
*relocs
, struct relocation_info
**dstp
)
1038 kern_return_t rval
= KERN_FAILURE
;
1039 const KXLDReloc
*reloc
= NULL
;
1040 struct relocation_info
*dst
= NULL
;
1041 struct scattered_relocation_info
*scatdst
= NULL
;
1046 for (i
= 0; i
< relocs
->nitems
; ++i
) {
1047 reloc
= kxld_array_get_item(relocs
, i
);
1048 scatdst
= (struct scattered_relocation_info
*) dst
;
1054 switch (reloc
->target_type
) {
1055 case KXLD_TARGET_LOOKUP
:
1056 scatdst
->r_address
= reloc
->address
;
1057 scatdst
->r_pcrel
= reloc
->pcrel
;
1058 scatdst
->r_length
= reloc
->length
;
1059 scatdst
->r_type
= reloc
->reloc_type
;
1060 scatdst
->r_value
= reloc
->target
;
1061 scatdst
->r_scattered
= 1;
1063 case KXLD_TARGET_SECTNUM
:
1064 dst
->r_address
= reloc
->address
;
1065 dst
->r_pcrel
= reloc
->pcrel
;
1066 dst
->r_length
= reloc
->length
;
1067 dst
->r_type
= reloc
->reloc_type
;
1068 dst
->r_symbolnum
= reloc
->target
+ 1;
1071 case KXLD_TARGET_SYMBOLNUM
:
1072 /* Assume that everything will be slid together; otherwise,
1073 * there is no sensible value for the section number.
1075 dst
->r_address
= reloc
->address
;
1076 dst
->r_pcrel
= reloc
->pcrel
;
1077 dst
->r_length
= reloc
->length
;
1078 dst
->r_type
= reloc
->reloc_type
;
1079 dst
->r_symbolnum
= 1;
1083 rval
= KERN_FAILURE
;
1089 if(reloc
->pair_target_type
!= KXLD_TARGET_NONE
) {
1091 require_action(i
< relocs
->nitems
, finish
, rval
=KERN_FAILURE
);
1092 scatdst
= (struct scattered_relocation_info
*) dst
;
1093 switch (reloc
->pair_target_type
) {
1094 case KXLD_TARGET_LOOKUP
:
1095 scatdst
->r_address
= reloc
->pair_address
;
1096 scatdst
->r_pcrel
= reloc
->pcrel
;
1097 scatdst
->r_length
= reloc
->length
;
1098 scatdst
->r_type
= relocator
->reloc_get_pair_type(reloc
->reloc_type
);
1099 scatdst
->r_value
= reloc
->pair_target
;
1100 scatdst
->r_scattered
= 1;
1102 case KXLD_TARGET_SECTNUM
:
1103 dst
->r_address
= reloc
->pair_address
;
1104 dst
->r_pcrel
= reloc
->pcrel
;
1105 dst
->r_length
= reloc
->length
;
1106 dst
->r_type
= relocator
->reloc_get_pair_type(reloc
->reloc_type
);
1107 dst
->r_symbolnum
= reloc
->pair_target
+ 1;
1110 case KXLD_TARGET_SYMBOLNUM
:
1111 dst
->r_address
= reloc
->pair_address
;
1112 dst
->r_pcrel
= reloc
->pcrel
;
1113 dst
->r_length
= reloc
->length
;
1114 dst
->r_type
= relocator
->reloc_get_pair_type(reloc
->reloc_type
);
1115 dst
->r_symbolnum
= 1;
1119 rval
= KERN_FAILURE
;
1126 rval
= KERN_SUCCESS
;
1131 #endif /* KXLD_PIC_KEXTS */
1133 #if KXLD_USER_OR_I386
1134 /*******************************************************************************
1135 *******************************************************************************/
1137 generic_reloc_has_pair(u_int _type
)
1139 enum reloc_type_generic type
= _type
;
1141 return (type
== GENERIC_RELOC_SECTDIFF
||
1142 type
== GENERIC_RELOC_LOCAL_SECTDIFF
);
1145 /*******************************************************************************
1146 *******************************************************************************/
1148 generic_reloc_get_pair_type(u_int _prev_type __unused
)
1150 return GENERIC_RELOC_PAIR
;
1153 /*******************************************************************************
1154 *******************************************************************************/
1155 static boolean_t
generic_reloc_has_got(u_int _type __unused
)
1160 /*******************************************************************************
1161 *******************************************************************************/
1162 static kern_return_t
1163 generic_process_reloc(const KXLDRelocator
*relocator
, u_char
*instruction
,
1164 u_int length
, u_int pcrel
, kxld_addr_t _base_pc
, kxld_addr_t _link_pc
,
1165 kxld_addr_t _link_disp __unused
, u_int _type
, kxld_addr_t _target
,
1166 kxld_addr_t _pair_target
, boolean_t swap __unused
)
1168 kern_return_t rval
= KERN_FAILURE
;
1169 uint32_t base_pc
= (uint32_t) _base_pc
;
1170 uint32_t link_pc
= (uint32_t) _link_pc
;
1171 uint32_t *instr_addr
= NULL
;
1172 uint32_t instr_data
= 0;
1173 uint32_t target
= (uint32_t) _target
;
1174 uint32_t pair_target
= (uint32_t) _pair_target
;
1175 enum reloc_type_generic type
= _type
;
1178 require_action(length
== 2, finish
, rval
=KERN_FAILURE
);
1180 if (pcrel
) target
= target
+ base_pc
- link_pc
;
1182 instr_addr
= (uint32_t *) ((void *) instruction
);
1183 instr_data
= *instr_addr
;
1186 if (swap
) instr_data
= OSSwapInt32(instr_data
);
1189 rval
= check_for_direct_pure_virtual_call(relocator
, instr_data
);
1190 require_noerr(rval
, finish
);
1193 case GENERIC_RELOC_VANILLA
:
1194 instr_data
+= target
;
1196 case GENERIC_RELOC_SECTDIFF
:
1197 case GENERIC_RELOC_LOCAL_SECTDIFF
:
1198 instr_data
= instr_data
+ target
- pair_target
;
1200 case GENERIC_RELOC_PB_LA_PTR
:
1201 rval
= KERN_FAILURE
;
1203 case GENERIC_RELOC_PAIR
:
1205 rval
= KERN_FAILURE
;
1210 if (swap
) instr_data
= OSSwapInt32(instr_data
);
1213 *instr_addr
= instr_data
;
1215 rval
= KERN_SUCCESS
;
1220 #endif /* KXLD_USER_OR_I386 */
1222 #if KXLD_USER_OR_X86_64
1223 /*******************************************************************************
1224 *******************************************************************************/
1226 x86_64_reloc_has_pair(u_int _type
)
1228 enum reloc_type_x86_64 type
= _type
;
1230 return (type
== X86_64_RELOC_SUBTRACTOR
);
1233 /*******************************************************************************
1234 *******************************************************************************/
1236 x86_64_reloc_get_pair_type(u_int _prev_type __unused
)
1238 return X86_64_RELOC_UNSIGNED
;
1241 /*******************************************************************************
1242 *******************************************************************************/
1244 x86_64_reloc_has_got(u_int _type
)
1246 enum reloc_type_x86_64 type
= _type
;
1248 return (type
== X86_64_RELOC_GOT_LOAD
|| type
== X86_64_RELOC_GOT
);
1251 /*******************************************************************************
1252 *******************************************************************************/
1253 static kern_return_t
1254 x86_64_process_reloc(const KXLDRelocator
*relocator __unused
, u_char
*instruction
,
1255 u_int length
, u_int pcrel
, kxld_addr_t _base_pc __unused
,
1256 kxld_addr_t _link_pc
, kxld_addr_t _link_disp
, u_int _type
,
1257 kxld_addr_t _target
, kxld_addr_t _pair_target
, boolean_t swap __unused
)
1259 kern_return_t rval
= KERN_FAILURE
;
1260 enum reloc_type_x86_64 type
= _type
;
1261 int32_t *instr32p
= NULL
;
1262 int32_t instr32
= 0;
1263 uint64_t *instr64p
= NULL
;
1264 uint64_t instr64
= 0;
1265 uint64_t target
= _target
;
1266 uint64_t pair_target
= _pair_target
;
1267 uint64_t link_pc
= (uint64_t) _link_pc
;
1268 uint64_t link_disp
= (uint64_t) _link_disp
;
1269 uint64_t adjustment
= 0;
1272 require_action(length
== 2 || length
== 3,
1273 finish
, rval
=KERN_FAILURE
);
1276 instr32p
= (int32_t *) ((void *) instruction
);
1277 instr32
= *instr32p
;
1280 if (swap
) instr32
= OSSwapInt32(instr32
);
1283 rval
= check_for_direct_pure_virtual_call(relocator
, instr32
);
1284 require_noerr(rval
, finish
);
1286 /* There are a number of different small adjustments for pc-relative
1287 * relocation entries. The general case is to subtract the size of the
1288 * relocation (represented by the length parameter), and it applies to
1289 * the GOT types and external SIGNED types. The non-external signed types
1290 * have a different adjustment corresponding to the specific type.
1293 case X86_64_RELOC_SIGNED
:
1299 case X86_64_RELOC_SIGNED_1
:
1305 case X86_64_RELOC_SIGNED_2
:
1311 case X86_64_RELOC_SIGNED_4
:
1317 case X86_64_RELOC_BRANCH
:
1318 case X86_64_RELOC_GOT
:
1319 case X86_64_RELOC_GOT_LOAD
:
1320 adjustment
= (1 << length
);
1326 /* Perform the actual relocation. All of the 32-bit relocations are
1327 * pc-relative except for SUBTRACTOR, so a good chunk of the logic is
1328 * stuck in calculate_displacement_x86_64. The signed relocations are
1329 * a special case, because when they are non-external, the instruction
1330 * already contains the pre-relocation displacement, so we only need to
1331 * find the difference between how far the PC was relocated, and how
1332 * far the target is relocated. Since the target variable already
1333 * contains the difference between the target's base and link
1334 * addresses, we add the difference between the PC's base and link
1335 * addresses to the adjustment variable. This will yield the
1336 * appropriate displacement in calculate_displacement.
1339 case X86_64_RELOC_BRANCH
:
1340 require_action(pcrel
, finish
, rval
=KERN_FAILURE
);
1341 adjustment
+= link_pc
;
1343 case X86_64_RELOC_SIGNED
:
1344 case X86_64_RELOC_SIGNED_1
:
1345 case X86_64_RELOC_SIGNED_2
:
1346 case X86_64_RELOC_SIGNED_4
:
1347 require_action(pcrel
, finish
, rval
=KERN_FAILURE
);
1348 adjustment
+= (pair_target
) ? (link_disp
) : (link_pc
);
1350 case X86_64_RELOC_GOT
:
1351 case X86_64_RELOC_GOT_LOAD
:
1352 require_action(pcrel
, finish
, rval
=KERN_FAILURE
);
1353 adjustment
+= link_pc
;
1354 target
= pair_target
;
1356 case X86_64_RELOC_SUBTRACTOR
:
1357 require_action(!pcrel
, finish
, rval
=KERN_FAILURE
);
1358 instr32
= (int32_t) (target
- pair_target
);
1360 case X86_64_RELOC_UNSIGNED
:
1362 rval
= KERN_FAILURE
;
1366 /* Call calculate_displacement for the pc-relative relocations */
1368 rval
= calculate_displacement_x86_64(target
, adjustment
, &instr32
);
1369 require_noerr(rval
, finish
);
1373 if (swap
) instr32
= OSSwapInt32(instr32
);
1376 *instr32p
= instr32
;
1378 instr64p
= (uint64_t *) ((void *) instruction
);
1379 instr64
= *instr64p
;
1382 if (swap
) instr64
= OSSwapInt64(instr64
);
1385 rval
= check_for_direct_pure_virtual_call(relocator
, (u_long
) instr64
);
1386 require_noerr(rval
, finish
);
1389 case X86_64_RELOC_UNSIGNED
:
1390 require_action(!pcrel
, finish
, rval
=KERN_FAILURE
);
1394 case X86_64_RELOC_SUBTRACTOR
:
1395 require_action(!pcrel
, finish
, rval
=KERN_FAILURE
);
1397 instr64
= target
- pair_target
;
1399 case X86_64_RELOC_SIGNED_1
:
1400 case X86_64_RELOC_SIGNED_2
:
1401 case X86_64_RELOC_SIGNED_4
:
1402 case X86_64_RELOC_GOT_LOAD
:
1403 case X86_64_RELOC_BRANCH
:
1404 case X86_64_RELOC_SIGNED
:
1405 case X86_64_RELOC_GOT
:
1407 rval
= KERN_FAILURE
;
1412 if (swap
) instr64
= OSSwapInt64(instr64
);
1415 *instr64p
= instr64
;
1418 rval
= KERN_SUCCESS
;
1424 /*******************************************************************************
1425 *******************************************************************************/
1426 static kern_return_t
1427 calculate_displacement_x86_64(uint64_t target
, uint64_t adjustment
,
1430 kern_return_t rval
= KERN_FAILURE
;
1431 int64_t displacement
;
1432 uint64_t difference
;
1434 displacement
= *instr32
+ target
- adjustment
;
1435 difference
= ABSOLUTE_VALUE(displacement
);
1436 require_action(difference
< X86_64_RIP_RELATIVE_LIMIT
, finish
,
1438 kxld_log(kKxldLogLinking
, kKxldLogErr
, kKxldLogRelocationOverflow
));
1440 *instr32
= (int32_t) displacement
;
1441 rval
= KERN_SUCCESS
;
1446 #endif /* KXLD_USER_OR_X86_64 */
1448 #if KXLD_USER_OR_ARM
1449 /*******************************************************************************
1450 *******************************************************************************/
1452 arm_reloc_has_pair(u_int _type
)
1454 enum reloc_type_arm type
= _type
;
1457 case ARM_RELOC_SECTDIFF
:
1465 /*******************************************************************************
1466 *******************************************************************************/
1468 arm_reloc_get_pair_type(u_int _prev_type __unused
)
1470 return ARM_RELOC_PAIR
;
1473 /*******************************************************************************
1474 *******************************************************************************/
1476 arm_reloc_has_got(u_int _type __unused
)
1481 /*******************************************************************************
1482 *******************************************************************************/
1483 static kern_return_t
1484 arm_process_reloc(const KXLDRelocator
*relocator __unused
, u_char
*instruction
,
1485 u_int length
, u_int pcrel
, kxld_addr_t _base_pc __unused
,
1486 kxld_addr_t _link_pc __unused
, kxld_addr_t _link_disp __unused
,
1487 u_int _type __unused
, kxld_addr_t _target __unused
,
1488 kxld_addr_t _pair_target __unused
, boolean_t swap __unused
)
1490 kern_return_t rval
= KERN_FAILURE
;
1491 uint32_t *instr_addr
= NULL
;
1492 uint32_t instr_data
= 0;
1493 uint32_t base_pc
= (uint32_t) _base_pc
;
1494 uint32_t link_pc
= (uint32_t) _link_pc
;
1495 uint32_t target
= (uint32_t) _target
;
1496 int32_t displacement
= 0;
1497 enum reloc_type_arm type
= _type
;
1500 require_action(length
== 2, finish
, rval
=KERN_FAILURE
);
1502 if (pcrel
) displacement
= target
+ base_pc
- link_pc
;
1504 instr_addr
= (uint32_t *) ((void *) instruction
);
1505 instr_data
= *instr_addr
;
1508 if (swap
) instr_data
= OSSwapInt32(instr_data
);
1511 rval
= check_for_direct_pure_virtual_call(relocator
, instr_data
);
1512 require_noerr(rval
, finish
);
1515 case ARM_RELOC_VANILLA
:
1516 instr_data
+= target
;
1520 * If the displacement is 0 (the offset between the pc and the target has
1521 * not changed), then we don't need to do anything for BR24 and BR22
1522 * relocs. As it turns out, because kexts build with -mlong-calls all
1523 * relocations currently end up being either vanilla (handled above) or
1524 * BR22/BR24 with a displacement of 0.
1525 * We could handle other displacements here but to keep things simple, we
1526 * won't until it is needed (at which point the kernelcache will fail to
1529 case ARM_RELOC_BR24
:
1530 require_action(pcrel
, finish
, rval
=KERN_FAILURE
);
1531 require_action(displacement
== 0, finish
, rval
=KERN_FAILURE
);
1533 case ARM_THUMB_RELOC_BR22
:
1534 require_action(pcrel
, finish
, rval
=KERN_FAILURE
);
1535 require_action(displacement
== 0, finish
, rval
=KERN_FAILURE
);
1538 case ARM_RELOC_SECTDIFF
:
1539 case ARM_RELOC_LOCAL_SECTDIFF
:
1540 case ARM_RELOC_PB_LA_PTR
:
1541 rval
= KERN_FAILURE
;
1544 case ARM_RELOC_PAIR
:
1546 rval
= KERN_FAILURE
;
1551 if (swap
) instr_data
= OSSwapInt32(instr_data
);
1554 *instr_addr
= instr_data
;
1556 rval
= KERN_SUCCESS
;
1562 #endif /* KXLD_USER_OR_ARM */
1564 #if KXLD_USER_OR_ARM64
1565 /*******************************************************************************
1566 *******************************************************************************/
1568 arm64_reloc_has_pair(u_int _type
)
1570 return (_type
== ARM64_RELOC_SUBTRACTOR
);
1573 /*******************************************************************************
1574 *******************************************************************************/
1576 arm64_reloc_get_pair_type(u_int _prev_type __unused
)
1578 if (_prev_type
== ARM64_RELOC_SUBTRACTOR
) {
1579 return ARM64_RELOC_UNSIGNED
;
1585 /*******************************************************************************
1586 *******************************************************************************/
1588 arm64_reloc_has_got(u_int _type
)
1590 return (_type
== ARM64_RELOC_GOT_LOAD_PAGE21
||
1591 _type
== ARM64_RELOC_GOT_LOAD_PAGEOFF12
);
1594 /*******************************************************************************
1595 *******************************************************************************/
1597 arm64_process_reloc(const KXLDRelocator
*relocator __unused
, u_char
*instruction
,
1598 u_int length
, u_int pcrel
, kxld_addr_t _base_pc __unused
, kxld_addr_t _link_pc
,
1599 kxld_addr_t _link_disp __unused
, u_int _type
, kxld_addr_t _target
,
1600 kxld_addr_t _pair_target __unused
, boolean_t swap
)
1602 kern_return_t rval
= KERN_FAILURE
;
1603 enum reloc_type_arm64 type
= _type
;
1604 uint64_t target
= _target
;
1605 uint64_t link_pc
= (uint64_t) _link_pc
;
1606 uint64_t difference
= 0;
1607 int64_t displacement
= 0;
1608 uint32_t addend
= 0;
1611 require_action((length
== 2 || length
== 3), finish
, rval
=KERN_FAILURE
);
1614 uint32_t *instr32p
= (uint32_t *) (void *) instruction
;
1615 uint32_t instr32
= *instr32p
;
1618 if (swap
) instr32
= OSSwapInt32(instr32
);
1622 case ARM64_RELOC_BRANCH26
:
1623 require_action(pcrel
, finish
, rval
=KERN_FAILURE
);
1624 addend
= (instr32
& 0x03FFFFFF) << 2;
1625 addend
= SIGN_EXTEND(addend
, 27);
1626 displacement
= (target
- link_pc
+ addend
);
1627 difference
= ABSOLUTE_VALUE(displacement
);
1628 displacement
= (displacement
>> 2);
1629 require_action(difference
< (128 * 1024 * 1024), finish
,
1630 rval
= KERN_FAILURE
;
1631 kxld_log(kKxldLogLinking
, kKxldLogErr
, kKxldLogRelocationOverflow
));
1632 instr32
= (instr32
& 0xFC000000) | (displacement
& 0x03FFFFFF);
1636 rval
= KERN_FAILURE
;
1641 if (swap
) instr32
= OSSwapInt32(instr32
);
1644 *instr32p
= instr32
;
1645 } else { /* length == 3 */
1646 uint64_t *instr64p
= (uint64_t *) (void *) instruction
;
1647 uint64_t instr64
= *instr64p
;
1650 if (swap
) instr64
= OSSwapInt64(instr64
);
1654 case ARM64_RELOC_UNSIGNED
:
1655 require_action(!pcrel
, finish
, rval
=KERN_FAILURE
);
1659 rval
= KERN_FAILURE
;
1664 if (swap
) instr64
= OSSwapInt64(instr64
);
1667 *instr64p
= instr64
;
1670 rval
= KERN_SUCCESS
;
1675 #endif /* KXLD_USER_OR_ARM64 */