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