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