gen-hyprel.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020 - Google LLC
  4. * Author: David Brazdil <[email protected]>
  5. *
  6. * Generates relocation information used by the kernel to convert
  7. * absolute addresses in hyp data from kernel VAs to hyp VAs.
  8. *
  9. * This is necessary because hyp code is linked into the same binary
  10. * as the kernel but executes under different memory mappings.
  11. * If the compiler used absolute addressing, those addresses need to
  12. * be converted before they are used by hyp code.
  13. *
  14. * The input of this program is the relocatable ELF object containing
  15. * all hyp code/data, not yet linked into vmlinux. Hyp section names
  16. * should have been prefixed with `.hyp` at this point.
  17. *
  18. * The output (printed to stdout) is an assembly file containing
  19. * an array of 32-bit integers and static relocations that instruct
  20. * the linker of `vmlinux` to populate the array entries with offsets
  21. * to positions in the kernel binary containing VAs used by hyp code.
  22. *
  23. * Note that dynamic relocations could be used for the same purpose.
  24. * However, those are only generated if CONFIG_RELOCATABLE=y.
  25. */
  26. #include <elf.h>
  27. #include <endian.h>
  28. #include <errno.h>
  29. #include <fcntl.h>
  30. #include <stdbool.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/mman.h>
  35. #include <sys/types.h>
  36. #include <sys/stat.h>
  37. #include <unistd.h>
  38. #include <generated/autoconf.h>
  39. #define HYP_SECTION_PREFIX ".hyp"
  40. #define HYP_RELOC_SECTION ".hyp.reloc"
  41. #define HYP_SECTION_SYMBOL_PREFIX "__hyp_section_"
  42. /*
  43. * AArch64 relocation type constants.
  44. * Included in case these are not defined in the host toolchain.
  45. */
  46. #ifndef R_AARCH64_ABS64
  47. #define R_AARCH64_ABS64 257
  48. #endif
  49. #ifndef R_AARCH64_PREL64
  50. #define R_AARCH64_PREL64 260
  51. #endif
  52. #ifndef R_AARCH64_PREL32
  53. #define R_AARCH64_PREL32 261
  54. #endif
  55. #ifndef R_AARCH64_PREL16
  56. #define R_AARCH64_PREL16 262
  57. #endif
  58. #ifndef R_AARCH64_PLT32
  59. #define R_AARCH64_PLT32 314
  60. #endif
  61. #ifndef R_AARCH64_LD_PREL_LO19
  62. #define R_AARCH64_LD_PREL_LO19 273
  63. #endif
  64. #ifndef R_AARCH64_ADR_PREL_LO21
  65. #define R_AARCH64_ADR_PREL_LO21 274
  66. #endif
  67. #ifndef R_AARCH64_ADR_PREL_PG_HI21
  68. #define R_AARCH64_ADR_PREL_PG_HI21 275
  69. #endif
  70. #ifndef R_AARCH64_ADR_PREL_PG_HI21_NC
  71. #define R_AARCH64_ADR_PREL_PG_HI21_NC 276
  72. #endif
  73. #ifndef R_AARCH64_ADD_ABS_LO12_NC
  74. #define R_AARCH64_ADD_ABS_LO12_NC 277
  75. #endif
  76. #ifndef R_AARCH64_LDST8_ABS_LO12_NC
  77. #define R_AARCH64_LDST8_ABS_LO12_NC 278
  78. #endif
  79. #ifndef R_AARCH64_TSTBR14
  80. #define R_AARCH64_TSTBR14 279
  81. #endif
  82. #ifndef R_AARCH64_CONDBR19
  83. #define R_AARCH64_CONDBR19 280
  84. #endif
  85. #ifndef R_AARCH64_JUMP26
  86. #define R_AARCH64_JUMP26 282
  87. #endif
  88. #ifndef R_AARCH64_CALL26
  89. #define R_AARCH64_CALL26 283
  90. #endif
  91. #ifndef R_AARCH64_LDST16_ABS_LO12_NC
  92. #define R_AARCH64_LDST16_ABS_LO12_NC 284
  93. #endif
  94. #ifndef R_AARCH64_LDST32_ABS_LO12_NC
  95. #define R_AARCH64_LDST32_ABS_LO12_NC 285
  96. #endif
  97. #ifndef R_AARCH64_LDST64_ABS_LO12_NC
  98. #define R_AARCH64_LDST64_ABS_LO12_NC 286
  99. #endif
  100. #ifndef R_AARCH64_MOVW_PREL_G0
  101. #define R_AARCH64_MOVW_PREL_G0 287
  102. #endif
  103. #ifndef R_AARCH64_MOVW_PREL_G0_NC
  104. #define R_AARCH64_MOVW_PREL_G0_NC 288
  105. #endif
  106. #ifndef R_AARCH64_MOVW_PREL_G1
  107. #define R_AARCH64_MOVW_PREL_G1 289
  108. #endif
  109. #ifndef R_AARCH64_MOVW_PREL_G1_NC
  110. #define R_AARCH64_MOVW_PREL_G1_NC 290
  111. #endif
  112. #ifndef R_AARCH64_MOVW_PREL_G2
  113. #define R_AARCH64_MOVW_PREL_G2 291
  114. #endif
  115. #ifndef R_AARCH64_MOVW_PREL_G2_NC
  116. #define R_AARCH64_MOVW_PREL_G2_NC 292
  117. #endif
  118. #ifndef R_AARCH64_MOVW_PREL_G3
  119. #define R_AARCH64_MOVW_PREL_G3 293
  120. #endif
  121. #ifndef R_AARCH64_LDST128_ABS_LO12_NC
  122. #define R_AARCH64_LDST128_ABS_LO12_NC 299
  123. #endif
  124. /* Global state of the processed ELF. */
  125. static struct {
  126. const char *path;
  127. char *begin;
  128. size_t size;
  129. Elf64_Ehdr *ehdr;
  130. Elf64_Shdr *sh_table;
  131. const char *sh_string;
  132. } elf;
  133. #if defined(CONFIG_CPU_LITTLE_ENDIAN)
  134. #define elf16toh(x) le16toh(x)
  135. #define elf32toh(x) le32toh(x)
  136. #define elf64toh(x) le64toh(x)
  137. #define ELFENDIAN ELFDATA2LSB
  138. #elif defined(CONFIG_CPU_BIG_ENDIAN)
  139. #define elf16toh(x) be16toh(x)
  140. #define elf32toh(x) be32toh(x)
  141. #define elf64toh(x) be64toh(x)
  142. #define ELFENDIAN ELFDATA2MSB
  143. #else
  144. #error PDP-endian sadly unsupported...
  145. #endif
  146. #define fatal_error(fmt, ...) \
  147. ({ \
  148. fprintf(stderr, "error: %s: " fmt "\n", \
  149. elf.path, ## __VA_ARGS__); \
  150. exit(EXIT_FAILURE); \
  151. __builtin_unreachable(); \
  152. })
  153. #define fatal_perror(msg) \
  154. ({ \
  155. fprintf(stderr, "error: %s: " msg ": %s\n", \
  156. elf.path, strerror(errno)); \
  157. exit(EXIT_FAILURE); \
  158. __builtin_unreachable(); \
  159. })
  160. #define assert_op(lhs, rhs, fmt, op) \
  161. ({ \
  162. typeof(lhs) _lhs = (lhs); \
  163. typeof(rhs) _rhs = (rhs); \
  164. \
  165. if (!(_lhs op _rhs)) { \
  166. fatal_error("assertion " #lhs " " #op " " #rhs \
  167. " failed (lhs=" fmt ", rhs=" fmt \
  168. ", line=%d)", _lhs, _rhs, __LINE__); \
  169. } \
  170. })
  171. #define assert_eq(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, ==)
  172. #define assert_ne(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, !=)
  173. #define assert_lt(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, <)
  174. #define assert_ge(lhs, rhs, fmt) assert_op(lhs, rhs, fmt, >=)
  175. /*
  176. * Return a pointer of a given type at a given offset from
  177. * the beginning of the ELF file.
  178. */
  179. #define elf_ptr(type, off) ((type *)(elf.begin + (off)))
  180. /* Iterate over all sections in the ELF. */
  181. #define for_each_section(var) \
  182. for (var = elf.sh_table; var < elf.sh_table + elf16toh(elf.ehdr->e_shnum); ++var)
  183. /* Iterate over all Elf64_Rela relocations in a given section. */
  184. #define for_each_rela(shdr, var) \
  185. for (var = elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset)); \
  186. var < elf_ptr(Elf64_Rela, elf64toh(shdr->sh_offset) + elf64toh(shdr->sh_size)); var++)
  187. /* True if a string starts with a given prefix. */
  188. static inline bool starts_with(const char *str, const char *prefix)
  189. {
  190. return memcmp(str, prefix, strlen(prefix)) == 0;
  191. }
  192. /* Returns a string containing the name of a given section. */
  193. static inline const char *section_name(Elf64_Shdr *shdr)
  194. {
  195. return elf.sh_string + elf32toh(shdr->sh_name);
  196. }
  197. /* Returns a pointer to the first byte of section data. */
  198. static inline const char *section_begin(Elf64_Shdr *shdr)
  199. {
  200. return elf_ptr(char, elf64toh(shdr->sh_offset));
  201. }
  202. /* Find a section by its offset from the beginning of the file. */
  203. static inline Elf64_Shdr *section_by_off(Elf64_Off off)
  204. {
  205. assert_ne(off, 0UL, "%lu");
  206. return elf_ptr(Elf64_Shdr, off);
  207. }
  208. /* Find a section by its index. */
  209. static inline Elf64_Shdr *section_by_idx(uint16_t idx)
  210. {
  211. assert_ne(idx, SHN_UNDEF, "%u");
  212. return &elf.sh_table[idx];
  213. }
  214. /*
  215. * Memory-map the given ELF file, perform sanity checks, and
  216. * populate global state.
  217. */
  218. static void init_elf(const char *path)
  219. {
  220. int fd, ret;
  221. struct stat stat;
  222. /* Store path in the global struct for error printing. */
  223. elf.path = path;
  224. /* Open the ELF file. */
  225. fd = open(path, O_RDONLY);
  226. if (fd < 0)
  227. fatal_perror("Could not open ELF file");
  228. /* Get status of ELF file to obtain its size. */
  229. ret = fstat(fd, &stat);
  230. if (ret < 0) {
  231. close(fd);
  232. fatal_perror("Could not get status of ELF file");
  233. }
  234. /* mmap() the entire ELF file read-only at an arbitrary address. */
  235. elf.begin = mmap(0, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  236. if (elf.begin == MAP_FAILED) {
  237. close(fd);
  238. fatal_perror("Could not mmap ELF file");
  239. }
  240. /* mmap() was successful, close the FD. */
  241. close(fd);
  242. /* Get pointer to the ELF header. */
  243. assert_ge(stat.st_size, sizeof(*elf.ehdr), "%lu");
  244. elf.ehdr = elf_ptr(Elf64_Ehdr, 0);
  245. /* Check the ELF magic. */
  246. assert_eq(elf.ehdr->e_ident[EI_MAG0], ELFMAG0, "0x%x");
  247. assert_eq(elf.ehdr->e_ident[EI_MAG1], ELFMAG1, "0x%x");
  248. assert_eq(elf.ehdr->e_ident[EI_MAG2], ELFMAG2, "0x%x");
  249. assert_eq(elf.ehdr->e_ident[EI_MAG3], ELFMAG3, "0x%x");
  250. /* Sanity check that this is an ELF64 relocatable object for AArch64. */
  251. assert_eq(elf.ehdr->e_ident[EI_CLASS], ELFCLASS64, "%u");
  252. assert_eq(elf.ehdr->e_ident[EI_DATA], ELFENDIAN, "%u");
  253. assert_eq(elf16toh(elf.ehdr->e_type), ET_REL, "%u");
  254. assert_eq(elf16toh(elf.ehdr->e_machine), EM_AARCH64, "%u");
  255. /* Populate fields of the global struct. */
  256. elf.sh_table = section_by_off(elf64toh(elf.ehdr->e_shoff));
  257. elf.sh_string = section_begin(section_by_idx(elf16toh(elf.ehdr->e_shstrndx)));
  258. }
  259. /* Print the prologue of the output ASM file. */
  260. static void emit_prologue(void)
  261. {
  262. printf(".data\n"
  263. ".pushsection " HYP_RELOC_SECTION ", \"a\"\n");
  264. }
  265. /* Print ASM statements needed as a prologue to a processed hyp section. */
  266. static void emit_section_prologue(const char *sh_orig_name)
  267. {
  268. /* Declare the hyp section symbol. */
  269. printf(".global %s%s\n", HYP_SECTION_SYMBOL_PREFIX, sh_orig_name);
  270. }
  271. /*
  272. * Print ASM statements to create a hyp relocation entry for a given
  273. * R_AARCH64_ABS64 relocation.
  274. *
  275. * The linker of vmlinux will populate the position given by `rela` with
  276. * an absolute 64-bit kernel VA. If the kernel is relocatable, it will
  277. * also generate a dynamic relocation entry so that the kernel can shift
  278. * the address at runtime for KASLR.
  279. *
  280. * Emit a 32-bit offset from the current address to the position given
  281. * by `rela`. This way the kernel can iterate over all kernel VAs used
  282. * by hyp at runtime and convert them to hyp VAs. However, that offset
  283. * will not be known until linking of `vmlinux`, so emit a PREL32
  284. * relocation referencing a symbol that the hyp linker script put at
  285. * the beginning of the relocated section + the offset from `rela`.
  286. */
  287. static void emit_rela_abs64(Elf64_Rela *rela, const char *sh_orig_name)
  288. {
  289. /* Offset of this reloc from the beginning of HYP_RELOC_SECTION. */
  290. static size_t reloc_offset;
  291. /* Create storage for the 32-bit offset. */
  292. printf(".word 0\n");
  293. /*
  294. * Create a PREL32 relocation which instructs the linker of `vmlinux`
  295. * to insert offset to position <base> + <offset>, where <base> is
  296. * a symbol at the beginning of the relocated section, and <offset>
  297. * is `rela->r_offset`.
  298. */
  299. printf(".reloc %lu, R_AARCH64_PREL32, %s%s + 0x%lx\n",
  300. reloc_offset, HYP_SECTION_SYMBOL_PREFIX, sh_orig_name,
  301. elf64toh(rela->r_offset));
  302. reloc_offset += 4;
  303. }
  304. /* Print the epilogue of the output ASM file. */
  305. static void emit_epilogue(void)
  306. {
  307. printf(".popsection\n");
  308. }
  309. /*
  310. * Iterate over all RELA relocations in a given section and emit
  311. * hyp relocation data for all absolute addresses in hyp code/data.
  312. *
  313. * Static relocations that generate PC-relative-addressing are ignored.
  314. * Failure is reported for unexpected relocation types.
  315. */
  316. static void emit_rela_section(Elf64_Shdr *sh_rela)
  317. {
  318. Elf64_Shdr *sh_orig = &elf.sh_table[elf32toh(sh_rela->sh_info)];
  319. const char *sh_orig_name = section_name(sh_orig);
  320. Elf64_Rela *rela;
  321. /* Skip all non-hyp sections. */
  322. if (!starts_with(sh_orig_name, HYP_SECTION_PREFIX))
  323. return;
  324. emit_section_prologue(sh_orig_name);
  325. for_each_rela(sh_rela, rela) {
  326. uint32_t type = (uint32_t)elf64toh(rela->r_info);
  327. /* Check that rela points inside the relocated section. */
  328. assert_lt(elf64toh(rela->r_offset), elf64toh(sh_orig->sh_size), "0x%lx");
  329. switch (type) {
  330. /*
  331. * Data relocations to generate absolute addressing.
  332. * Emit a hyp relocation.
  333. */
  334. case R_AARCH64_ABS64:
  335. emit_rela_abs64(rela, sh_orig_name);
  336. break;
  337. /* Allow position-relative data relocations. */
  338. case R_AARCH64_PREL64:
  339. case R_AARCH64_PREL32:
  340. case R_AARCH64_PREL16:
  341. case R_AARCH64_PLT32:
  342. break;
  343. /* Allow relocations to generate PC-relative addressing. */
  344. case R_AARCH64_LD_PREL_LO19:
  345. case R_AARCH64_ADR_PREL_LO21:
  346. case R_AARCH64_ADR_PREL_PG_HI21:
  347. case R_AARCH64_ADR_PREL_PG_HI21_NC:
  348. case R_AARCH64_ADD_ABS_LO12_NC:
  349. case R_AARCH64_LDST8_ABS_LO12_NC:
  350. case R_AARCH64_LDST16_ABS_LO12_NC:
  351. case R_AARCH64_LDST32_ABS_LO12_NC:
  352. case R_AARCH64_LDST64_ABS_LO12_NC:
  353. case R_AARCH64_LDST128_ABS_LO12_NC:
  354. break;
  355. /* Allow relative relocations for control-flow instructions. */
  356. case R_AARCH64_TSTBR14:
  357. case R_AARCH64_CONDBR19:
  358. case R_AARCH64_JUMP26:
  359. case R_AARCH64_CALL26:
  360. break;
  361. /* Allow group relocations to create PC-relative offset inline. */
  362. case R_AARCH64_MOVW_PREL_G0:
  363. case R_AARCH64_MOVW_PREL_G0_NC:
  364. case R_AARCH64_MOVW_PREL_G1:
  365. case R_AARCH64_MOVW_PREL_G1_NC:
  366. case R_AARCH64_MOVW_PREL_G2:
  367. case R_AARCH64_MOVW_PREL_G2_NC:
  368. case R_AARCH64_MOVW_PREL_G3:
  369. break;
  370. default:
  371. fatal_error("Unexpected RELA type %u", type);
  372. }
  373. }
  374. }
  375. /* Iterate over all sections and emit hyp relocation data for RELA sections. */
  376. static void emit_all_relocs(void)
  377. {
  378. Elf64_Shdr *shdr;
  379. for_each_section(shdr) {
  380. switch (elf32toh(shdr->sh_type)) {
  381. case SHT_REL:
  382. fatal_error("Unexpected SHT_REL section \"%s\"",
  383. section_name(shdr));
  384. case SHT_RELA:
  385. emit_rela_section(shdr);
  386. break;
  387. }
  388. }
  389. }
  390. int main(int argc, const char **argv)
  391. {
  392. if (argc != 2) {
  393. fprintf(stderr, "Usage: %s <elf_input>\n", argv[0]);
  394. return EXIT_FAILURE;
  395. }
  396. init_elf(argv[1]);
  397. emit_prologue();
  398. emit_all_relocs();
  399. emit_epilogue();
  400. return EXIT_SUCCESS;
  401. }