The Pedigree Project 0.1
core/processor/arm64/Elf.cc
1#include "pedigree/kernel/Log.h"
2#include "pedigree/kernel/linker/Elf.h"
3#include "pedigree/kernel/linker/KernelElf.h"
4
5namespace {
6enum AArch64Relocation {
7 R_AARCH64_NONE = 0,
8 R_AARCH64_ABS64 = 257,
9 R_AARCH64_ABS32 = 258,
10 R_AARCH64_PREL64 = 260,
11 R_AARCH64_PREL32 = 261,
12 R_AARCH64_COPY = 1024,
13 R_AARCH64_GLOB_DAT = 1025,
14 R_AARCH64_JUMP_SLOT = 1026,
15 R_AARCH64_RELATIVE = 1027,
16};
17}
18
20 SymbolTable::Policy, uintptr_t, uintptr_t) {
21 ERROR("AArch64 ELF REL relocation without an explicit addend");
22 return false;
23}
24
26 uintptr_t loadBase, SymbolTable::Policy policy,
27 uintptr_t destinationAddress, uintptr_t destinationEnd) {
28 if (section && !section->addr) {
29 return true;
30 }
31
32 const auto type = static_cast<AArch64Relocation>(R_TYPE(rel.info));
33 if (type == R_AARCH64_NONE) {
34 return true;
35 }
36 if (!loadBase) {
37 loadBase = section ? section->addr - section->offset : 0;
38 if (!loadBase) {
39 ERROR("AArch64 relocation has no load base");
40 return false;
41 }
42 }
43
44 const uintptr_t place = loadBase + rel.offset;
45 const uintptr_t destination = destinationAddress ? destinationAddress : place;
46 const size_t symbolIndex = R_SYM(rel.info);
47 ElfSymbol_t* elfSymbols = m_pDynamicSymbolTable ? m_pDynamicSymbolTable : m_pSymbolTable;
48 const char* strings = m_pDynamicStringTable ? m_pDynamicStringTable : m_pStringTable;
49 uintptr_t symbol = 0;
50 size_t symbolSize = 0;
51
52 if (type != R_AARCH64_RELATIVE) {
53 if (!elfSymbols) {
54 ERROR("AArch64 relocation has no symbol table");
55 return false;
56 }
57 const ElfSymbol_t& entry = elfSymbols[symbolIndex];
58 symbolSize = entry.size;
59 if (ST_TYPE(entry.info) == 3) {
60 if (!m_pSectionHeaders || entry.shndx >= m_nSectionHeaders) {
61 return false;
62 }
63 symbol = m_pSectionHeaders[entry.shndx].addr;
64 } else {
65 if (!strings) {
66 return false;
67 }
68 const char* name = strings + entry.name;
69 if (type == R_AARCH64_COPY) {
71 }
72 if (!symbols) {
73 symbols = &m_SymbolTable;
74 }
75 symbol = symbols->lookup(String(name), this, policy);
76 if (!symbol) {
77 symbol = KernelElf::instance().getSymbolTable()->lookup(String(name), this, policy);
78 }
79 if (!symbol && ST_BIND(entry.info) != 2) {
80 WARNING("AArch64 relocation failed for symbol \"" << name << "\"");
81 return false;
82 }
83 }
84 }
85
86 size_t writeSize = sizeof(uint64_t);
87 if (type == R_AARCH64_ABS32 || type == R_AARCH64_PREL32) {
88 writeSize = sizeof(uint32_t);
89 } else if (type == R_AARCH64_COPY) {
90 writeSize = symbolSize;
91 }
92 if (destinationEnd &&
93 (destination > destinationEnd || destinationEnd - destination < writeSize)) {
94 ERROR("AArch64 relocation crosses the demand-page staging boundary");
95 return false;
96 }
97
98 const uint64_t addend = static_cast<uint64_t>(rel.addend);
99 uint64_t value = 0;
100 switch (type) {
101 case R_AARCH64_ABS64:
102 value = symbol + addend;
103 break;
104 case R_AARCH64_ABS32:
105 value = symbol + addend;
106 if (value >> 32) {
107 ERROR("AArch64 ABS32 relocation overflows");
108 return false;
109 }
110 break;
111 case R_AARCH64_PREL64:
112 value = symbol + addend - place;
113 break;
114 case R_AARCH64_PREL32:
115 value = symbol + addend - place;
116 if (static_cast<int64_t>(value) < INT32_MIN || static_cast<int64_t>(value) > INT32_MAX) {
117 ERROR("AArch64 PREL32 relocation overflows");
118 return false;
119 }
120 break;
121 case R_AARCH64_GLOB_DAT:
122 case R_AARCH64_JUMP_SLOT:
123 value = symbol + addend;
124 break;
125 case R_AARCH64_RELATIVE:
126 value = loadBase + addend;
127 break;
128 case R_AARCH64_COPY:
129 if (!symbol) {
130 ERROR("AArch64 COPY relocation has no source");
131 return false;
132 }
133 for (size_t i = 0; i < symbolSize; ++i) {
134 reinterpret_cast<uint8_t*>(destination)[i] = reinterpret_cast<const uint8_t*>(symbol)[i];
135 }
136 return true;
137 default:
138 ERROR("Unsupported AArch64 ELF relocation " << Dec << R_TYPE(rel.info));
139 return false;
140 }
141
142 if (writeSize == sizeof(uint32_t)) {
143 *reinterpret_cast<uint32_t*>(destination) = static_cast<uint32_t>(value);
144 } else {
145 *reinterpret_cast<uint64_t*>(destination) = value;
146 }
147 return true;
148}
bool applyRelocation(ElfRel_t rel, ElfSectionHeader_t *pSh, SymbolTable *pSymtab=0, uintptr_t loadBase=0, SymbolTable::Policy policy=SymbolTable::LocalFirst, uintptr_t destinationAddress=0, uintptr_t destinationEnd=0)
static KernelElf & instance()
Definition KernelElf.h:135
uintptr_t EXPORTED_PUBLIC lookup(const HashedStringView &name, Elf *pElf, Policy policy=LocalFirst, Binding *pBinding=0)
@ Dec
Definition Log.h:126