]> git.saurik.com Git - apple/xnu.git/blob - libkern/kxld/kxld_reloc.c
4867c8c78e41dc186299072a50ca67a16ef027ec
[apple/xnu.git] / libkern / kxld / kxld_reloc.c
1 /*
2 * Copyright (c) 2007-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <string.h>
29 #include <mach/boolean.h>
30 #include <mach/machine.h>
31 #include <sys/types.h>
32
33 #if KERNEL
34 #include <libkern/libkern.h>
35 #else
36 #include <libkern/OSByteOrder.h>
37 #include <stdlib.h>
38 #endif
39
40 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
41 #include <AssertMacros.h>
42
43 #include "kxld_array.h"
44 #include "kxld_demangle.h"
45 #include "kxld_dict.h"
46 #include "kxld_reloc.h"
47 #include "kxld_sect.h"
48 #include "kxld_seg.h"
49 #include "kxld_sym.h"
50 #include "kxld_symtab.h"
51 #include "kxld_util.h"
52 #include "kxld_vtable.h"
53
54 /* include target-specific relocation prototypes */
55 #include <mach-o/reloc.h>
56 #if KXLD_USER_OR_PPC
57 #include <mach-o/ppc/reloc.h>
58 #endif
59 #if KXLD_USER_OR_X86_64
60 #include <mach-o/x86_64/reloc.h>
61 #endif
62 #if KXLD_USER_OR_ARM
63 #include <mach-o/arm/reloc.h>
64 #endif
65
66 #define KXLD_TARGET_NONE (u_int) 0x0
67 #define KXLD_TARGET_VALUE (u_int) 0x1
68 #define KXLD_TARGET_SECTNUM (u_int) 0x2
69 #define KXLD_TARGET_SYMBOLNUM (u_int) 0x3
70 #define KXLD_TARGET_LOOKUP (u_int) 0x4
71 #define KXLD_TARGET_GOT (u_int) 0x5
72
73 #define ABSOLUTE_VALUE(x) (((x) < 0) ? -(x) : (x))
74
75 #define LO16(x) (0x0000FFFF & x)
76 #define LO16S(x) ((0x0000FFFF & x) << 16)
77 #define HI16(x) (0xFFFF0000 & x)
78 #define HI16S(x) ((0xFFFF0000 & x) >> 16)
79 #define BIT15(x) (0x00008000 & x)
80 #define BR14I(x) (0xFFFF0003 & x)
81 #define BR14D(x) (0x0000FFFC & x)
82 #define BR24I(x) (0xFC000003 & x)
83 #define BR24D(x) (0x03FFFFFC & x)
84 #define HADISP 0x00010000
85 #define BR14_LIMIT 0x00008000
86 #define BR24_LIMIT 0x02000000
87 #define IS_COND_BR_INSTR(x) ((x & 0xFC000000) == 0x40000000)
88 #define IS_NOT_ALWAYS_TAKEN(x) ((x & 0x03E00000) != 0x02800000)
89 #define FLIP_PREDICT_BIT(x) x ^= 0x00200000
90
91 #define SIGN_EXTEND_MASK(n) (1 << ((n) - 1))
92 #define SIGN_EXTEND(x,n) (((x) ^ SIGN_EXTEND_MASK(n)) - SIGN_EXTEND_MASK(n))
93 #define BR14_NBITS_DISPLACEMENT 16
94 #define BR24_NBITS_DISPLACEMENT 26
95
96 #define X86_64_RIP_RELATIVE_LIMIT 0x80000000UL
97
98 /*******************************************************************************
99 * Prototypes
100 *******************************************************************************/
101 #if KXLD_USER_OR_I386
102 static boolean_t generic_reloc_has_pair(u_int _type)
103 __attribute__((const));
104 static boolean_t generic_reloc_is_pair(u_int _type, u_int _prev_type)
105 __attribute__((const));
106 static boolean_t generic_reloc_has_got(u_int _type)
107 __attribute__((const));
108 static kern_return_t generic_process_reloc(const KXLDRelocator *relocator,
109 u_char *instruction, u_int length, u_int pcrel, kxld_addr_t base_pc,
110 kxld_addr_t link_pc, kxld_addr_t link_disp, u_int type, kxld_addr_t target,
111 kxld_addr_t pair_target, boolean_t swap);
112 #endif /* KXLD_USER_OR_I386 */
113
114 #if KXLD_USER_OR_PPC
115 static boolean_t ppc_reloc_has_pair(u_int _type)
116 __attribute__((const));
117 static boolean_t ppc_reloc_is_pair(u_int _type, u_int _prev_type)
118 __attribute__((const));
119 static boolean_t ppc_reloc_has_got(u_int _type)
120 __attribute__((const));
121 static kern_return_t ppc_process_reloc(const KXLDRelocator *relocator,
122 u_char *instruction, u_int length, u_int pcrel, kxld_addr_t base_pc,
123 kxld_addr_t link_pc, kxld_addr_t link_disp, u_int type, kxld_addr_t target,
124 kxld_addr_t pair_target, boolean_t swap);
125 #endif /* KXLD_USER_OR_PPC */
126
127 #if KXLD_USER_OR_X86_64
128 static boolean_t x86_64_reloc_has_pair(u_int _type)
129 __attribute__((const));
130 static boolean_t x86_64_reloc_is_pair(u_int _type, u_int _prev_type)
131 __attribute__((const));
132 static boolean_t x86_64_reloc_has_got(u_int _type)
133 __attribute__((const));
134 static kern_return_t x86_64_process_reloc(const KXLDRelocator *relocator,
135 u_char *instruction, u_int length, u_int pcrel, kxld_addr_t base_pc,
136 kxld_addr_t link_pc, kxld_addr_t link_disp, u_int type, kxld_addr_t target,
137 kxld_addr_t pair_target, boolean_t swap);
138 static kern_return_t calculate_displacement_x86_64(uint64_t target,
139 uint64_t adjustment, int32_t *instr32);
140 #endif /* KXLD_USER_OR_X86_64 */
141
142 #if KXLD_USER_OR_ARM
143 static boolean_t arm_reloc_has_pair(u_int _type)
144 __attribute__((const));
145 static boolean_t arm_reloc_is_pair(u_int _type, u_int _prev_type)
146 __attribute__((const));
147 static boolean_t arm_reloc_has_got(u_int _type)
148 __attribute__((const));
149 static kern_return_t arm_process_reloc(const KXLDRelocator *relocator,
150 u_char *instruction, u_int length, u_int pcrel, kxld_addr_t base_pc,
151 kxld_addr_t link_pc, kxld_addr_t link_disp, u_int type, kxld_addr_t target,
152 kxld_addr_t pair_target, boolean_t swap);
153 #endif /* KXLD_USER_OR_ARM */
154
155 #if KXLD_USER_OR_ILP32
156 static kxld_addr_t get_pointer_at_addr_32(const KXLDRelocator *relocator,
157 const u_char *data, u_long offset)
158 __attribute__((pure, nonnull));
159 #endif /* KXLD_USER_OR_ILP32 */
160 #if KXLD_USER_OR_LP64
161 static kxld_addr_t get_pointer_at_addr_64(const KXLDRelocator *relocator,
162 const u_char *data, u_long offset)
163 __attribute__((pure, nonnull));
164 #endif /* KXLD_USER_OR_LP64 */
165
166 static u_int count_relocatable_relocs(const KXLDRelocator *relocator,
167 const struct relocation_info *relocs, u_int nrelocs)
168 __attribute__((pure));
169
170 static kern_return_t calculate_targets(KXLDRelocator *relocator,
171 kxld_addr_t *_target, kxld_addr_t *_pair_target, const KXLDReloc *reloc);
172
173 static kxld_addr_t align_raw_function_address(const KXLDRelocator *relocator,
174 kxld_addr_t value);
175
176 static kern_return_t get_target_by_address_lookup(kxld_addr_t *target,
177 kxld_addr_t addr, const KXLDArray *sectarray);
178
179 static kern_return_t check_for_direct_pure_virtual_call(
180 const KXLDRelocator *relocator, u_long offset);
181
182 /*******************************************************************************
183 *******************************************************************************/
184 kern_return_t
185 kxld_relocator_init(KXLDRelocator *relocator, u_char *file,
186 const KXLDSymtab *symtab, const KXLDArray *sectarray, cpu_type_t cputype,
187 cpu_subtype_t cpusubtype __unused, boolean_t swap)
188 {
189 kern_return_t rval = KERN_FAILURE;
190
191 check(relocator);
192
193 switch(cputype) {
194 #if KXLD_USER_OR_I386
195 case CPU_TYPE_I386:
196 relocator->reloc_has_pair = generic_reloc_has_pair;
197 relocator->reloc_is_pair = generic_reloc_is_pair;
198 relocator->reloc_has_got = generic_reloc_has_got;
199 relocator->process_reloc = generic_process_reloc;
200 relocator->function_align = 0;
201 relocator->is_32_bit = TRUE;
202 break;
203 #endif /* KXLD_USER_OR_I386 */
204 #if KXLD_USER_OR_PPC
205 case CPU_TYPE_POWERPC:
206 relocator->reloc_has_pair = ppc_reloc_has_pair;
207 relocator->reloc_is_pair = ppc_reloc_is_pair;
208 relocator->reloc_has_got = ppc_reloc_has_got;
209 relocator->process_reloc = ppc_process_reloc;
210 relocator->function_align = 0;
211 relocator->is_32_bit = TRUE;
212 break;
213 #endif /* KXLD_USER_OR_PPC */
214 #if KXLD_USER_OR_X86_64
215 case CPU_TYPE_X86_64:
216 relocator->reloc_has_pair = x86_64_reloc_has_pair;
217 relocator->reloc_is_pair = x86_64_reloc_is_pair;
218 relocator->reloc_has_got = x86_64_reloc_has_got;
219 relocator->process_reloc = x86_64_process_reloc;
220 relocator->function_align = 0;
221 relocator->is_32_bit = FALSE;
222 break;
223 #endif /* KXLD_USER_OR_X86_64 */
224 #if KXLD_USER_OR_ARM
225 case CPU_TYPE_ARM:
226 relocator->reloc_has_pair = arm_reloc_has_pair;
227 relocator->reloc_is_pair = arm_reloc_is_pair;
228 relocator->reloc_has_got = arm_reloc_has_got;
229 relocator->process_reloc = arm_process_reloc;
230 relocator->function_align = 1;
231 relocator->is_32_bit = TRUE;
232 break;
233 #endif /* KXLD_USER_OR_ARM */
234 default:
235 rval = KERN_FAILURE;
236 kxld_log(kKxldLogLinking, kKxldLogErr,
237 kKxldLogArchNotSupported, cputype);
238 goto finish;
239 }
240
241 relocator->file = file;
242 relocator->symtab = symtab;
243 relocator->sectarray = sectarray;
244 relocator->is_32_bit = kxld_is_32_bit(cputype);
245 relocator->swap = swap;
246
247 rval = KERN_SUCCESS;
248
249 finish:
250 return rval;
251 }
252
253 /*******************************************************************************
254 *******************************************************************************/
255 kern_return_t
256 kxld_reloc_create_macho(KXLDArray *relocarray, const KXLDRelocator *relocator,
257 const struct relocation_info *srcs, u_int nsrcs)
258 {
259 kern_return_t rval = KERN_FAILURE;
260 KXLDReloc *reloc = NULL;
261 u_int nrelocs = 0;
262 const struct relocation_info *src = NULL;
263 const struct scattered_relocation_info *scatsrc = NULL;
264 u_int i = 0;
265 u_int reloc_index = 0;
266
267 check(relocarray);
268 check(srcs);
269
270 /* If there are no relocation entries, just return */
271 if (!nsrcs) {
272 rval = KERN_SUCCESS;
273 goto finish;
274 }
275
276 /* Count the number of non-pair relocs */
277 nrelocs = count_relocatable_relocs(relocator, srcs, nsrcs);
278
279 if (nrelocs) {
280
281 /* Allocate the array of relocation entries */
282
283 rval = kxld_array_init(relocarray, sizeof(KXLDReloc), nrelocs);
284 require_noerr(rval, finish);
285
286 /* Initialize the relocation entries */
287
288 for (i = 0; i < nsrcs; ++i) {
289 src = srcs + i;
290 scatsrc = (const struct scattered_relocation_info *) src;
291
292 /* A section-based relocation entry can be skipped for absolute
293 * symbols.
294 */
295
296 if (!(src->r_address & R_SCATTERED) && !(src->r_extern) &&
297 (R_ABS == src->r_symbolnum))
298 {
299 continue;
300 }
301
302 /* Pull out the data from the relocation entries. The target_type
303 * depends on the r_extern bit:
304 * Scattered -> Section Lookup by Address
305 * Local (not extern) -> Section by Index
306 * Extern -> Symbolnum by Index
307 */
308 reloc = kxld_array_get_item(relocarray, reloc_index++);
309 if (src->r_address & R_SCATTERED) {
310 reloc->address = scatsrc->r_address;
311 reloc->pcrel = scatsrc->r_pcrel;
312 reloc->length = scatsrc->r_length;
313 reloc->reloc_type = scatsrc->r_type;
314 reloc->target = scatsrc->r_value;
315 reloc->target_type = KXLD_TARGET_LOOKUP;
316 } else {
317 reloc->address = src->r_address;
318 reloc->pcrel = src->r_pcrel;
319 reloc->length = src->r_length;
320 reloc->reloc_type = src->r_type;
321 reloc->target = src->r_symbolnum;
322
323 if (0 == src->r_extern) {
324 reloc->target_type = KXLD_TARGET_SECTNUM;
325 reloc->target -= 1;
326 } else {
327 reloc->target_type = KXLD_TARGET_SYMBOLNUM;
328 }
329 }
330
331 /* Find the pair entry if it exists */
332
333 if (relocator->reloc_has_pair(reloc->reloc_type)) {
334 ++i;
335 require_action(i < nsrcs, finish, rval=KERN_FAILURE);
336
337 src = srcs + i;
338 scatsrc = (const struct scattered_relocation_info *) src;
339
340 if (src->r_address & R_SCATTERED) {
341 require_action(relocator->reloc_is_pair(
342 scatsrc->r_type, reloc->reloc_type),
343 finish, rval=KERN_FAILURE);
344 reloc->pair_target = scatsrc->r_value;
345 reloc->pair_target_type = KXLD_TARGET_LOOKUP;
346 } else {
347 require_action(relocator->reloc_is_pair(src->r_type,
348 reloc->reloc_type), finish, rval=KERN_FAILURE);
349
350 if (src->r_extern) {
351 reloc->pair_target = src->r_symbolnum;
352 reloc->pair_target_type = KXLD_TARGET_SYMBOLNUM;
353 } else {
354 reloc->pair_target = src->r_address;
355 reloc->pair_target_type = KXLD_TARGET_VALUE;
356 }
357 }
358 } else {
359 reloc->pair_target = 0;
360 if (relocator->reloc_has_got(reloc->reloc_type)) {
361 reloc->pair_target_type = KXLD_TARGET_GOT;
362 } else {
363 reloc->pair_target_type = KXLD_TARGET_NONE;
364 }
365 }
366 }
367 }
368
369 rval = KERN_SUCCESS;
370
371 finish:
372 return rval;
373 }
374
375
376 /*******************************************************************************
377 * Relocatable relocs :
378 * 1) Are not _PAIR_ relocs
379 * 2) Don't reference N_ABS symbols
380 *******************************************************************************/
381 static u_int
382 count_relocatable_relocs(const KXLDRelocator *relocator,
383 const struct relocation_info *relocs, u_int nrelocs)
384 {
385 u_int num_nonpair_relocs = 0;
386 u_int i = 0;
387 u_int prev_type = 0;
388 const struct relocation_info *reloc = NULL;
389 const struct scattered_relocation_info *sreloc = NULL;
390
391 check(relocator);
392 check(relocs);
393
394 /* Loop over all of the relocation entries */
395
396 num_nonpair_relocs = 1;
397 prev_type = relocs->r_type;
398 for (i = 1; i < nrelocs; ++i) {
399 reloc = relocs + i;
400
401 if (reloc->r_address & R_SCATTERED) {
402 /* A scattered relocation entry is relocatable as long as it's not a
403 * pair.
404 */
405 sreloc = (const struct scattered_relocation_info *) reloc;
406
407 num_nonpair_relocs +=
408 (!relocator->reloc_is_pair(sreloc->r_type, prev_type));
409
410 prev_type = sreloc->r_type;
411 } else {
412 /* A normal relocation entry is relocatable if it is not a pair and
413 * if it is not a section-based relocation for an absolute symbol.
414 */
415 num_nonpair_relocs +=
416 !(relocator->reloc_is_pair(reloc->r_type, prev_type)
417 || (0 == reloc->r_extern && R_ABS == reloc->r_symbolnum));
418
419 prev_type = reloc->r_type;
420 }
421
422 }
423
424 return num_nonpair_relocs;
425 }
426
427 /*******************************************************************************
428 *******************************************************************************/
429 void
430 kxld_relocator_clear(KXLDRelocator *relocator)
431 {
432 bzero(relocator, sizeof(*relocator));
433 }
434
435 /*******************************************************************************
436 *******************************************************************************/
437 boolean_t
438 kxld_relocator_has_pair(const KXLDRelocator *relocator, u_int r_type)
439 {
440 check(relocator);
441
442 return relocator->reloc_has_pair(r_type);
443 }
444
445 /*******************************************************************************
446 *******************************************************************************/
447 boolean_t
448 kxld_relocator_is_pair(const KXLDRelocator *relocator, u_int r_type,
449 u_int prev_r_type)
450 {
451 check(relocator);
452
453 return relocator->reloc_is_pair(r_type, prev_r_type);
454 }
455
456 /*******************************************************************************
457 *******************************************************************************/
458 boolean_t
459 kxld_relocator_has_got(const KXLDRelocator *relocator, u_int r_type)
460 {
461 check(relocator);
462
463 return relocator->reloc_has_got(r_type);
464 }
465
466 /*******************************************************************************
467 *******************************************************************************/
468 KXLDSym *
469 kxld_reloc_get_symbol(const KXLDRelocator *relocator, const KXLDReloc *reloc,
470 const u_char *data)
471 {
472 KXLDSym *sym = NULL;
473 kxld_addr_t value = 0;
474
475 check(reloc);
476
477 switch (reloc->target_type) {
478 case KXLD_TARGET_SYMBOLNUM:
479 sym = kxld_symtab_get_symbol_by_index(relocator->symtab, reloc->target);
480 break;
481 case KXLD_TARGET_SECTNUM:
482 if (data) {
483 value = kxld_relocator_get_pointer_at_addr(relocator, data,
484 reloc->address);
485 sym = kxld_symtab_get_cxx_symbol_by_value(relocator->symtab, value);
486 }
487 break;
488 default:
489 sym = NULL;
490 break;
491 }
492
493 return sym;
494 }
495
496 /*******************************************************************************
497 *******************************************************************************/
498 kern_return_t
499 kxld_reloc_get_reloc_index_by_offset(const KXLDArray *relocs,
500 kxld_size_t offset, u_int *idx)
501 {
502 kern_return_t rval = KERN_FAILURE;
503 KXLDReloc *reloc = NULL;
504 u_int i = 0;
505
506 for (i = 0; i < relocs->nitems; ++i) {
507 reloc = kxld_array_get_item(relocs, i);
508 if (reloc->address == offset) break;
509 }
510
511 if (i >= relocs->nitems) {
512 rval = KERN_FAILURE;
513 goto finish;
514 }
515
516 *idx = i;
517 rval = KERN_SUCCESS;
518
519 finish:
520 return rval;
521 }
522
523 /*******************************************************************************
524 *******************************************************************************/
525 KXLDReloc *
526 kxld_reloc_get_reloc_by_offset(const KXLDArray *relocs, kxld_addr_t offset)
527 {
528 kern_return_t rval = KERN_FAILURE;
529 KXLDReloc *reloc = NULL;
530 u_int i = 0;
531
532 rval = kxld_reloc_get_reloc_index_by_offset(relocs, offset, &i);
533 if (rval) goto finish;
534
535 reloc = kxld_array_get_item(relocs, i);
536
537 finish:
538 return reloc;
539 }
540
541 /*******************************************************************************
542 *******************************************************************************/
543 kxld_addr_t
544 kxld_relocator_get_pointer_at_addr(const KXLDRelocator *relocator,
545 const u_char *data, u_long offset)
546 {
547 kxld_addr_t value;
548
549 KXLD_3264_FUNC(relocator->is_32_bit, value,
550 get_pointer_at_addr_32, get_pointer_at_addr_64,
551 relocator, data, offset);
552
553 return value;
554 }
555
556 #if KXLD_USER_OR_ILP32
557 /*******************************************************************************
558 *******************************************************************************/
559 static kxld_addr_t
560 get_pointer_at_addr_32(const KXLDRelocator *relocator,
561 const u_char *data, u_long offset)
562 {
563 uint32_t addr = 0;
564
565 check(relocator);
566
567 addr = *(const uint32_t *) (data + offset);
568 #if !KERNEL
569 if (relocator->swap) {
570 addr = OSSwapInt32(addr);
571 }
572 #endif
573
574 return align_raw_function_address(relocator, addr);
575 }
576 #endif /* KXLD_USER_OR_ILP32 */
577
578 #if KXLD_USER_OR_LP64
579 /*******************************************************************************
580 *******************************************************************************/
581 static kxld_addr_t
582 get_pointer_at_addr_64(const KXLDRelocator *relocator,
583 const u_char *data, u_long offset)
584 {
585 uint64_t addr = 0;
586
587 check(relocator);
588
589 addr = *(const uint64_t *) (data + offset);
590 #if !KERNEL
591 if (relocator->swap) {
592 addr = OSSwapInt64(addr);
593 }
594 #endif
595
596 return align_raw_function_address(relocator, addr);
597 }
598 #endif /* KXLD_USER_OR_LP64 */
599
600 /*******************************************************************************
601 *******************************************************************************/
602 void
603 kxld_relocator_set_vtables(KXLDRelocator *relocator,
604 const struct kxld_dict *vtables)
605 {
606 relocator->vtables = vtables;
607 }
608
609 /*******************************************************************************
610 * When we're inspecting the raw binary and not the symbol table, value may
611 * hold a THUMB address (with bit 0 set to 1) but the index will have the real
612 * address (bit 0 set to 0). So if bit 0 is set here, we clear it. This only
613 * impacts ARM for now, but it's implemented as a generic function alignment
614 * mask.
615 *******************************************************************************/
616 static kxld_addr_t
617 align_raw_function_address(const KXLDRelocator *relocator, kxld_addr_t value)
618 {
619 if (relocator->function_align) {
620 value &= ~((1ULL << relocator->function_align) - 1);
621 }
622
623 return value;
624 }
625
626 /*******************************************************************************
627 *******************************************************************************/
628 kern_return_t
629 kxld_relocator_process_sect_reloc(KXLDRelocator *relocator,
630 const KXLDReloc *reloc, const struct kxld_sect *sect)
631 {
632 kern_return_t rval = KERN_FAILURE;
633 u_char *instruction = NULL;
634 kxld_addr_t target = 0;
635 kxld_addr_t pair_target = 0;
636 kxld_addr_t base_pc = 0;
637 kxld_addr_t link_pc = 0;
638 kxld_addr_t link_disp = 0;
639
640 check(relocator);
641 check(reloc);
642 check(sect);
643
644 /* Find the instruction */
645
646 instruction = sect->data + reloc->address;
647
648 /* Calculate the target */
649
650 rval = calculate_targets(relocator, &target, &pair_target, reloc);
651 require_noerr(rval, finish);
652
653 base_pc = reloc->address;
654 link_pc = base_pc + sect->link_addr;
655 link_disp = sect->link_addr - sect->base_addr;
656
657 /* Relocate */
658
659 rval = relocator->process_reloc(relocator, instruction, reloc->length,
660 reloc->pcrel, base_pc, link_pc, link_disp, reloc->reloc_type, target,
661 pair_target, relocator->swap);
662 require_noerr(rval, finish);
663
664 /* Return */
665
666 relocator->current_vtable = NULL;
667 rval = KERN_SUCCESS;
668
669 finish:
670 return rval;
671 }
672
673 /*******************************************************************************
674 *******************************************************************************/
675 kern_return_t
676 kxld_reloc_update_symindex(KXLDReloc *reloc, u_int symindex)
677 {
678 kern_return_t rval = KERN_FAILURE;
679
680 require_action(reloc->target_type == KXLD_TARGET_SYMBOLNUM,
681 finish, rval = KERN_FAILURE);
682
683 reloc->target = symindex;
684
685 rval = KERN_SUCCESS;
686
687 finish:
688 return rval;
689 }
690
691 /*******************************************************************************
692 *******************************************************************************/
693 kern_return_t
694 kxld_relocator_process_table_reloc(KXLDRelocator *relocator,
695 const KXLDReloc *reloc, const KXLDSeg *seg, kxld_addr_t link_addr)
696 {
697 kern_return_t rval = KERN_FAILURE;
698 u_char *instruction = NULL;
699 kxld_addr_t target = 0;
700 kxld_addr_t pair_target = 0;
701 kxld_addr_t base_pc = 0;
702 kxld_addr_t link_pc = 0;
703 u_long offset = 0;
704
705 check(relocator);
706 check(reloc);
707
708 /* Find the instruction */
709
710 offset = (u_long)(seg->fileoff + (reloc->address - seg->base_addr));
711 instruction = relocator->file + offset;
712
713 /* Calculate the target */
714
715 rval = calculate_targets(relocator, &target, &pair_target, reloc);
716 require_noerr(rval, finish);
717
718 base_pc = reloc->address;
719 link_pc = base_pc + link_addr;
720
721 /* Relocate */
722
723 rval = relocator->process_reloc(relocator, instruction, reloc->length,
724 reloc->pcrel, base_pc, link_pc, link_addr, reloc->reloc_type, target,
725 pair_target, relocator->swap);
726 require_noerr(rval, finish);
727
728 /* Return */
729
730 relocator->current_vtable = NULL;
731 rval = KERN_SUCCESS;
732
733 finish:
734 return rval;
735 }
736
737 /*******************************************************************************
738 *******************************************************************************/
739 static kern_return_t
740 calculate_targets(KXLDRelocator *relocator, kxld_addr_t *_target,
741 kxld_addr_t *_pair_target, const KXLDReloc *reloc)
742 {
743 kern_return_t rval = KERN_FAILURE;
744 const KXLDSect *sect = NULL;
745 const KXLDSym *sym = NULL;
746 kxld_addr_t target = 0;
747 kxld_addr_t pair_target = 0;
748 char *demangled_name = NULL;
749 size_t demangled_length = 0;
750
751 check(_target);
752 check(_pair_target);
753 *_target = 0;
754 *_pair_target = 0;
755
756 /* Find the target based on the lookup type */
757
758 switch(reloc->target_type) {
759 case KXLD_TARGET_LOOKUP:
760 require_action(reloc->pair_target_type == KXLD_TARGET_NONE ||
761 reloc->pair_target_type == KXLD_TARGET_LOOKUP ||
762 reloc->pair_target_type == KXLD_TARGET_VALUE,
763 finish, rval=KERN_FAILURE);
764
765 rval = get_target_by_address_lookup(&target, reloc->target,
766 relocator->sectarray);
767 require_noerr(rval, finish);
768
769 if (reloc->pair_target_type == KXLD_TARGET_LOOKUP) {
770 rval = get_target_by_address_lookup(&pair_target,
771 reloc->pair_target, relocator->sectarray);
772 require_noerr(rval, finish);
773 } else if (reloc->pair_target_type == KXLD_TARGET_VALUE) {
774 pair_target = reloc->pair_target;
775 }
776 break;
777 case KXLD_TARGET_SECTNUM:
778 require_action(reloc->pair_target_type == KXLD_TARGET_NONE ||
779 reloc->pair_target_type == KXLD_TARGET_VALUE,
780 finish, rval=KERN_FAILURE);
781
782 /* Get the target's section by section number */
783 sect = kxld_array_get_item(relocator->sectarray, reloc->target);
784 require_action(sect, finish, rval=KERN_FAILURE);
785
786 /* target is the change in the section's address */
787 target = sect->link_addr - sect->base_addr;
788
789 if (reloc->pair_target_type) {
790 pair_target = reloc->pair_target;
791 } else {
792 /* x86_64 needs to know when we have a non-external relocation,
793 * so we hack that information in here.
794 */
795 pair_target = TRUE;
796 }
797 break;
798 case KXLD_TARGET_SYMBOLNUM:
799 require_action(reloc->pair_target_type == KXLD_TARGET_NONE ||
800 reloc->pair_target_type == KXLD_TARGET_GOT ||
801 reloc->pair_target_type == KXLD_TARGET_SYMBOLNUM ||
802 reloc->pair_target_type == KXLD_TARGET_VALUE, finish,
803 rval=KERN_FAILURE);
804
805 /* Get the target's symbol by symbol number */
806 sym = kxld_symtab_get_symbol_by_index(relocator->symtab, reloc->target);
807 require_action(sym, finish, rval=KERN_FAILURE);
808
809 /* If this symbol is a padslot that has already been replaced, then the
810 * only way a relocation entry can still reference it is if there is a
811 * vtable that has not been patched. The vtable patcher uses the
812 * MetaClass structure to find classes for patching, so an unpatched
813 * vtable means that there is an OSObject-dervied class that is missing
814 * its OSDeclare/OSDefine macros.
815 */
816 require_action(!kxld_sym_is_padslot(sym) || !kxld_sym_is_replaced(sym),
817 finish, rval=KERN_FAILURE;
818 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogRelocatingPatchedSym,
819 kxld_demangle(sym->name, &demangled_name, &demangled_length)));
820
821 target = sym->link_addr;
822
823 if (kxld_sym_is_vtable(sym)) {
824 relocator->current_vtable = kxld_dict_find(relocator->vtables, sym->name);
825 }
826
827 /* Some relocation types need the GOT entry address instead of the
828 * symbol's actual address. These types don't have pair relocation
829 * entries, so we store the GOT entry address as the pair target.
830 */
831 if (reloc->pair_target_type == KXLD_TARGET_VALUE) {
832 pair_target = reloc->pair_target;
833 } else if (reloc->pair_target_type == KXLD_TARGET_SYMBOLNUM ) {
834 sym = kxld_symtab_get_symbol_by_index(relocator->symtab,
835 reloc->pair_target);
836 require_action(sym, finish, rval=KERN_FAILURE);
837 pair_target = sym->link_addr;
838 } else if (reloc->pair_target_type == KXLD_TARGET_GOT) {
839 pair_target = sym->got_addr;
840 }
841 break;
842 default:
843 rval = KERN_FAILURE;
844 goto finish;
845 }
846
847 *_target = target;
848 *_pair_target = pair_target;
849 rval = KERN_SUCCESS;
850
851 finish:
852 if (demangled_name) kxld_free(demangled_name, demangled_length);
853 return rval;
854 }
855
856 /*******************************************************************************
857 *******************************************************************************/
858 static kern_return_t
859 get_target_by_address_lookup(kxld_addr_t *target, kxld_addr_t addr,
860 const KXLDArray *sectarray)
861 {
862 kern_return_t rval = KERN_FAILURE;
863 const KXLDSect *sect = NULL;
864 kxld_addr_t start = 0;
865 kxld_addr_t end = 0;
866 u_int i = 0;
867
868 check(target);
869 check(sectarray);
870 *target = 0;
871
872 for (i = 0; i < sectarray->nitems; ++i) {
873 sect = kxld_array_get_item(sectarray, i);
874 start = sect->base_addr;
875 end = start + sect->size;
876
877 if (start <= addr && addr < end) break;
878
879 sect = NULL;
880 }
881 require_action(sect, finish, rval=KERN_FAILURE);
882
883 *target = sect->link_addr - sect->base_addr;
884 rval = KERN_SUCCESS;
885
886 finish:
887 return rval;
888 }
889
890 /*******************************************************************************
891 *******************************************************************************/
892 static kern_return_t
893 check_for_direct_pure_virtual_call(const KXLDRelocator *relocator, u_long offset)
894 {
895 kern_return_t rval = KERN_FAILURE;
896 const KXLDVTableEntry *entry = NULL;
897
898 if (relocator->current_vtable) {
899 entry = kxld_vtable_get_entry_for_offset(relocator->current_vtable,
900 offset, relocator->is_32_bit);
901 require_action(!entry || !entry->patched.name ||
902 !kxld_sym_name_is_pure_virtual(entry->patched.name),
903 finish, rval=KERN_FAILURE;
904 kxld_log(kKxldLogLinking, kKxldLogErr,
905 kKxldLogDirectPureVirtualCall));
906 }
907
908 rval = KERN_SUCCESS;
909 finish:
910 return rval;
911 }
912
913 #if KXLD_USER_OR_I386
914 /*******************************************************************************
915 *******************************************************************************/
916 static boolean_t
917 generic_reloc_has_pair(u_int _type)
918 {
919 enum reloc_type_generic type = _type;
920
921 return (type == GENERIC_RELOC_SECTDIFF ||
922 type == GENERIC_RELOC_LOCAL_SECTDIFF);
923 }
924
925 /*******************************************************************************
926 *******************************************************************************/
927 static boolean_t
928 generic_reloc_is_pair(u_int _type, u_int _prev_type __unused)
929 {
930 enum reloc_type_generic type = _type;
931
932 return (type == GENERIC_RELOC_PAIR);
933 }
934
935 /*******************************************************************************
936 *******************************************************************************/
937 static boolean_t generic_reloc_has_got(u_int _type __unused)
938 {
939 return FALSE;
940 }
941
942 /*******************************************************************************
943 *******************************************************************************/
944 static kern_return_t
945 generic_process_reloc(const KXLDRelocator *relocator, u_char *instruction,
946 u_int length, u_int pcrel, kxld_addr_t _base_pc, kxld_addr_t _link_pc,
947 kxld_addr_t _link_disp __unused, u_int _type, kxld_addr_t _target,
948 kxld_addr_t _pair_target, boolean_t swap __unused)
949 {
950 kern_return_t rval = KERN_FAILURE;
951 uint32_t base_pc = (uint32_t) _base_pc;
952 uint32_t link_pc = (uint32_t) _link_pc;
953 uint32_t *instr_addr = NULL;
954 uint32_t instr_data = 0;
955 uint32_t target = (uint32_t) _target;
956 uint32_t pair_target = (uint32_t) _pair_target;
957 enum reloc_type_generic type = _type;
958
959 check(instruction);
960 require_action(length == 2, finish, rval=KERN_FAILURE);
961
962 if (pcrel) target = target + base_pc - link_pc;
963
964 instr_addr = (uint32_t *)instruction;
965 instr_data = *instr_addr;
966
967 #if !KERNEL
968 if (swap) instr_data = OSSwapInt32(instr_data);
969 #endif
970
971 rval = check_for_direct_pure_virtual_call(relocator, instr_data);
972 require_noerr(rval, finish);
973
974 switch (type) {
975 case GENERIC_RELOC_VANILLA:
976 instr_data += target;
977 break;
978 case GENERIC_RELOC_SECTDIFF:
979 case GENERIC_RELOC_LOCAL_SECTDIFF:
980 instr_data = instr_data + target - pair_target;
981 break;
982 case GENERIC_RELOC_PB_LA_PTR:
983 rval = KERN_FAILURE;
984 goto finish;
985 case GENERIC_RELOC_PAIR:
986 default:
987 rval = KERN_FAILURE;
988 goto finish;
989 }
990
991 #if !KERNEL
992 if (swap) instr_data = OSSwapInt32(instr_data);
993 #endif
994
995 *instr_addr = instr_data;
996
997 rval = KERN_SUCCESS;
998
999 finish:
1000 return rval;
1001 }
1002 #endif /* KXLD_USER_OR_I386 */
1003
1004 #if KXLD_USER_OR_PPC
1005 /*******************************************************************************
1006 *******************************************************************************/
1007 static boolean_t
1008 ppc_reloc_has_pair(u_int _type)
1009 {
1010 enum reloc_type_ppc type = _type;
1011
1012 switch(type) {
1013 case PPC_RELOC_HI16:
1014 case PPC_RELOC_LO16:
1015 case PPC_RELOC_HA16:
1016 case PPC_RELOC_LO14:
1017 case PPC_RELOC_JBSR:
1018 case PPC_RELOC_SECTDIFF:
1019 return TRUE;
1020 default:
1021 return FALSE;
1022 }
1023 }
1024
1025 /*******************************************************************************
1026 *******************************************************************************/
1027 static boolean_t
1028 ppc_reloc_is_pair(u_int _type, u_int _prev_type __unused)
1029 {
1030 enum reloc_type_ppc type = _type;
1031
1032 return (type == PPC_RELOC_PAIR);
1033 }
1034
1035 /*******************************************************************************
1036 *******************************************************************************/
1037 static boolean_t ppc_reloc_has_got(u_int _type __unused)
1038 {
1039 return FALSE;
1040 }
1041
1042 /*******************************************************************************
1043 *******************************************************************************/
1044 static kern_return_t
1045 ppc_process_reloc(const KXLDRelocator *relocator __unused, u_char *instruction,
1046 u_int length, u_int pcrel, kxld_addr_t _base_pc, kxld_addr_t _link_pc,
1047 kxld_addr_t _link_disp __unused, u_int _type, kxld_addr_t _target,
1048 kxld_addr_t _pair_target __unused, boolean_t swap __unused)
1049 {
1050 kern_return_t rval = KERN_FAILURE;
1051 uint32_t *instr_addr = NULL;
1052 uint32_t instr_data = 0;
1053 uint32_t base_pc = (uint32_t) _base_pc;
1054 uint32_t link_pc = (uint32_t) _link_pc;
1055 uint32_t target = (uint32_t) _target;
1056 uint32_t pair_target = (uint32_t) _pair_target;
1057 int32_t addend = 0;
1058 int32_t displacement = 0;
1059 uint32_t difference = 0;
1060 uint32_t br14_disp_sign = 0;
1061 enum reloc_type_ppc type = _type;
1062
1063 check(instruction);
1064 require_action(length == 2 || length == 3, finish,
1065 rval=KERN_FAILURE);
1066
1067 if (pcrel) displacement = target + base_pc - link_pc;
1068
1069 instr_addr = (uint32_t *)instruction;
1070 instr_data = *instr_addr;
1071
1072 #if !KERNEL
1073 if (swap) instr_data = OSSwapInt32(instr_data);
1074 #endif
1075
1076 rval = check_for_direct_pure_virtual_call(relocator, instr_data);
1077 require_noerr(rval, finish);
1078
1079 switch (type) {
1080 case PPC_RELOC_VANILLA:
1081 require_action(!pcrel, finish, rval=KERN_FAILURE);
1082
1083 instr_data += target;
1084 break;
1085 case PPC_RELOC_BR14:
1086 require_action(pcrel, finish, rval=KERN_FAILURE);
1087
1088 addend = BR14D(instr_data);
1089 displacement += SIGN_EXTEND(addend, BR14_NBITS_DISPLACEMENT);
1090 difference = ABSOLUTE_VALUE(displacement);
1091 require_action(difference < BR14_LIMIT, finish,
1092 rval=KERN_FAILURE;
1093 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogRelocationOverflow));
1094
1095
1096 br14_disp_sign = BIT15(instr_data);
1097 instr_data = BR14I(instr_data) | BR14D(displacement);
1098
1099 /* If this is a predicted conditional branch (signified by an
1100 * instruction length of 3) that is not branch-always, and the sign of
1101 * the displacement is different after relocation, then flip the y-bit
1102 * to preserve the branch prediction
1103 */
1104 if ((length == 3) &&
1105 IS_COND_BR_INSTR(instr_data) &&
1106 IS_NOT_ALWAYS_TAKEN(instr_data) &&
1107 (BIT15(instr_data) != br14_disp_sign))
1108 {
1109 FLIP_PREDICT_BIT(instr_data);
1110 }
1111 break;
1112 case PPC_RELOC_BR24:
1113 require_action(pcrel, finish, rval=KERN_FAILURE);
1114
1115 addend = BR24D(instr_data);
1116 displacement += SIGN_EXTEND(addend, BR24_NBITS_DISPLACEMENT);
1117 difference = ABSOLUTE_VALUE(displacement);
1118 require_action(difference < BR24_LIMIT, finish,
1119 rval=KERN_FAILURE;
1120 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogRelocationOverflow));
1121
1122 instr_data = BR24I(instr_data) | BR24D(displacement);
1123 break;
1124 case PPC_RELOC_HI16:
1125 require_action(!pcrel, finish, rval=KERN_FAILURE);
1126
1127 target += LO16S(instr_data) | LO16(pair_target);
1128 instr_data = HI16(instr_data) | HI16S(target);
1129 break;
1130 case PPC_RELOC_LO16:
1131 require_action(!pcrel, finish, rval=KERN_FAILURE);
1132
1133 target += LO16S(pair_target) | LO16(instr_data);
1134 instr_data = HI16(instr_data) | LO16(target);
1135 break;
1136 case PPC_RELOC_HA16:
1137 require_action(!pcrel, finish, rval=KERN_FAILURE);
1138
1139 instr_data -= BIT15(pair_target) ? 1 : 0;
1140 target += LO16S(instr_data) | LO16(pair_target);
1141 instr_data = HI16(instr_data) | HI16S(target);
1142 instr_data += BIT15(target) ? 1 : 0;
1143 break;
1144 case PPC_RELOC_JBSR:
1145 require_action(!pcrel, finish, rval=KERN_FAILURE);
1146
1147 /* The generated code as written branches to an island that loads the
1148 * absolute address of the target. If we can branch to the target
1149 * directly with less than 24 bits of displacement, we modify the branch
1150 * instruction to do so which avoids the cost of the island.
1151 */
1152
1153 displacement = target + pair_target - link_pc;
1154 difference = ABSOLUTE_VALUE(displacement);
1155 if (difference < BR24_LIMIT) {
1156 instr_data = BR24I(instr_data) | BR24D(displacement);
1157 }
1158 break;
1159 case PPC_RELOC_SECTDIFF:
1160 require_action(!pcrel, finish, rval=KERN_FAILURE);
1161
1162 instr_data = instr_data + target - pair_target;
1163 break;
1164 case PPC_RELOC_LO14:
1165 case PPC_RELOC_PB_LA_PTR:
1166 case PPC_RELOC_HI16_SECTDIFF:
1167 case PPC_RELOC_LO16_SECTDIFF:
1168 case PPC_RELOC_HA16_SECTDIFF:
1169 case PPC_RELOC_LO14_SECTDIFF:
1170 case PPC_RELOC_LOCAL_SECTDIFF:
1171 rval = KERN_FAILURE;
1172 goto finish;
1173 case PPC_RELOC_PAIR:
1174 default:
1175 rval = KERN_FAILURE;
1176 goto finish;
1177 }
1178
1179 #if !KERNEL
1180 if (swap) instr_data = OSSwapInt32(instr_data);
1181 #endif
1182
1183 *instr_addr = instr_data;
1184
1185 rval = KERN_SUCCESS;
1186 finish:
1187
1188 return rval;
1189 }
1190 #endif /* KXLD_USER_OR_PPC */
1191
1192 #if KXLD_USER_OR_X86_64
1193 /*******************************************************************************
1194 *******************************************************************************/
1195 static boolean_t
1196 x86_64_reloc_has_pair(u_int _type)
1197 {
1198 enum reloc_type_x86_64 type = _type;
1199
1200 return (type == X86_64_RELOC_SUBTRACTOR);
1201 }
1202
1203 /*******************************************************************************
1204 *******************************************************************************/
1205 static boolean_t
1206 x86_64_reloc_is_pair(u_int _type, u_int _prev_type)
1207 {
1208 enum reloc_type_x86_64 type = _type;
1209 enum reloc_type_x86_64 prev_type = _prev_type;
1210
1211 return (x86_64_reloc_has_pair(prev_type) && type == X86_64_RELOC_UNSIGNED);
1212 }
1213
1214 /*******************************************************************************
1215 *******************************************************************************/
1216 static boolean_t
1217 x86_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 *******************************************************************************/
1226 static kern_return_t
1227 x86_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 *) 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 *) 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
1393 finish:
1394 return rval;
1395 }
1396
1397 /*******************************************************************************
1398 *******************************************************************************/
1399 static kern_return_t
1400 calculate_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
1416 finish:
1417 return rval;
1418 }
1419 #endif /* KXLD_USER_OR_X86_64 */
1420
1421 #if KXLD_USER_OR_ARM
1422 /*******************************************************************************
1423 *******************************************************************************/
1424 static boolean_t
1425 arm_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 *******************************************************************************/
1440 static boolean_t
1441 arm_reloc_is_pair(u_int _type, u_int _prev_type __unused)
1442 {
1443 enum reloc_type_arm type = _type;
1444
1445 return (type == ARM_RELOC_PAIR);
1446 }
1447
1448 /*******************************************************************************
1449 *******************************************************************************/
1450 static boolean_t
1451 arm_reloc_has_got(u_int _type __unused)
1452 {
1453 return FALSE;
1454 }
1455
1456 /*******************************************************************************
1457 *******************************************************************************/
1458 static kern_return_t
1459 arm_process_reloc(const KXLDRelocator *relocator __unused, u_char *instruction,
1460 u_int length, u_int pcrel, kxld_addr_t _base_pc __unused,
1461 kxld_addr_t _link_pc __unused, kxld_addr_t _link_disp __unused,
1462 u_int _type __unused, kxld_addr_t _target __unused,
1463 kxld_addr_t _pair_target __unused, boolean_t swap __unused)
1464 {
1465 kern_return_t rval = KERN_FAILURE;
1466 uint32_t *instr_addr = NULL;
1467 uint32_t instr_data = 0;
1468 uint32_t base_pc = (uint32_t) _base_pc;
1469 uint32_t link_pc = (uint32_t) _link_pc;
1470 uint32_t target = (uint32_t) _target;
1471 int32_t displacement = 0;
1472 enum reloc_type_arm type = _type;
1473
1474 check(instruction);
1475 require_action(length == 2, finish, rval=KERN_FAILURE);
1476
1477 if (pcrel) displacement = target + base_pc - link_pc;
1478
1479 instr_addr = (uint32_t *)instruction;
1480 instr_data = *instr_addr;
1481
1482 #if !KERNEL
1483 if (swap) instr_data = OSSwapInt32(instr_data);
1484 #endif
1485
1486 rval = check_for_direct_pure_virtual_call(relocator, instr_data);
1487 require_noerr(rval, finish);
1488
1489 switch (type) {
1490 case ARM_RELOC_VANILLA:
1491 instr_data += target;
1492 break;
1493
1494 /*
1495 * If the displacement is 0 (the offset between the pc and the target has
1496 * not changed), then we don't need to do anything for BR24 and BR22
1497 * relocs. As it turns out, because kexts build with -mlong-calls all
1498 * relocations currently end up being either vanilla (handled above) or
1499 * BR22/BR24 with a displacement of 0.
1500 * We could handle other displacements here but to keep things simple, we
1501 * won't until it is needed (at which point the kernelcache will fail to
1502 * link)
1503 */
1504 case ARM_RELOC_BR24:
1505 require_action(pcrel, finish, rval=KERN_FAILURE);
1506 require_action(displacement == 0, finish, rval=KERN_FAILURE);
1507 break;
1508 case ARM_THUMB_RELOC_BR22:
1509 require_action(pcrel, finish, rval=KERN_FAILURE);
1510 require_action(displacement == 0, finish, rval=KERN_FAILURE);
1511 break;
1512
1513 case ARM_RELOC_SECTDIFF:
1514 case ARM_RELOC_LOCAL_SECTDIFF:
1515 case ARM_RELOC_PB_LA_PTR:
1516 rval = KERN_FAILURE;
1517 goto finish;
1518
1519 case ARM_RELOC_PAIR:
1520 default:
1521 rval = KERN_FAILURE;
1522 goto finish;
1523 }
1524
1525 #if !KERNEL
1526 if (swap) instr_data = OSSwapInt32(instr_data);
1527 #endif
1528
1529 *instr_addr = instr_data;
1530
1531 rval = KERN_SUCCESS;
1532
1533 finish:
1534 return rval;
1535 }
1536
1537 #endif /* KXLD_USER_OR_ARM */
1538