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