1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <elf.h>
28#include <endian.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/mman.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <unistd.h>
39
40#include <generated/autoconf.h>
41
42#define HYP_SECTION_PREFIX ".hyp"
43#define HYP_RELOC_SECTION ".hyp.reloc"
44#define HYP_SECTION_SYMBOL_PREFIX "__hyp_section_"
45
46
47
48
49
50#ifndef R_AARCH64_ABS64
51#define R_AARCH64_ABS64 257
52#endif
53#ifndef R_AARCH64_PREL64
54#define R_AARCH64_PREL64 260
55#endif
56#ifndef R_AARCH64_PREL32
57#define R_AARCH64_PREL32 261
58#endif
59#ifndef R_AARCH64_PREL16
60#define R_AARCH64_PREL16 262
61#endif
62#ifndef R_AARCH64_PLT32
63#define R_AARCH64_PLT32 314
64#endif
65#ifndef R_AARCH64_LD_PREL_LO19
66#define R_AARCH64_LD_PREL_LO19 273
67#endif
68#ifndef R_AARCH64_ADR_PREL_LO21
69#define R_AARCH64_ADR_PREL_LO21 274
70#endif
71#ifndef R_AARCH64_ADR_PREL_PG_HI21
72#define R_AARCH64_ADR_PREL_PG_HI21 275
73#endif
74#ifndef R_AARCH64_ADR_PREL_PG_HI21_NC
75#define R_AARCH64_ADR_PREL_PG_HI21_NC 276
76#endif
77#ifndef R_AARCH64_ADD_ABS_LO12_NC
78#define R_AARCH64_ADD_ABS_LO12_NC 277
79#endif
80#ifndef R_AARCH64_LDST8_ABS_LO12_NC
81#define R_AARCH64_LDST8_ABS_LO12_NC 278
82#endif
83#ifndef R_AARCH64_TSTBR14
84#define R_AARCH64_TSTBR14 279
85#endif
86#ifndef R_AARCH64_CONDBR19
87#define R_AARCH64_CONDBR19 280
88#endif
89#ifndef R_AARCH64_JUMP26
90#define R_AARCH64_JUMP26 282
91#endif
92#ifndef R_AARCH64_CALL26
93#define R_AARCH64_CALL26 283
94#endif
95#ifndef R_AARCH64_LDST16_ABS_LO12_NC
96#define R_AARCH64_LDST16_ABS_LO12_NC 284
97#endif
98#ifndef R_AARCH64_LDST32_ABS_LO12_NC
99#define R_AARCH64_LDST32_ABS_LO12_NC 285
100#endif
101#ifndef R_AARCH64_LDST64_ABS_LO12_NC
102#define R_AARCH64_LDST64_ABS_LO12_NC 286
103#endif
104#ifndef R_AARCH64_MOVW_PREL_G0
105#define R_AARCH64_MOVW_PREL_G0 287
106#endif
107#ifndef R_AARCH64_MOVW_PREL_G0_NC
108#define R_AARCH64_MOVW_PREL_G0_NC 288
109#endif
110#ifndef R_AARCH64_MOVW_PREL_G1
111#define R_AARCH64_MOVW_PREL_G1 289
112#endif
113#ifndef R_AARCH64_MOVW_PREL_G1_NC
114#define R_AARCH64_MOVW_PREL_G1_NC 290
115#endif
116#ifndef R_AARCH64_MOVW_PREL_G2
117#define R_AARCH64_MOVW_PREL_G2 291
118#endif
119#ifndef R_AARCH64_MOVW_PREL_G2_NC
120#define R_AARCH64_MOVW_PREL_G2_NC 292
121#endif
122#ifndef R_AARCH64_MOVW_PREL_G3
123#define R_AARCH64_MOVW_PREL_G3 293
124#endif
125#ifndef R_AARCH64_LDST128_ABS_LO12_NC
126#define R_AARCH64_LDST128_ABS_LO12_NC 299
127#endif
128
129
130static struct {
131 const char *path;
132 char *begin;
133 size_t size;
134 Elf64_Ehdr *ehdr;
135 Elf64_Shdr *sh_table;
136 const char *sh_string;
137} elf;
138
139#if defined(CONFIG_CPU_LITTLE_ENDIAN)
140
141#define elf16toh(x) le16toh(x)
142#define elf32toh(x) le32toh(x)
143#define elf64toh(x) le64toh(x)
144
145#define ELFENDIAN ELFDATA2LSB
146
147#elif defined(CONFIG_CPU_BIG_ENDIAN)
148
149#define elf16toh(x) be16toh(x)
150#define elf32toh(x) be32toh(x)
151#define elf64toh(x) be64toh(x)
152
153#define ELFENDIAN ELFDATA2MSB
154
155#else
156
157#error PDP-endian sadly unsupported...
158
159#endif
160
161#define fatal_error(fmt, ...) \
162 ({ \
163 fprintf(stderr, "error: %s: " fmt "\n", \
164 elf.path, ## __VA_ARGS__); \
165 exit(EXIT_FAILURE); \
166 __builtin_unreachable(); \
167 })
168
169#define fatal_perror(msg) \
170 ({ \
171 fprintf(stderr, "error: %s: " msg ": %s\n", \
172 elf.path, strerror(errno)); \
173 exit(EXIT_FAILURE); \
174 __builtin_unreachable(); \
175 })
176
177#define assert_op(lhs, rhs, fmt, op) \
178 ({ \
179 typeof(lhs) _lhs = (lhs); \
180 typeof(rhs) _rhs = (rhs); \
181 \
182 if (!(_lhs op _rhs)) { \
183 fatal_error("assertion " #lhs " " #op " " #rhs \
184 " failed (lhs=" fmt ", rhs=" fmt \
185 ", line=%d)", _lhs, _rhs, __LINE__); \
186 } \
187 })
188
189#define assert_eq(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, ==)
190#define assert_ne(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, !=)
191#define assert_lt(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, <)
192#define assert_ge(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, >=)
193
194
195
196
197
198#define elf_ptr(type, off) ((type *)(elf.begin + (off)))
199
200
201#define for_each_section(var) \
202 for (var = elf.sh_table; var < elf.sh_table + elf16toh(elf.ehdr->e_shnum); ++var)
203
204
205#define for_each_rela(shdr, var) \
206 for (var = elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset)); \
207 var < elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset) + elf64toh(shdr->sh_size)); var++)
208
209
210static inline bool starts_with(const char *str, const char *prefix)
211{
212 return memcmp(str, prefix, strlen(prefix)) == 0;
213}
214
215
216static inline const char *section_name(Elf64_Shdr *shdr)
217{
218 return elf.sh_string + elf32toh(shdr->sh_name);
219}
220
221
222static inline const char *section_begin(Elf64_Shdr *shdr)
223{
224 return elf_ptr(char, elf64toh(shdr->sh_offset));
225}
226
227
228static inline Elf64_Shdr *section_by_off(Elf64_Off off)
229{
230 assert_ne(off, 0UL, "%lu");
231 return elf_ptr(Elf64_Shdr, off);
232}
233
234
235static inline Elf64_Shdr *section_by_idx(uint16_t idx)
236{
237 assert_ne(idx, SHN_UNDEF, "%u");
238 return &elf.sh_table[idx];
239}
240
241
242
243
244
245static void init_elf(const char *path)
246{
247 int fd, ret;
248 struct stat stat;
249
250
251 elf.path = path;
252
253
254 fd = open(path, O_RDONLY);
255 if (fd < 0)
256 fatal_perror("Could not open ELF file");
257
258
259 ret = fstat(fd, &stat);
260 if (ret < 0) {
261 close(fd);
262 fatal_perror("Could not get status of ELF file");
263 }
264
265
266 elf.begin = mmap(0, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
267 if (elf.begin == MAP_FAILED) {
268 close(fd);
269 fatal_perror("Could not mmap ELF file");
270 }
271
272
273 close(fd);
274
275
276 assert_ge(stat.st_size, sizeof(*elf.ehdr), "%lu");
277 elf.ehdr = elf_ptr(Elf64_Ehdr, 0);
278
279
280 assert_eq(elf.ehdr->e_ident[EI_MAG0], ELFMAG0, "0x%x");
281 assert_eq(elf.ehdr->e_ident[EI_MAG1], ELFMAG1, "0x%x");
282 assert_eq(elf.ehdr->e_ident[EI_MAG2], ELFMAG2, "0x%x");
283 assert_eq(elf.ehdr->e_ident[EI_MAG3], ELFMAG3, "0x%x");
284
285
286 assert_eq(elf.ehdr->e_ident[EI_CLASS], ELFCLASS64, "%u");
287 assert_eq(elf.ehdr->e_ident[EI_DATA], ELFENDIAN, "%u");
288 assert_eq(elf16toh(elf.ehdr->e_type), ET_REL, "%u");
289 assert_eq(elf16toh(elf.ehdr->e_machine), EM_AARCH64, "%u");
290
291
292 elf.sh_table = section_by_off(elf64toh(elf.ehdr->e_shoff));
293 elf.sh_string = section_begin(section_by_idx(elf16toh(elf.ehdr->e_shstrndx)));
294}
295
296
297static void emit_prologue(void)
298{
299 printf(".data\n"
300 ".pushsection " HYP_RELOC_SECTION ", \"a\"\n");
301}
302
303
304static void emit_section_prologue(const char *sh_orig_name)
305{
306
307 printf(".global %s%s\n", HYP_SECTION_SYMBOL_PREFIX, sh_orig_name);
308}
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326static void emit_rela_abs64(Elf64_Rela *rela, const char *sh_orig_name)
327{
328
329 static size_t reloc_offset;
330
331
332 printf(".word 0\n");
333
334
335
336
337
338
339
340 printf(".reloc %lu, R_AARCH64_PREL32, %s%s + 0x%lx\n",
341 reloc_offset, HYP_SECTION_SYMBOL_PREFIX, sh_orig_name,
342 elf64toh(rela->r_offset));
343
344 reloc_offset += 4;
345}
346
347
348static void emit_epilogue(void)
349{
350 printf(".popsection\n");
351}
352
353
354
355
356
357
358
359
360static void emit_rela_section(Elf64_Shdr *sh_rela)
361{
362 Elf64_Shdr *sh_orig = &elf.sh_table[elf32toh(sh_rela->sh_info)];
363 const char *sh_orig_name = section_name(sh_orig);
364 Elf64_Rela *rela;
365
366
367 if (!starts_with(sh_orig_name, HYP_SECTION_PREFIX))
368 return;
369
370 emit_section_prologue(sh_orig_name);
371
372 for_each_rela(sh_rela, rela) {
373 uint32_t type = (uint32_t)elf64toh(rela->r_info);
374
375
376 assert_lt(elf64toh(rela->r_offset), elf64toh(sh_orig->sh_size), "0x%lx");
377
378 switch (type) {
379
380
381
382
383 case R_AARCH64_ABS64:
384 emit_rela_abs64(rela, sh_orig_name);
385 break;
386
387 case R_AARCH64_PREL64:
388 case R_AARCH64_PREL32:
389 case R_AARCH64_PREL16:
390 case R_AARCH64_PLT32:
391 break;
392
393 case R_AARCH64_LD_PREL_LO19:
394 case R_AARCH64_ADR_PREL_LO21:
395 case R_AARCH64_ADR_PREL_PG_HI21:
396 case R_AARCH64_ADR_PREL_PG_HI21_NC:
397 case R_AARCH64_ADD_ABS_LO12_NC:
398 case R_AARCH64_LDST8_ABS_LO12_NC:
399 case R_AARCH64_LDST16_ABS_LO12_NC:
400 case R_AARCH64_LDST32_ABS_LO12_NC:
401 case R_AARCH64_LDST64_ABS_LO12_NC:
402 case R_AARCH64_LDST128_ABS_LO12_NC:
403 break;
404
405 case R_AARCH64_TSTBR14:
406 case R_AARCH64_CONDBR19:
407 case R_AARCH64_JUMP26:
408 case R_AARCH64_CALL26:
409 break;
410
411 case R_AARCH64_MOVW_PREL_G0:
412 case R_AARCH64_MOVW_PREL_G0_NC:
413 case R_AARCH64_MOVW_PREL_G1:
414 case R_AARCH64_MOVW_PREL_G1_NC:
415 case R_AARCH64_MOVW_PREL_G2:
416 case R_AARCH64_MOVW_PREL_G2_NC:
417 case R_AARCH64_MOVW_PREL_G3:
418 break;
419 default:
420 fatal_error("Unexpected RELA type %u", type);
421 }
422 }
423}
424
425
426static void emit_all_relocs(void)
427{
428 Elf64_Shdr *shdr;
429
430 for_each_section(shdr) {
431 switch (elf32toh(shdr->sh_type)) {
432 case SHT_REL:
433 fatal_error("Unexpected SHT_REL section \"%s\"",
434 section_name(shdr));
435 case SHT_RELA:
436 emit_rela_section(shdr);
437 break;
438 }
439 }
440}
441
442int main(int argc, const char **argv)
443{
444 if (argc != 2) {
445 fprintf(stderr, "Usage: %s <elf_input>\n", argv[0]);
446 return EXIT_FAILURE;
447 }
448
449 init_elf(argv[1]);
450
451 emit_prologue();
452 emit_all_relocs();
453 emit_epilogue();
454
455 return EXIT_SUCCESS;
456}
457