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