relocate-rela.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause
  2. /*
  3. * Copyright 2013 Freescale Semiconductor, Inc.
  4. *
  5. * 64-bit and little-endian target only until we need to support a different
  6. * arch that needs this.
  7. */
  8. #include <elf.h>
  9. #include <errno.h>
  10. #include <inttypes.h>
  11. #include <stdarg.h>
  12. #include <stdbool.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include "compiler.h"
  17. #ifndef R_AARCH64_RELATIVE
  18. #define R_AARCH64_RELATIVE 1027
  19. #endif
  20. static const bool debug_en;
  21. static void debug(const char *fmt, ...)
  22. {
  23. va_list args;
  24. if (debug_en) {
  25. va_start(args, fmt);
  26. vprintf(fmt, args);
  27. va_end(args);
  28. }
  29. }
  30. static bool supported_rela(Elf64_Rela *rela)
  31. {
  32. uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */
  33. uint32_t type = rela->r_info & mask;
  34. switch (type) {
  35. #ifdef R_AARCH64_RELATIVE
  36. case R_AARCH64_RELATIVE:
  37. return true;
  38. #endif
  39. default:
  40. fprintf(stderr, "warning: unsupported relocation type %"
  41. PRIu32 " at %" PRIx64 "\n",
  42. type, rela->r_offset);
  43. return false;
  44. }
  45. }
  46. static bool read_num(const char *str, uint64_t *num)
  47. {
  48. char *endptr;
  49. *num = strtoull(str, &endptr, 16);
  50. return str[0] && !endptr[0];
  51. }
  52. int main(int argc, char **argv)
  53. {
  54. FILE *f;
  55. int i, num;
  56. uint64_t rela_start, rela_end, text_base;
  57. if (argc != 5) {
  58. fprintf(stderr, "Statically apply ELF rela relocations\n");
  59. fprintf(stderr, "Usage: %s <bin file> <text base> " \
  60. "<rela start> <rela end>\n", argv[0]);
  61. fprintf(stderr, "All numbers in hex.\n");
  62. return 1;
  63. }
  64. f = fopen(argv[1], "r+b");
  65. if (!f) {
  66. fprintf(stderr, "%s: Cannot open %s: %s\n",
  67. argv[0], argv[1], strerror(errno));
  68. return 2;
  69. }
  70. if (!read_num(argv[2], &text_base) ||
  71. !read_num(argv[3], &rela_start) ||
  72. !read_num(argv[4], &rela_end)) {
  73. fprintf(stderr, "%s: bad number\n", argv[0]);
  74. return 3;
  75. }
  76. if (rela_start > rela_end || rela_start < text_base ||
  77. (rela_end - rela_start) % sizeof(Elf64_Rela)) {
  78. fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
  79. return 3;
  80. }
  81. rela_start -= text_base;
  82. rela_end -= text_base;
  83. num = (rela_end - rela_start) / sizeof(Elf64_Rela);
  84. for (i = 0; i < num; i++) {
  85. Elf64_Rela rela, swrela;
  86. uint64_t pos = rela_start + sizeof(Elf64_Rela) * i;
  87. uint64_t addr;
  88. if (fseek(f, pos, SEEK_SET) < 0) {
  89. fprintf(stderr, "%s: %s: seek to %" PRIx64
  90. " failed: %s\n",
  91. argv[0], argv[1], pos, strerror(errno));
  92. }
  93. if (fread(&rela, sizeof(rela), 1, f) != 1) {
  94. fprintf(stderr, "%s: %s: read rela failed at %"
  95. PRIx64 "\n",
  96. argv[0], argv[1], pos);
  97. return 4;
  98. }
  99. swrela.r_offset = cpu_to_le64(rela.r_offset);
  100. swrela.r_info = cpu_to_le64(rela.r_info);
  101. swrela.r_addend = cpu_to_le64(rela.r_addend);
  102. if (!supported_rela(&swrela))
  103. continue;
  104. debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n",
  105. swrela.r_offset, swrela.r_info, swrela.r_addend);
  106. if (swrela.r_offset < text_base) {
  107. fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n",
  108. argv[0], argv[1], pos);
  109. return 4;
  110. }
  111. addr = swrela.r_offset - text_base;
  112. if (fseek(f, addr, SEEK_SET) < 0) {
  113. fprintf(stderr, "%s: %s: seek to %"
  114. PRIx64 " failed: %s\n",
  115. argv[0], argv[1], addr, strerror(errno));
  116. }
  117. if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
  118. fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n",
  119. argv[0], argv[1], addr);
  120. return 4;
  121. }
  122. }
  123. if (fclose(f) < 0) {
  124. fprintf(stderr, "%s: %s: close failed: %s\n",
  125. argv[0], argv[1], strerror(errno));
  126. return 4;
  127. }
  128. return 0;
  129. }