relocate-rela.c 3.4 KB

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