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