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
  19#ifndef R_AARCH64_RELATIVE
  20#define R_AARCH64_RELATIVE      1027
  21#endif
  22
  23static const bool debug_en;
  24
  25static 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
  34static 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
  53static 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
  66static inline uint64_t be64(uint64_t val)
  67{
  68        return swap64(val);
  69}
  70
  71static inline uint64_t le64(uint64_t val)
  72{
  73        return val;
  74}
  75#else
  76static inline uint64_t le64(uint64_t val)
  77{
  78        return swap64(val);
  79}
  80
  81static inline uint64_t be64(uint64_t val)
  82{
  83        return val;
  84}
  85#endif
  86
  87static 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
  94int 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