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 if (debug_en) { 31 va_start(args, fmt); 32 vprintf(fmt, args); 33 va_end(args); 34 } 35 } 36 37 static bool supported_rela(Elf64_Rela *rela) 38 { 39 uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */ 40 uint32_t type = rela->r_info & mask; 41 42 switch (type) { 43 #ifdef R_AARCH64_RELATIVE 44 case R_AARCH64_RELATIVE: 45 return true; 46 #endif 47 default: 48 fprintf(stderr, "warning: unsupported relocation type %" 49 PRIu32 " at %" PRIx64 "\n", 50 type, rela->r_offset); 51 52 return false; 53 } 54 } 55 56 static bool read_num(const char *str, uint64_t *num) 57 { 58 char *endptr; 59 *num = strtoull(str, &endptr, 16); 60 return str[0] && !endptr[0]; 61 } 62 63 int main(int argc, char **argv) 64 { 65 FILE *f; 66 int i, num; 67 uint64_t rela_start, rela_end, text_base; 68 69 if (argc != 5) { 70 fprintf(stderr, "Statically apply ELF rela relocations\n"); 71 fprintf(stderr, "Usage: %s <bin file> <text base> " \ 72 "<rela start> <rela end>\n", argv[0]); 73 fprintf(stderr, "All numbers in hex.\n"); 74 return 1; 75 } 76 77 f = fopen(argv[1], "r+b"); 78 if (!f) { 79 fprintf(stderr, "%s: Cannot open %s: %s\n", 80 argv[0], argv[1], strerror(errno)); 81 return 2; 82 } 83 84 if (!read_num(argv[2], &text_base) || 85 !read_num(argv[3], &rela_start) || 86 !read_num(argv[4], &rela_end)) { 87 fprintf(stderr, "%s: bad number\n", argv[0]); 88 return 3; 89 } 90 91 if (rela_start > rela_end || rela_start < text_base || 92 (rela_end - rela_start) % sizeof(Elf64_Rela)) { 93 fprintf(stderr, "%s: bad rela bounds\n", argv[0]); 94 return 3; 95 } 96 97 rela_start -= text_base; 98 rela_end -= text_base; 99 100 num = (rela_end - rela_start) / sizeof(Elf64_Rela); 101 102 for (i = 0; i < num; i++) { 103 Elf64_Rela rela, swrela; 104 uint64_t pos = rela_start + sizeof(Elf64_Rela) * i; 105 uint64_t addr; 106 107 if (fseek(f, pos, SEEK_SET) < 0) { 108 fprintf(stderr, "%s: %s: seek to %" PRIx64 109 " failed: %s\n", 110 argv[0], argv[1], pos, strerror(errno)); 111 } 112 113 if (fread(&rela, sizeof(rela), 1, f) != 1) { 114 fprintf(stderr, "%s: %s: read rela failed at %" 115 PRIx64 "\n", 116 argv[0], argv[1], pos); 117 return 4; 118 } 119 120 swrela.r_offset = cpu_to_le64(rela.r_offset); 121 swrela.r_info = cpu_to_le64(rela.r_info); 122 swrela.r_addend = cpu_to_le64(rela.r_addend); 123 124 if (!supported_rela(&swrela)) 125 continue; 126 127 debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n", 128 swrela.r_offset, swrela.r_info, swrela.r_addend); 129 130 if (swrela.r_offset < text_base) { 131 fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n", 132 argv[0], argv[1], pos); 133 return 4; 134 } 135 136 addr = swrela.r_offset - text_base; 137 138 if (fseek(f, addr, SEEK_SET) < 0) { 139 fprintf(stderr, "%s: %s: seek to %" 140 PRIx64 " failed: %s\n", 141 argv[0], argv[1], addr, strerror(errno)); 142 } 143 144 if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) { 145 fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n", 146 argv[0], argv[1], addr); 147 return 4; 148 } 149 } 150 151 if (fclose(f) < 0) { 152 fprintf(stderr, "%s: %s: close failed: %s\n", 153 argv[0], argv[1], strerror(errno)); 154 return 4; 155 } 156 157 return 0; 158 } 159