1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause 2 /* 3 * Copyright 2013 Freescale Semiconductor, Inc. 4 * 5 * 64-bit and little-endian target only until we need to support a different 6 * arch that needs this. 7 */ 8 9 #include <elf.h> 10 #include <errno.h> 11 #include <inttypes.h> 12 #include <stdarg.h> 13 #include <stdbool.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include "compiler.h" 18 19 #ifndef R_AARCH64_RELATIVE 20 #define R_AARCH64_RELATIVE 1027 21 #endif 22 23 static const bool debug_en; 24 25 static void debug(const char *fmt, ...) 26 { 27 va_list args; 28 29 if (debug_en) { 30 va_start(args, fmt); 31 vprintf(fmt, args); 32 va_end(args); 33 } 34 } 35 36 static bool supported_rela(Elf64_Rela *rela) 37 { 38 uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */ 39 uint32_t type = rela->r_info & mask; 40 41 switch (type) { 42 #ifdef R_AARCH64_RELATIVE 43 case R_AARCH64_RELATIVE: 44 return true; 45 #endif 46 default: 47 fprintf(stderr, "warning: unsupported relocation type %" 48 PRIu32 " at %" PRIx64 "\n", 49 type, rela->r_offset); 50 51 return false; 52 } 53 } 54 55 static bool read_num(const char *str, uint64_t *num) 56 { 57 char *endptr; 58 *num = strtoull(str, &endptr, 16); 59 return str[0] && !endptr[0]; 60 } 61 62 int main(int argc, char **argv) 63 { 64 FILE *f; 65 int i, num; 66 uint64_t rela_start, rela_end, text_base; 67 68 if (argc != 5) { 69 fprintf(stderr, "Statically apply ELF rela relocations\n"); 70 fprintf(stderr, "Usage: %s <bin file> <text base> " \ 71 "<rela start> <rela end>\n", argv[0]); 72 fprintf(stderr, "All numbers in hex.\n"); 73 return 1; 74 } 75 76 f = fopen(argv[1], "r+b"); 77 if (!f) { 78 fprintf(stderr, "%s: Cannot open %s: %s\n", 79 argv[0], argv[1], strerror(errno)); 80 return 2; 81 } 82 83 if (!read_num(argv[2], &text_base) || 84 !read_num(argv[3], &rela_start) || 85 !read_num(argv[4], &rela_end)) { 86 fprintf(stderr, "%s: bad number\n", argv[0]); 87 return 3; 88 } 89 90 if (rela_start > rela_end || rela_start < text_base || 91 (rela_end - rela_start) % sizeof(Elf64_Rela)) { 92 fprintf(stderr, "%s: bad rela bounds\n", argv[0]); 93 return 3; 94 } 95 96 rela_start -= text_base; 97 rela_end -= text_base; 98 99 num = (rela_end - rela_start) / sizeof(Elf64_Rela); 100 101 for (i = 0; i < num; i++) { 102 Elf64_Rela rela, swrela; 103 uint64_t pos = rela_start + sizeof(Elf64_Rela) * i; 104 uint64_t addr; 105 106 if (fseek(f, pos, SEEK_SET) < 0) { 107 fprintf(stderr, "%s: %s: seek to %" PRIx64 108 " failed: %s\n", 109 argv[0], argv[1], pos, strerror(errno)); 110 } 111 112 if (fread(&rela, sizeof(rela), 1, f) != 1) { 113 fprintf(stderr, "%s: %s: read rela failed at %" 114 PRIx64 "\n", 115 argv[0], argv[1], pos); 116 return 4; 117 } 118 119 swrela.r_offset = cpu_to_le64(rela.r_offset); 120 swrela.r_info = cpu_to_le64(rela.r_info); 121 swrela.r_addend = cpu_to_le64(rela.r_addend); 122 123 if (!supported_rela(&swrela)) 124 continue; 125 126 debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n", 127 swrela.r_offset, swrela.r_info, swrela.r_addend); 128 129 if (swrela.r_offset < text_base) { 130 fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n", 131 argv[0], argv[1], pos); 132 return 4; 133 } 134 135 addr = swrela.r_offset - text_base; 136 137 if (fseek(f, addr, SEEK_SET) < 0) { 138 fprintf(stderr, "%s: %s: seek to %" 139 PRIx64 " failed: %s\n", 140 argv[0], argv[1], addr, strerror(errno)); 141 } 142 143 if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) { 144 fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n", 145 argv[0], argv[1], addr); 146 return 4; 147 } 148 } 149 150 if (fclose(f) < 0) { 151 fprintf(stderr, "%s: %s: close failed: %s\n", 152 argv[0], argv[1], strerror(errno)); 153 return 4; 154 } 155 156 return 0; 157 } 158