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