relacheck.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2023 - Google LLC
  4. * Author: Ard Biesheuvel <ardb@google.com>
  5. */
  6. #include <elf.h>
  7. #include <fcntl.h>
  8. #include <stdbool.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <sys/mman.h>
  13. #include <sys/stat.h>
  14. #include <sys/types.h>
  15. #include <unistd.h>
  16. #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
  17. #define HOST_ORDER ELFDATA2LSB
  18. #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
  19. #define HOST_ORDER ELFDATA2MSB
  20. #endif
  21. static Elf64_Ehdr *ehdr;
  22. static Elf64_Shdr *shdr;
  23. static const char *strtab;
  24. static bool swap;
  25. static uint64_t swab_elfxword(uint64_t val)
  26. {
  27. return swap ? __builtin_bswap64(val) : val;
  28. }
  29. static uint32_t swab_elfword(uint32_t val)
  30. {
  31. return swap ? __builtin_bswap32(val) : val;
  32. }
  33. static uint16_t swab_elfhword(uint16_t val)
  34. {
  35. return swap ? __builtin_bswap16(val) : val;
  36. }
  37. int main(int argc, char *argv[])
  38. {
  39. struct stat stat;
  40. int fd, ret;
  41. if (argc < 3) {
  42. fprintf(stderr, "file arguments missing\n");
  43. exit(EXIT_FAILURE);
  44. }
  45. fd = open(argv[1], O_RDWR);
  46. if (fd < 0) {
  47. fprintf(stderr, "failed to open %s\n", argv[1]);
  48. exit(EXIT_FAILURE);
  49. }
  50. ret = fstat(fd, &stat);
  51. if (ret < 0) {
  52. fprintf(stderr, "failed to stat() %s\n", argv[1]);
  53. exit(EXIT_FAILURE);
  54. }
  55. ehdr = mmap(0, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  56. if (ehdr == MAP_FAILED) {
  57. fprintf(stderr, "failed to mmap() %s\n", argv[1]);
  58. exit(EXIT_FAILURE);
  59. }
  60. swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
  61. shdr = (void *)ehdr + swab_elfxword(ehdr->e_shoff);
  62. strtab = (void *)ehdr +
  63. swab_elfxword(shdr[swab_elfhword(ehdr->e_shstrndx)].sh_offset);
  64. for (int i = 0; i < swab_elfhword(ehdr->e_shnum); i++) {
  65. unsigned long info, flags;
  66. bool prel64 = false;
  67. Elf64_Rela *rela;
  68. int numrela;
  69. if (swab_elfword(shdr[i].sh_type) != SHT_RELA)
  70. continue;
  71. /* only consider RELA sections operating on data */
  72. info = swab_elfword(shdr[i].sh_info);
  73. flags = swab_elfxword(shdr[info].sh_flags);
  74. if ((flags & (SHF_ALLOC | SHF_EXECINSTR)) != SHF_ALLOC)
  75. continue;
  76. /*
  77. * We generally don't permit ABS64 relocations in the code that
  78. * runs before relocation processing occurs. If statically
  79. * initialized absolute symbol references are unavoidable, they
  80. * may be emitted into a *.rodata.prel64 section and they will
  81. * be converted to place-relative 64-bit references. This
  82. * requires special handling in the referring code.
  83. */
  84. if (strstr(strtab + swab_elfword(shdr[info].sh_name),
  85. ".rodata.prel64")) {
  86. prel64 = true;
  87. }
  88. rela = (void *)ehdr + swab_elfxword(shdr[i].sh_offset);
  89. numrela = swab_elfxword(shdr[i].sh_size) / sizeof(*rela);
  90. for (int j = 0; j < numrela; j++) {
  91. uint64_t info = swab_elfxword(rela[j].r_info);
  92. if (ELF64_R_TYPE(info) != R_AARCH64_ABS64)
  93. continue;
  94. if (prel64) {
  95. /* convert ABS64 into PREL64 */
  96. info ^= R_AARCH64_ABS64 ^ R_AARCH64_PREL64;
  97. rela[j].r_info = swab_elfxword(info);
  98. } else {
  99. fprintf(stderr,
  100. "Unexpected absolute relocations detected in %s\n",
  101. argv[2]);
  102. close(fd);
  103. unlink(argv[1]);
  104. exit(EXIT_FAILURE);
  105. }
  106. }
  107. }
  108. close(fd);
  109. return 0;
  110. }