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