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