xref: /openbmc/u-boot/tools/relocate-rela.c (revision 4549e789c1d58a8c48e8a20f1b4bdb83e978c954)
1*4549e789STom Rini // SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause
28137af19SScott Wood /*
38137af19SScott Wood  * Copyright 2013 Freescale Semiconductor, Inc.
48137af19SScott Wood  *
58137af19SScott Wood  * 64-bit and little-endian target only until we need to support a different
68137af19SScott Wood  * arch that needs this.
78137af19SScott Wood  */
88137af19SScott Wood 
98137af19SScott Wood #include <elf.h>
108137af19SScott Wood #include <errno.h>
118137af19SScott Wood #include <inttypes.h>
128137af19SScott Wood #include <stdarg.h>
138137af19SScott Wood #include <stdbool.h>
148137af19SScott Wood #include <stdio.h>
158137af19SScott Wood #include <stdlib.h>
168137af19SScott Wood #include <string.h>
1743db3e3bSJonathan Gray #include "compiler.h"
188137af19SScott Wood 
198137af19SScott Wood #ifndef R_AARCH64_RELATIVE
208137af19SScott Wood #define R_AARCH64_RELATIVE	1027
218137af19SScott Wood #endif
228137af19SScott Wood 
238137af19SScott Wood static const bool debug_en;
248137af19SScott Wood 
debug(const char * fmt,...)258137af19SScott Wood static void debug(const char *fmt, ...)
268137af19SScott Wood {
278137af19SScott Wood 	va_list args;
288137af19SScott Wood 
29d27e35f2Sxypron.glpk@gmx.de 	if (debug_en) {
308137af19SScott Wood 		va_start(args, fmt);
318137af19SScott Wood 		vprintf(fmt, args);
32d27e35f2Sxypron.glpk@gmx.de 		va_end(args);
33d27e35f2Sxypron.glpk@gmx.de 	}
348137af19SScott Wood }
358137af19SScott Wood 
supported_rela(Elf64_Rela * rela)368137af19SScott Wood static bool supported_rela(Elf64_Rela *rela)
378137af19SScott Wood {
388137af19SScott Wood 	uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */
398137af19SScott Wood 	uint32_t type = rela->r_info & mask;
408137af19SScott Wood 
418137af19SScott Wood 	switch (type) {
428137af19SScott Wood #ifdef R_AARCH64_RELATIVE
438137af19SScott Wood 	case R_AARCH64_RELATIVE:
448137af19SScott Wood 		return true;
458137af19SScott Wood #endif
468137af19SScott Wood 	default:
478137af19SScott Wood 		fprintf(stderr, "warning: unsupported relocation type %"
488137af19SScott Wood 				PRIu32 " at %" PRIx64 "\n",
498137af19SScott Wood 			type, rela->r_offset);
508137af19SScott Wood 
518137af19SScott Wood 		return false;
528137af19SScott Wood 	}
538137af19SScott Wood }
548137af19SScott Wood 
read_num(const char * str,uint64_t * num)558137af19SScott Wood static bool read_num(const char *str, uint64_t *num)
568137af19SScott Wood {
578137af19SScott Wood 	char *endptr;
588137af19SScott Wood 	*num = strtoull(str, &endptr, 16);
598137af19SScott Wood 	return str[0] && !endptr[0];
608137af19SScott Wood }
618137af19SScott Wood 
main(int argc,char ** argv)628137af19SScott Wood int main(int argc, char **argv)
638137af19SScott Wood {
648137af19SScott Wood 	FILE *f;
658137af19SScott Wood 	int i, num;
668137af19SScott Wood 	uint64_t rela_start, rela_end, text_base;
678137af19SScott Wood 
688137af19SScott Wood 	if (argc != 5) {
698137af19SScott Wood 		fprintf(stderr, "Statically apply ELF rela relocations\n");
708137af19SScott Wood 		fprintf(stderr, "Usage: %s <bin file> <text base> " \
718137af19SScott Wood 				"<rela start> <rela end>\n", argv[0]);
728137af19SScott Wood 		fprintf(stderr, "All numbers in hex.\n");
738137af19SScott Wood 		return 1;
748137af19SScott Wood 	}
758137af19SScott Wood 
768137af19SScott Wood 	f = fopen(argv[1], "r+b");
778137af19SScott Wood 	if (!f) {
788137af19SScott Wood 		fprintf(stderr, "%s: Cannot open %s: %s\n",
798137af19SScott Wood 			argv[0], argv[1], strerror(errno));
808137af19SScott Wood 		return 2;
818137af19SScott Wood 	}
828137af19SScott Wood 
838137af19SScott Wood 	if (!read_num(argv[2], &text_base) ||
848137af19SScott Wood 	    !read_num(argv[3], &rela_start) ||
858137af19SScott Wood 	    !read_num(argv[4], &rela_end)) {
868137af19SScott Wood 		fprintf(stderr, "%s: bad number\n", argv[0]);
878137af19SScott Wood 		return 3;
888137af19SScott Wood 	}
898137af19SScott Wood 
908137af19SScott Wood 	if (rela_start > rela_end || rela_start < text_base ||
91e60cfd53SMasahiro Yamada 	    (rela_end - rela_start) % sizeof(Elf64_Rela)) {
928137af19SScott Wood 		fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
938137af19SScott Wood 		return 3;
948137af19SScott Wood 	}
958137af19SScott Wood 
968137af19SScott Wood 	rela_start -= text_base;
978137af19SScott Wood 	rela_end -= text_base;
988137af19SScott Wood 
998137af19SScott Wood 	num = (rela_end - rela_start) / sizeof(Elf64_Rela);
1008137af19SScott Wood 
1018137af19SScott Wood 	for (i = 0; i < num; i++) {
1028137af19SScott Wood 		Elf64_Rela rela, swrela;
1038137af19SScott Wood 		uint64_t pos = rela_start + sizeof(Elf64_Rela) * i;
1048137af19SScott Wood 		uint64_t addr;
1058137af19SScott Wood 
1068137af19SScott Wood 		if (fseek(f, pos, SEEK_SET) < 0) {
1078137af19SScott Wood 			fprintf(stderr, "%s: %s: seek to %" PRIx64
1088137af19SScott Wood 					" failed: %s\n",
1098137af19SScott Wood 				argv[0], argv[1], pos, strerror(errno));
1108137af19SScott Wood 		}
1118137af19SScott Wood 
1128137af19SScott Wood 		if (fread(&rela, sizeof(rela), 1, f) != 1) {
1138137af19SScott Wood 			fprintf(stderr, "%s: %s: read rela failed at %"
1148137af19SScott Wood 					PRIx64 "\n",
1158137af19SScott Wood 				argv[0], argv[1], pos);
1168137af19SScott Wood 			return 4;
1178137af19SScott Wood 		}
1188137af19SScott Wood 
11943db3e3bSJonathan Gray 		swrela.r_offset = cpu_to_le64(rela.r_offset);
12043db3e3bSJonathan Gray 		swrela.r_info = cpu_to_le64(rela.r_info);
12143db3e3bSJonathan Gray 		swrela.r_addend = cpu_to_le64(rela.r_addend);
1228137af19SScott Wood 
1238137af19SScott Wood 		if (!supported_rela(&swrela))
1248137af19SScott Wood 			continue;
1258137af19SScott Wood 
1268137af19SScott Wood 		debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n",
1278137af19SScott Wood 		      swrela.r_offset, swrela.r_info, swrela.r_addend);
1288137af19SScott Wood 
1298137af19SScott Wood 		if (swrela.r_offset < text_base) {
1308137af19SScott Wood 			fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n",
1318137af19SScott Wood 				argv[0], argv[1], pos);
1328137af19SScott Wood 			return 4;
1338137af19SScott Wood 		}
1348137af19SScott Wood 
1358137af19SScott Wood 		addr = swrela.r_offset - text_base;
1368137af19SScott Wood 
1378137af19SScott Wood 		if (fseek(f, addr, SEEK_SET) < 0) {
1388137af19SScott Wood 			fprintf(stderr, "%s: %s: seek to %"
1398137af19SScott Wood 					PRIx64 " failed: %s\n",
1408137af19SScott Wood 				argv[0], argv[1], addr, strerror(errno));
1418137af19SScott Wood 		}
1428137af19SScott Wood 
1438137af19SScott Wood 		if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
1448137af19SScott Wood 			fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n",
1458137af19SScott Wood 				argv[0], argv[1], addr);
1468137af19SScott Wood 			return 4;
1478137af19SScott Wood 		}
1488137af19SScott Wood 	}
1498137af19SScott Wood 
1508137af19SScott Wood 	if (fclose(f) < 0) {
1518137af19SScott Wood 		fprintf(stderr, "%s: %s: close failed: %s\n",
1528137af19SScott Wood 			argv[0], argv[1], strerror(errno));
1538137af19SScott Wood 		return 4;
1548137af19SScott Wood 	}
1558137af19SScott Wood 
1568137af19SScott Wood 	return 0;
1578137af19SScott Wood }
158