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