relocate-rela.c 3.4 KB

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