xref: /OK3568_Linux_fs/kernel/arch/arm64/kvm/hyp/nvhe/gen-hyprel.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2020 - Google LLC
4*4882a593Smuzhiyun  * Author: David Brazdil <dbrazdil@google.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Generates relocation information used by the kernel to convert
7*4882a593Smuzhiyun  * absolute addresses in hyp data from kernel VAs to hyp VAs.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This is necessary because hyp code is linked into the same binary
10*4882a593Smuzhiyun  * as the kernel but executes under different memory mappings.
11*4882a593Smuzhiyun  * If the compiler used absolute addressing, those addresses need to
12*4882a593Smuzhiyun  * be converted before they are used by hyp code.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * The input of this program is the relocatable ELF object containing
15*4882a593Smuzhiyun  * all hyp code/data, not yet linked into vmlinux. Hyp section names
16*4882a593Smuzhiyun  * should have been prefixed with `.hyp` at this point.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * The output (printed to stdout) is an assembly file containing
19*4882a593Smuzhiyun  * an array of 32-bit integers and static relocations that instruct
20*4882a593Smuzhiyun  * the linker of `vmlinux` to populate the array entries with offsets
21*4882a593Smuzhiyun  * to positions in the kernel binary containing VAs used by hyp code.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * Note that dynamic relocations could be used for the same purpose.
24*4882a593Smuzhiyun  * However, those are only generated if CONFIG_RELOCATABLE=y.
25*4882a593Smuzhiyun  */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <elf.h>
28*4882a593Smuzhiyun #include <endian.h>
29*4882a593Smuzhiyun #include <errno.h>
30*4882a593Smuzhiyun #include <fcntl.h>
31*4882a593Smuzhiyun #include <stdbool.h>
32*4882a593Smuzhiyun #include <stdio.h>
33*4882a593Smuzhiyun #include <stdlib.h>
34*4882a593Smuzhiyun #include <string.h>
35*4882a593Smuzhiyun #include <sys/mman.h>
36*4882a593Smuzhiyun #include <sys/types.h>
37*4882a593Smuzhiyun #include <sys/stat.h>
38*4882a593Smuzhiyun #include <unistd.h>
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #include <generated/autoconf.h>
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define HYP_SECTION_PREFIX		".hyp"
43*4882a593Smuzhiyun #define HYP_RELOC_SECTION		".hyp.reloc"
44*4882a593Smuzhiyun #define HYP_SECTION_SYMBOL_PREFIX	"__hyp_section_"
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /*
47*4882a593Smuzhiyun  * AArch64 relocation type constants.
48*4882a593Smuzhiyun  * Included in case these are not defined in the host toolchain.
49*4882a593Smuzhiyun  */
50*4882a593Smuzhiyun #ifndef R_AARCH64_ABS64
51*4882a593Smuzhiyun #define R_AARCH64_ABS64			257
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun #ifndef R_AARCH64_PREL64
54*4882a593Smuzhiyun #define R_AARCH64_PREL64		260
55*4882a593Smuzhiyun #endif
56*4882a593Smuzhiyun #ifndef R_AARCH64_PREL32
57*4882a593Smuzhiyun #define R_AARCH64_PREL32		261
58*4882a593Smuzhiyun #endif
59*4882a593Smuzhiyun #ifndef R_AARCH64_PREL16
60*4882a593Smuzhiyun #define R_AARCH64_PREL16		262
61*4882a593Smuzhiyun #endif
62*4882a593Smuzhiyun #ifndef R_AARCH64_PLT32
63*4882a593Smuzhiyun #define R_AARCH64_PLT32			314
64*4882a593Smuzhiyun #endif
65*4882a593Smuzhiyun #ifndef R_AARCH64_LD_PREL_LO19
66*4882a593Smuzhiyun #define R_AARCH64_LD_PREL_LO19		273
67*4882a593Smuzhiyun #endif
68*4882a593Smuzhiyun #ifndef R_AARCH64_ADR_PREL_LO21
69*4882a593Smuzhiyun #define R_AARCH64_ADR_PREL_LO21		274
70*4882a593Smuzhiyun #endif
71*4882a593Smuzhiyun #ifndef R_AARCH64_ADR_PREL_PG_HI21
72*4882a593Smuzhiyun #define R_AARCH64_ADR_PREL_PG_HI21	275
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun #ifndef R_AARCH64_ADR_PREL_PG_HI21_NC
75*4882a593Smuzhiyun #define R_AARCH64_ADR_PREL_PG_HI21_NC	276
76*4882a593Smuzhiyun #endif
77*4882a593Smuzhiyun #ifndef R_AARCH64_ADD_ABS_LO12_NC
78*4882a593Smuzhiyun #define R_AARCH64_ADD_ABS_LO12_NC	277
79*4882a593Smuzhiyun #endif
80*4882a593Smuzhiyun #ifndef R_AARCH64_LDST8_ABS_LO12_NC
81*4882a593Smuzhiyun #define R_AARCH64_LDST8_ABS_LO12_NC	278
82*4882a593Smuzhiyun #endif
83*4882a593Smuzhiyun #ifndef R_AARCH64_TSTBR14
84*4882a593Smuzhiyun #define R_AARCH64_TSTBR14		279
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun #ifndef R_AARCH64_CONDBR19
87*4882a593Smuzhiyun #define R_AARCH64_CONDBR19		280
88*4882a593Smuzhiyun #endif
89*4882a593Smuzhiyun #ifndef R_AARCH64_JUMP26
90*4882a593Smuzhiyun #define R_AARCH64_JUMP26		282
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun #ifndef R_AARCH64_CALL26
93*4882a593Smuzhiyun #define R_AARCH64_CALL26		283
94*4882a593Smuzhiyun #endif
95*4882a593Smuzhiyun #ifndef R_AARCH64_LDST16_ABS_LO12_NC
96*4882a593Smuzhiyun #define R_AARCH64_LDST16_ABS_LO12_NC	284
97*4882a593Smuzhiyun #endif
98*4882a593Smuzhiyun #ifndef R_AARCH64_LDST32_ABS_LO12_NC
99*4882a593Smuzhiyun #define R_AARCH64_LDST32_ABS_LO12_NC	285
100*4882a593Smuzhiyun #endif
101*4882a593Smuzhiyun #ifndef R_AARCH64_LDST64_ABS_LO12_NC
102*4882a593Smuzhiyun #define R_AARCH64_LDST64_ABS_LO12_NC	286
103*4882a593Smuzhiyun #endif
104*4882a593Smuzhiyun #ifndef R_AARCH64_MOVW_PREL_G0
105*4882a593Smuzhiyun #define R_AARCH64_MOVW_PREL_G0		287
106*4882a593Smuzhiyun #endif
107*4882a593Smuzhiyun #ifndef R_AARCH64_MOVW_PREL_G0_NC
108*4882a593Smuzhiyun #define R_AARCH64_MOVW_PREL_G0_NC	288
109*4882a593Smuzhiyun #endif
110*4882a593Smuzhiyun #ifndef R_AARCH64_MOVW_PREL_G1
111*4882a593Smuzhiyun #define R_AARCH64_MOVW_PREL_G1		289
112*4882a593Smuzhiyun #endif
113*4882a593Smuzhiyun #ifndef R_AARCH64_MOVW_PREL_G1_NC
114*4882a593Smuzhiyun #define R_AARCH64_MOVW_PREL_G1_NC	290
115*4882a593Smuzhiyun #endif
116*4882a593Smuzhiyun #ifndef R_AARCH64_MOVW_PREL_G2
117*4882a593Smuzhiyun #define R_AARCH64_MOVW_PREL_G2		291
118*4882a593Smuzhiyun #endif
119*4882a593Smuzhiyun #ifndef R_AARCH64_MOVW_PREL_G2_NC
120*4882a593Smuzhiyun #define R_AARCH64_MOVW_PREL_G2_NC	292
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun #ifndef R_AARCH64_MOVW_PREL_G3
123*4882a593Smuzhiyun #define R_AARCH64_MOVW_PREL_G3		293
124*4882a593Smuzhiyun #endif
125*4882a593Smuzhiyun #ifndef R_AARCH64_LDST128_ABS_LO12_NC
126*4882a593Smuzhiyun #define R_AARCH64_LDST128_ABS_LO12_NC	299
127*4882a593Smuzhiyun #endif
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun /* Global state of the processed ELF. */
130*4882a593Smuzhiyun static struct {
131*4882a593Smuzhiyun 	const char	*path;
132*4882a593Smuzhiyun 	char		*begin;
133*4882a593Smuzhiyun 	size_t		size;
134*4882a593Smuzhiyun 	Elf64_Ehdr	*ehdr;
135*4882a593Smuzhiyun 	Elf64_Shdr	*sh_table;
136*4882a593Smuzhiyun 	const char	*sh_string;
137*4882a593Smuzhiyun } elf;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun #if defined(CONFIG_CPU_LITTLE_ENDIAN)
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun #define elf16toh(x)	le16toh(x)
142*4882a593Smuzhiyun #define elf32toh(x)	le32toh(x)
143*4882a593Smuzhiyun #define elf64toh(x)	le64toh(x)
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun #define ELFENDIAN	ELFDATA2LSB
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun #elif defined(CONFIG_CPU_BIG_ENDIAN)
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun #define elf16toh(x)	be16toh(x)
150*4882a593Smuzhiyun #define elf32toh(x)	be32toh(x)
151*4882a593Smuzhiyun #define elf64toh(x)	be64toh(x)
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun #define ELFENDIAN	ELFDATA2MSB
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun #else
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun #error PDP-endian sadly unsupported...
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun #endif
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun #define fatal_error(fmt, ...)						\
162*4882a593Smuzhiyun 	({								\
163*4882a593Smuzhiyun 		fprintf(stderr, "error: %s: " fmt "\n",			\
164*4882a593Smuzhiyun 			elf.path, ## __VA_ARGS__);			\
165*4882a593Smuzhiyun 		exit(EXIT_FAILURE);					\
166*4882a593Smuzhiyun 		__builtin_unreachable();				\
167*4882a593Smuzhiyun 	})
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun #define fatal_perror(msg)						\
170*4882a593Smuzhiyun 	({								\
171*4882a593Smuzhiyun 		fprintf(stderr, "error: %s: " msg ": %s\n",		\
172*4882a593Smuzhiyun 			elf.path, strerror(errno));			\
173*4882a593Smuzhiyun 		exit(EXIT_FAILURE);					\
174*4882a593Smuzhiyun 		__builtin_unreachable();				\
175*4882a593Smuzhiyun 	})
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun #define assert_op(lhs, rhs, fmt, op)					\
178*4882a593Smuzhiyun 	({								\
179*4882a593Smuzhiyun 		typeof(lhs) _lhs = (lhs);				\
180*4882a593Smuzhiyun 		typeof(rhs) _rhs = (rhs);				\
181*4882a593Smuzhiyun 									\
182*4882a593Smuzhiyun 		if (!(_lhs op _rhs)) {					\
183*4882a593Smuzhiyun 			fatal_error("assertion " #lhs " " #op " " #rhs	\
184*4882a593Smuzhiyun 				" failed (lhs=" fmt ", rhs=" fmt	\
185*4882a593Smuzhiyun 				", line=%d)", _lhs, _rhs, __LINE__);	\
186*4882a593Smuzhiyun 		}							\
187*4882a593Smuzhiyun 	})
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun #define assert_eq(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, ==)
190*4882a593Smuzhiyun #define assert_ne(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, !=)
191*4882a593Smuzhiyun #define assert_lt(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, <)
192*4882a593Smuzhiyun #define assert_ge(lhs, rhs, fmt)	assert_op(lhs, rhs, fmt, >=)
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /*
195*4882a593Smuzhiyun  * Return a pointer of a given type at a given offset from
196*4882a593Smuzhiyun  * the beginning of the ELF file.
197*4882a593Smuzhiyun  */
198*4882a593Smuzhiyun #define elf_ptr(type, off) ((type *)(elf.begin + (off)))
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun /* Iterate over all sections in the ELF. */
201*4882a593Smuzhiyun #define for_each_section(var) \
202*4882a593Smuzhiyun 	for (var = elf.sh_table; var < elf.sh_table + elf16toh(elf.ehdr->e_shnum); ++var)
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun /* Iterate over all Elf64_Rela relocations in a given section. */
205*4882a593Smuzhiyun #define for_each_rela(shdr, var)					\
206*4882a593Smuzhiyun 	for (var = elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset));	\
207*4882a593Smuzhiyun 	     var < elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset) + elf64toh(shdr->sh_size)); var++)
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun /* True if a string starts with a given prefix. */
starts_with(const char * str,const char * prefix)210*4882a593Smuzhiyun static inline bool starts_with(const char *str, const char *prefix)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	return memcmp(str, prefix, strlen(prefix)) == 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun /* Returns a string containing the name of a given section. */
section_name(Elf64_Shdr * shdr)216*4882a593Smuzhiyun static inline const char *section_name(Elf64_Shdr *shdr)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	return elf.sh_string + elf32toh(shdr->sh_name);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun /* Returns a pointer to the first byte of section data. */
section_begin(Elf64_Shdr * shdr)222*4882a593Smuzhiyun static inline const char *section_begin(Elf64_Shdr *shdr)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	return elf_ptr(char, elf64toh(shdr->sh_offset));
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun /* Find a section by its offset from the beginning of the file. */
section_by_off(Elf64_Off off)228*4882a593Smuzhiyun static inline Elf64_Shdr *section_by_off(Elf64_Off off)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	assert_ne(off, 0UL, "%lu");
231*4882a593Smuzhiyun 	return elf_ptr(Elf64_Shdr, off);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun /* Find a section by its index. */
section_by_idx(uint16_t idx)235*4882a593Smuzhiyun static inline Elf64_Shdr *section_by_idx(uint16_t idx)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	assert_ne(idx, SHN_UNDEF, "%u");
238*4882a593Smuzhiyun 	return &elf.sh_table[idx];
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun /*
242*4882a593Smuzhiyun  * Memory-map the given ELF file, perform sanity checks, and
243*4882a593Smuzhiyun  * populate global state.
244*4882a593Smuzhiyun  */
init_elf(const char * path)245*4882a593Smuzhiyun static void init_elf(const char *path)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	int fd, ret;
248*4882a593Smuzhiyun 	struct stat stat;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	/* Store path in the global struct for error printing. */
251*4882a593Smuzhiyun 	elf.path = path;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* Open the ELF file. */
254*4882a593Smuzhiyun 	fd = open(path, O_RDONLY);
255*4882a593Smuzhiyun 	if (fd < 0)
256*4882a593Smuzhiyun 		fatal_perror("Could not open ELF file");
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	/* Get status of ELF file to obtain its size. */
259*4882a593Smuzhiyun 	ret = fstat(fd, &stat);
260*4882a593Smuzhiyun 	if (ret < 0) {
261*4882a593Smuzhiyun 		close(fd);
262*4882a593Smuzhiyun 		fatal_perror("Could not get status of ELF file");
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/* mmap() the entire ELF file read-only at an arbitrary address. */
266*4882a593Smuzhiyun 	elf.begin = mmap(0, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
267*4882a593Smuzhiyun 	if (elf.begin == MAP_FAILED) {
268*4882a593Smuzhiyun 		close(fd);
269*4882a593Smuzhiyun 		fatal_perror("Could not mmap ELF file");
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	/* mmap() was successful, close the FD. */
273*4882a593Smuzhiyun 	close(fd);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	/* Get pointer to the ELF header. */
276*4882a593Smuzhiyun 	assert_ge(stat.st_size, sizeof(*elf.ehdr), "%lu");
277*4882a593Smuzhiyun 	elf.ehdr = elf_ptr(Elf64_Ehdr, 0);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	/* Check the ELF magic. */
280*4882a593Smuzhiyun 	assert_eq(elf.ehdr->e_ident[EI_MAG0], ELFMAG0, "0x%x");
281*4882a593Smuzhiyun 	assert_eq(elf.ehdr->e_ident[EI_MAG1], ELFMAG1, "0x%x");
282*4882a593Smuzhiyun 	assert_eq(elf.ehdr->e_ident[EI_MAG2], ELFMAG2, "0x%x");
283*4882a593Smuzhiyun 	assert_eq(elf.ehdr->e_ident[EI_MAG3], ELFMAG3, "0x%x");
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* Sanity check that this is an ELF64 relocatable object for AArch64. */
286*4882a593Smuzhiyun 	assert_eq(elf.ehdr->e_ident[EI_CLASS], ELFCLASS64, "%u");
287*4882a593Smuzhiyun 	assert_eq(elf.ehdr->e_ident[EI_DATA], ELFENDIAN, "%u");
288*4882a593Smuzhiyun 	assert_eq(elf16toh(elf.ehdr->e_type), ET_REL, "%u");
289*4882a593Smuzhiyun 	assert_eq(elf16toh(elf.ehdr->e_machine), EM_AARCH64, "%u");
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* Populate fields of the global struct. */
292*4882a593Smuzhiyun 	elf.sh_table = section_by_off(elf64toh(elf.ehdr->e_shoff));
293*4882a593Smuzhiyun 	elf.sh_string = section_begin(section_by_idx(elf16toh(elf.ehdr->e_shstrndx)));
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun /* Print the prologue of the output ASM file. */
emit_prologue(void)297*4882a593Smuzhiyun static void emit_prologue(void)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	printf(".data\n"
300*4882a593Smuzhiyun 	       ".pushsection " HYP_RELOC_SECTION ", \"a\"\n");
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun /* Print ASM statements needed as a prologue to a processed hyp section. */
emit_section_prologue(const char * sh_orig_name)304*4882a593Smuzhiyun static void emit_section_prologue(const char *sh_orig_name)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun 	/* Declare the hyp section symbol. */
307*4882a593Smuzhiyun 	printf(".global %s%s\n", HYP_SECTION_SYMBOL_PREFIX, sh_orig_name);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun /*
311*4882a593Smuzhiyun  * Print ASM statements to create a hyp relocation entry for a given
312*4882a593Smuzhiyun  * R_AARCH64_ABS64 relocation.
313*4882a593Smuzhiyun  *
314*4882a593Smuzhiyun  * The linker of vmlinux will populate the position given by `rela` with
315*4882a593Smuzhiyun  * an absolute 64-bit kernel VA. If the kernel is relocatable, it will
316*4882a593Smuzhiyun  * also generate a dynamic relocation entry so that the kernel can shift
317*4882a593Smuzhiyun  * the address at runtime for KASLR.
318*4882a593Smuzhiyun  *
319*4882a593Smuzhiyun  * Emit a 32-bit offset from the current address to the position given
320*4882a593Smuzhiyun  * by `rela`. This way the kernel can iterate over all kernel VAs used
321*4882a593Smuzhiyun  * by hyp at runtime and convert them to hyp VAs. However, that offset
322*4882a593Smuzhiyun  * will not be known until linking of `vmlinux`, so emit a PREL32
323*4882a593Smuzhiyun  * relocation referencing a symbol that the hyp linker script put at
324*4882a593Smuzhiyun  * the beginning of the relocated section + the offset from `rela`.
325*4882a593Smuzhiyun  */
emit_rela_abs64(Elf64_Rela * rela,const char * sh_orig_name)326*4882a593Smuzhiyun static void emit_rela_abs64(Elf64_Rela *rela, const char *sh_orig_name)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	/* Offset of this reloc from the beginning of HYP_RELOC_SECTION. */
329*4882a593Smuzhiyun 	static size_t reloc_offset;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/* Create storage for the 32-bit offset. */
332*4882a593Smuzhiyun 	printf(".word 0\n");
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	/*
335*4882a593Smuzhiyun 	 * Create a PREL32 relocation which instructs the linker of `vmlinux`
336*4882a593Smuzhiyun 	 * to insert offset to position <base> + <offset>, where <base> is
337*4882a593Smuzhiyun 	 * a symbol at the beginning of the relocated section, and <offset>
338*4882a593Smuzhiyun 	 * is `rela->r_offset`.
339*4882a593Smuzhiyun 	 */
340*4882a593Smuzhiyun 	printf(".reloc %lu, R_AARCH64_PREL32, %s%s + 0x%lx\n",
341*4882a593Smuzhiyun 	       reloc_offset, HYP_SECTION_SYMBOL_PREFIX, sh_orig_name,
342*4882a593Smuzhiyun 	       elf64toh(rela->r_offset));
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	reloc_offset += 4;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun /* Print the epilogue of the output ASM file. */
emit_epilogue(void)348*4882a593Smuzhiyun static void emit_epilogue(void)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	printf(".popsection\n");
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun /*
354*4882a593Smuzhiyun  * Iterate over all RELA relocations in a given section and emit
355*4882a593Smuzhiyun  * hyp relocation data for all absolute addresses in hyp code/data.
356*4882a593Smuzhiyun  *
357*4882a593Smuzhiyun  * Static relocations that generate PC-relative-addressing are ignored.
358*4882a593Smuzhiyun  * Failure is reported for unexpected relocation types.
359*4882a593Smuzhiyun  */
emit_rela_section(Elf64_Shdr * sh_rela)360*4882a593Smuzhiyun static void emit_rela_section(Elf64_Shdr *sh_rela)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	Elf64_Shdr *sh_orig = &elf.sh_table[elf32toh(sh_rela->sh_info)];
363*4882a593Smuzhiyun 	const char *sh_orig_name = section_name(sh_orig);
364*4882a593Smuzhiyun 	Elf64_Rela *rela;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/* Skip all non-hyp sections. */
367*4882a593Smuzhiyun 	if (!starts_with(sh_orig_name, HYP_SECTION_PREFIX))
368*4882a593Smuzhiyun 		return;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	emit_section_prologue(sh_orig_name);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	for_each_rela(sh_rela, rela) {
373*4882a593Smuzhiyun 		uint32_t type = (uint32_t)elf64toh(rela->r_info);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 		/* Check that rela points inside the relocated section. */
376*4882a593Smuzhiyun 		assert_lt(elf64toh(rela->r_offset), elf64toh(sh_orig->sh_size), "0x%lx");
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 		switch (type) {
379*4882a593Smuzhiyun 		/*
380*4882a593Smuzhiyun 		 * Data relocations to generate absolute addressing.
381*4882a593Smuzhiyun 		 * Emit a hyp relocation.
382*4882a593Smuzhiyun 		 */
383*4882a593Smuzhiyun 		case R_AARCH64_ABS64:
384*4882a593Smuzhiyun 			emit_rela_abs64(rela, sh_orig_name);
385*4882a593Smuzhiyun 			break;
386*4882a593Smuzhiyun 		/* Allow position-relative data relocations. */
387*4882a593Smuzhiyun 		case R_AARCH64_PREL64:
388*4882a593Smuzhiyun 		case R_AARCH64_PREL32:
389*4882a593Smuzhiyun 		case R_AARCH64_PREL16:
390*4882a593Smuzhiyun 		case R_AARCH64_PLT32:
391*4882a593Smuzhiyun 			break;
392*4882a593Smuzhiyun 		/* Allow relocations to generate PC-relative addressing. */
393*4882a593Smuzhiyun 		case R_AARCH64_LD_PREL_LO19:
394*4882a593Smuzhiyun 		case R_AARCH64_ADR_PREL_LO21:
395*4882a593Smuzhiyun 		case R_AARCH64_ADR_PREL_PG_HI21:
396*4882a593Smuzhiyun 		case R_AARCH64_ADR_PREL_PG_HI21_NC:
397*4882a593Smuzhiyun 		case R_AARCH64_ADD_ABS_LO12_NC:
398*4882a593Smuzhiyun 		case R_AARCH64_LDST8_ABS_LO12_NC:
399*4882a593Smuzhiyun 		case R_AARCH64_LDST16_ABS_LO12_NC:
400*4882a593Smuzhiyun 		case R_AARCH64_LDST32_ABS_LO12_NC:
401*4882a593Smuzhiyun 		case R_AARCH64_LDST64_ABS_LO12_NC:
402*4882a593Smuzhiyun 		case R_AARCH64_LDST128_ABS_LO12_NC:
403*4882a593Smuzhiyun 			break;
404*4882a593Smuzhiyun 		/* Allow relative relocations for control-flow instructions. */
405*4882a593Smuzhiyun 		case R_AARCH64_TSTBR14:
406*4882a593Smuzhiyun 		case R_AARCH64_CONDBR19:
407*4882a593Smuzhiyun 		case R_AARCH64_JUMP26:
408*4882a593Smuzhiyun 		case R_AARCH64_CALL26:
409*4882a593Smuzhiyun 			break;
410*4882a593Smuzhiyun 		/* Allow group relocations to create PC-relative offset inline. */
411*4882a593Smuzhiyun 		case R_AARCH64_MOVW_PREL_G0:
412*4882a593Smuzhiyun 		case R_AARCH64_MOVW_PREL_G0_NC:
413*4882a593Smuzhiyun 		case R_AARCH64_MOVW_PREL_G1:
414*4882a593Smuzhiyun 		case R_AARCH64_MOVW_PREL_G1_NC:
415*4882a593Smuzhiyun 		case R_AARCH64_MOVW_PREL_G2:
416*4882a593Smuzhiyun 		case R_AARCH64_MOVW_PREL_G2_NC:
417*4882a593Smuzhiyun 		case R_AARCH64_MOVW_PREL_G3:
418*4882a593Smuzhiyun 			break;
419*4882a593Smuzhiyun 		default:
420*4882a593Smuzhiyun 			fatal_error("Unexpected RELA type %u", type);
421*4882a593Smuzhiyun 		}
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun /* Iterate over all sections and emit hyp relocation data for RELA sections. */
emit_all_relocs(void)426*4882a593Smuzhiyun static void emit_all_relocs(void)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	Elf64_Shdr *shdr;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	for_each_section(shdr) {
431*4882a593Smuzhiyun 		switch (elf32toh(shdr->sh_type)) {
432*4882a593Smuzhiyun 		case SHT_REL:
433*4882a593Smuzhiyun 			fatal_error("Unexpected SHT_REL section \"%s\"",
434*4882a593Smuzhiyun 				section_name(shdr));
435*4882a593Smuzhiyun 		case SHT_RELA:
436*4882a593Smuzhiyun 			emit_rela_section(shdr);
437*4882a593Smuzhiyun 			break;
438*4882a593Smuzhiyun 		}
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
main(int argc,const char ** argv)442*4882a593Smuzhiyun int main(int argc, const char **argv)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	if (argc != 2) {
445*4882a593Smuzhiyun 		fprintf(stderr, "Usage: %s <elf_input>\n", argv[0]);
446*4882a593Smuzhiyun 		return EXIT_FAILURE;
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	init_elf(argv[1]);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	emit_prologue();
452*4882a593Smuzhiyun 	emit_all_relocs();
453*4882a593Smuzhiyun 	emit_epilogue();
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	return EXIT_SUCCESS;
456*4882a593Smuzhiyun }
457