linker.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <vector>
  5. #include "common/common_funcs.h"
  6. #include "common/logging/log.h"
  7. #include "common/swap.h"
  8. #include "core/loader/linker.h"
  9. #include "core/memory.h"
  10. namespace Loader {
  11. enum class RelocationType : u32 { ABS64 = 257, GLOB_DAT = 1025, JUMP_SLOT = 1026, RELATIVE = 1027 };
  12. enum DynamicType : u32 {
  13. DT_NULL = 0,
  14. DT_PLTRELSZ = 2,
  15. DT_STRTAB = 5,
  16. DT_SYMTAB = 6,
  17. DT_RELA = 7,
  18. DT_RELASZ = 8,
  19. DT_STRSZ = 10,
  20. DT_JMPREL = 23,
  21. };
  22. struct Elf64_Rela {
  23. u64_le offset;
  24. RelocationType type;
  25. u32_le symbol;
  26. s64_le addend;
  27. };
  28. static_assert(sizeof(Elf64_Rela) == 0x18, "Elf64_Rela has incorrect size.");
  29. struct Elf64_Dyn {
  30. u64_le tag;
  31. u64_le value;
  32. };
  33. static_assert(sizeof(Elf64_Dyn) == 0x10, "Elf64_Dyn has incorrect size.");
  34. struct Elf64_Sym {
  35. u32_le name;
  36. INSERT_PADDING_BYTES(0x2);
  37. u16_le shndx;
  38. u64_le value;
  39. u64_le size;
  40. };
  41. static_assert(sizeof(Elf64_Sym) == 0x18, "Elf64_Sym has incorrect size.");
  42. void Linker::WriteRelocations(std::vector<u8>& program_image,
  43. const std::vector<Symbol>& symbols, u64 relocation_offset,
  44. u64 size, bool is_jump_relocation, VAddr load_base) {
  45. for (u64 i = 0; i < size; i += sizeof(Elf64_Rela)) {
  46. Elf64_Rela rela;
  47. std::memcpy(&rela, &program_image[relocation_offset + i], sizeof(Elf64_Rela));
  48. const Symbol& symbol = symbols[rela.symbol];
  49. switch (rela.type) {
  50. case RelocationType::RELATIVE: {
  51. const u64 value = load_base + rela.addend;
  52. if (!symbol.name.empty()) {
  53. exports[symbol.name] = value;
  54. }
  55. std::memcpy(&program_image[rela.offset], &value, sizeof(u64));
  56. break;
  57. }
  58. case RelocationType::JUMP_SLOT:
  59. case RelocationType::GLOB_DAT:
  60. if (!symbol.value) {
  61. imports[symbol.name] = {rela.offset + load_base, 0};
  62. } else {
  63. exports[symbol.name] = symbol.value;
  64. std::memcpy(&program_image[rela.offset], &symbol.value, sizeof(u64));
  65. }
  66. break;
  67. case RelocationType::ABS64:
  68. if (!symbol.value) {
  69. imports[symbol.name] = {rela.offset + load_base, rela.addend};
  70. } else {
  71. const u64 value = symbol.value + rela.addend;
  72. exports[symbol.name] = value;
  73. std::memcpy(&program_image[rela.offset], &value, sizeof(u64));
  74. }
  75. break;
  76. default:
  77. LOG_CRITICAL(Loader, "Unknown relocation type: %d", rela.type);
  78. break;
  79. }
  80. }
  81. }
  82. void Linker::Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset,
  83. VAddr load_base) {
  84. std::map<u64, u64> dynamic;
  85. while (dynamic_section_offset < program_image.size()) {
  86. Elf64_Dyn dyn;
  87. std::memcpy(&dyn, &program_image[dynamic_section_offset], sizeof(Elf64_Dyn));
  88. dynamic_section_offset += sizeof(Elf64_Dyn);
  89. if (dyn.tag == DT_NULL) {
  90. break;
  91. }
  92. dynamic[dyn.tag] = dyn.value;
  93. }
  94. u64 offset = dynamic[DT_SYMTAB];
  95. std::vector<Symbol> symbols;
  96. while (offset < program_image.size()) {
  97. Elf64_Sym sym;
  98. std::memcpy(&sym, &program_image[offset], sizeof(Elf64_Sym));
  99. offset += sizeof(Elf64_Sym);
  100. if (sym.name >= dynamic[DT_STRSZ]) {
  101. break;
  102. }
  103. std::string name = reinterpret_cast<char*>(&program_image[dynamic[DT_STRTAB] + sym.name]);
  104. if (sym.value) {
  105. exports[name] = load_base + sym.value;
  106. symbols.emplace_back(std::move(name), load_base + sym.value);
  107. } else {
  108. symbols.emplace_back(std::move(name), 0);
  109. }
  110. }
  111. if (dynamic.find(DT_RELA) != dynamic.end()) {
  112. WriteRelocations(program_image, symbols, dynamic[DT_RELA], dynamic[DT_RELASZ], false,
  113. load_base);
  114. }
  115. if (dynamic.find(DT_JMPREL) != dynamic.end()) {
  116. WriteRelocations(program_image, symbols, dynamic[DT_JMPREL], dynamic[DT_PLTRELSZ], true,
  117. load_base);
  118. }
  119. }
  120. void Linker::ResolveImports() {
  121. // Resolve imports
  122. for (const auto& import : imports) {
  123. const auto& search = exports.find(import.first);
  124. if (search != exports.end()) {
  125. Memory::Write64(import.second.ea, search->second + import.second.addend);
  126. }
  127. else {
  128. LOG_ERROR(Loader, "Unresolved import: %s", import.first.c_str());
  129. }
  130. }
  131. }
  132. } // namespace Loader