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