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