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