1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2023 - Google LLC 4 * Author: Ard Biesheuvel <ardb@google.com> 5 */ 6 7 #include <elf.h> 8 #include <fcntl.h> 9 #include <stdbool.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <sys/mman.h> 14 #include <sys/stat.h> 15 #include <sys/types.h> 16 #include <unistd.h> 17 18 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 19 #define HOST_ORDER ELFDATA2LSB 20 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 21 #define HOST_ORDER ELFDATA2MSB 22 #endif 23 24 static Elf64_Ehdr *ehdr; 25 static Elf64_Shdr *shdr; 26 static const char *strtab; 27 static bool swap; 28 29 static uint64_t swab_elfxword(uint64_t val) 30 { 31 return swap ? __builtin_bswap64(val) : val; 32 } 33 34 static uint32_t swab_elfword(uint32_t val) 35 { 36 return swap ? __builtin_bswap32(val) : val; 37 } 38 39 static uint16_t swab_elfhword(uint16_t val) 40 { 41 return swap ? __builtin_bswap16(val) : val; 42 } 43 44 int main(int argc, char *argv[]) 45 { 46 struct stat stat; 47 int fd, ret; 48 49 if (argc < 3) { 50 fprintf(stderr, "file arguments missing\n"); 51 exit(EXIT_FAILURE); 52 } 53 54 fd = open(argv[1], O_RDWR); 55 if (fd < 0) { 56 fprintf(stderr, "failed to open %s\n", argv[1]); 57 exit(EXIT_FAILURE); 58 } 59 60 ret = fstat(fd, &stat); 61 if (ret < 0) { 62 fprintf(stderr, "failed to stat() %s\n", argv[1]); 63 exit(EXIT_FAILURE); 64 } 65 66 ehdr = mmap(0, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 67 if (ehdr == MAP_FAILED) { 68 fprintf(stderr, "failed to mmap() %s\n", argv[1]); 69 exit(EXIT_FAILURE); 70 } 71 72 swap = ehdr->e_ident[EI_DATA] != HOST_ORDER; 73 shdr = (void *)ehdr + swab_elfxword(ehdr->e_shoff); 74 strtab = (void *)ehdr + 75 swab_elfxword(shdr[swab_elfhword(ehdr->e_shstrndx)].sh_offset); 76 77 for (int i = 0; i < swab_elfhword(ehdr->e_shnum); i++) { 78 unsigned long info, flags; 79 bool prel64 = false; 80 Elf64_Rela *rela; 81 int numrela; 82 83 if (swab_elfword(shdr[i].sh_type) != SHT_RELA) 84 continue; 85 86 /* only consider RELA sections operating on data */ 87 info = swab_elfword(shdr[i].sh_info); 88 flags = swab_elfxword(shdr[info].sh_flags); 89 if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) != SHF_ALLOC) 90 continue; 91 92 /* 93 * We generally don't permit ABS64 relocations in the code that 94 * runs before relocation processing occurs. If statically 95 * initialized absolute symbol references are unavoidable, they 96 * may be emitted into a *.rodata.prel64 section and they will 97 * be converted to place-relative 64-bit references. This 98 * requires special handling in the referring code. 99 */ 100 if (strstr(strtab + swab_elfword(shdr[info].sh_name), 101 ".rodata.prel64")) { 102 prel64 = true; 103 } 104 105 rela = (void *)ehdr + swab_elfxword(shdr[i].sh_offset); 106 numrela = swab_elfxword(shdr[i].sh_size) / sizeof(*rela); 107 108 for (int j = 0; j < numrela; j++) { 109 uint64_t info = swab_elfxword(rela[j].r_info); 110 111 if (ELF64_R_TYPE(info) != R_AARCH64_ABS64) 112 continue; 113 114 if (prel64) { 115 /* convert ABS64 into PREL64 */ 116 info ^= R_AARCH64_ABS64 ^ R_AARCH64_PREL64; 117 rela[j].r_info = swab_elfxword(info); 118 } else { 119 fprintf(stderr, 120 "Unexpected absolute relocations detected in %s\n", 121 argv[2]); 122 close(fd); 123 unlink(argv[1]); 124 exit(EXIT_FAILURE); 125 } 126 } 127 } 128 close(fd); 129 return 0; 130 } 131