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