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