123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- /*
- * Copyright 2013 Freescale Semiconductor, Inc.
- *
- * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
- *
- * 64-bit and little-endian target only until we need to support a different
- * arch that needs this.
- */
- #include <elf.h>
- #include <errno.h>
- #include <inttypes.h>
- #include <stdarg.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "compiler.h"
- #ifndef R_AARCH64_RELATIVE
- #define R_AARCH64_RELATIVE 1027
- #endif
- static const bool debug_en;
- static void debug(const char *fmt, ...)
- {
- va_list args;
- va_start(args, fmt);
- if (debug_en)
- vprintf(fmt, args);
- }
- static bool supported_rela(Elf64_Rela *rela)
- {
- uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */
- uint32_t type = rela->r_info & mask;
- switch (type) {
- #ifdef R_AARCH64_RELATIVE
- case R_AARCH64_RELATIVE:
- return true;
- #endif
- default:
- fprintf(stderr, "warning: unsupported relocation type %"
- PRIu32 " at %" PRIx64 "\n",
- type, rela->r_offset);
- return false;
- }
- }
- static bool read_num(const char *str, uint64_t *num)
- {
- char *endptr;
- *num = strtoull(str, &endptr, 16);
- return str[0] && !endptr[0];
- }
- int main(int argc, char **argv)
- {
- FILE *f;
- int i, num;
- uint64_t rela_start, rela_end, text_base;
- if (argc != 5) {
- fprintf(stderr, "Statically apply ELF rela relocations\n");
- fprintf(stderr, "Usage: %s <bin file> <text base> " \
- "<rela start> <rela end>\n", argv[0]);
- fprintf(stderr, "All numbers in hex.\n");
- return 1;
- }
- f = fopen(argv[1], "r+b");
- if (!f) {
- fprintf(stderr, "%s: Cannot open %s: %s\n",
- argv[0], argv[1], strerror(errno));
- return 2;
- }
- if (!read_num(argv[2], &text_base) ||
- !read_num(argv[3], &rela_start) ||
- !read_num(argv[4], &rela_end)) {
- fprintf(stderr, "%s: bad number\n", argv[0]);
- return 3;
- }
- if (rela_start > rela_end || rela_start < text_base ||
- (rela_end - rela_start) % sizeof(Elf64_Rela)) {
- fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
- return 3;
- }
- rela_start -= text_base;
- rela_end -= text_base;
- num = (rela_end - rela_start) / sizeof(Elf64_Rela);
- for (i = 0; i < num; i++) {
- Elf64_Rela rela, swrela;
- uint64_t pos = rela_start + sizeof(Elf64_Rela) * i;
- uint64_t addr;
- if (fseek(f, pos, SEEK_SET) < 0) {
- fprintf(stderr, "%s: %s: seek to %" PRIx64
- " failed: %s\n",
- argv[0], argv[1], pos, strerror(errno));
- }
- if (fread(&rela, sizeof(rela), 1, f) != 1) {
- fprintf(stderr, "%s: %s: read rela failed at %"
- PRIx64 "\n",
- argv[0], argv[1], pos);
- return 4;
- }
- swrela.r_offset = cpu_to_le64(rela.r_offset);
- swrela.r_info = cpu_to_le64(rela.r_info);
- swrela.r_addend = cpu_to_le64(rela.r_addend);
- if (!supported_rela(&swrela))
- continue;
- debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n",
- swrela.r_offset, swrela.r_info, swrela.r_addend);
- if (swrela.r_offset < text_base) {
- fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n",
- argv[0], argv[1], pos);
- return 4;
- }
- addr = swrela.r_offset - text_base;
- if (fseek(f, addr, SEEK_SET) < 0) {
- fprintf(stderr, "%s: %s: seek to %"
- PRIx64 " failed: %s\n",
- argv[0], argv[1], addr, strerror(errno));
- }
- if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
- fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n",
- argv[0], argv[1], addr);
- return 4;
- }
- }
- if (fclose(f) < 0) {
- fprintf(stderr, "%s: %s: close failed: %s\n",
- argv[0], argv[1], strerror(errno));
- return 4;
- }
- return 0;
- }
|