The Pedigree Project 0.1
core/processor/x64/Elf.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/linker/Elf.h"
22#include "pedigree/kernel/linker/KernelElf.h"
23
24static constexpr bool VerboseElf = false;
25#define VERBOSE_NOTICE(x) \
26 do { \
27 EMIT_IF(VerboseElf) { \
28 NOTICE(x); \
29 } \
30 } while (0)
31
32// http://www.caldera.com/developers/devspecs/abi386-4.pdf
33
34#define R_X86_64_NONE 0
35#define R_X86_64_64 1
36#define R_X86_64_PC32 2
37#define R_X86_64_GOT32 3
38#define R_X86_64_PLT32 4
39#define R_X86_64_COPY 5
40#define R_X86_64_GLOB_DAT 6
41#define R_X86_64_JUMP_SLOT 7
42#define R_X86_64_RELATIVE 8
43#define R_X86_64_GOTPCREL 9
44#define R_X86_64_32 10
45#define R_X86_64_32S 11
46#define R_X86_64_PC64 24
47#define R_X86_64_GOTOFF64 25
48#define R_X86_64_GOTPC32 26
49#define R_X86_64_GOT64 27
50#define R_X86_64_GOTPCREL64 28
51#define R_X86_64_GOTPC64 29
52#define R_X86_64_GOTPLT64 30
53#define R_X86_64_PLTOFF64 31
54
56 uintptr_t loadBase, SymbolTable::Policy policy,
57 uintptr_t destinationAddress, uintptr_t destinationEnd) {
58 ERROR("The X64 architecture does not use REL entries!");
59 return false;
60}
61
62bool Elf::applyRelocation(ElfRela_t rel, ElfSectionHeader_t* pSh, SymbolTable* pSymtab,
63 uintptr_t loadBase, SymbolTable::Policy policy,
64 uintptr_t destinationAddress, uintptr_t destinationEnd) {
65 // Section not loaded?
66 if (pSh && pSh->addr == 0) {
67 return true; // Not a fatal error.
68 }
69
70 // Avoid NONE relocations.
71 if (R_TYPE(rel.info) == R_X86_64_NONE) {
72 return true;
73 }
74
75 if (!loadBase) {
76 loadBase = pSh ? pSh->addr - pSh->offset : 0;
77 if (!loadBase) {
78 ERROR("Cannot apply relocation, no load base given.");
79 return false;
80 }
81 }
82
83 // Get the address of the unit to be relocated.
84 // NOTE: offsets are against the binary start, not the section
85 uint64_t address = loadBase + rel.offset;
86
87 // Addend is the value currently at the given address.
88 Elf_Sxword A = rel.addend;
89
90 // 'Place' is the address.
91 uint64_t P = address;
92
93 // Symbol location.
94 uint64_t S = 0;
95 ElfSymbol_t* pSymbols = 0;
96 if (!m_pDynamicSymbolTable) {
97 pSymbols = m_pSymbolTable;
98 } else {
99 pSymbols = m_pDynamicSymbolTable;
100 }
101
102 const char* pStringTable = 0;
103 if (!m_pDynamicStringTable) {
104 pStringTable = reinterpret_cast<const char*>(m_pStringTable);
105 } else {
106 pStringTable = m_pDynamicStringTable;
107 }
108
109 String symbolName("(unknown)");
110
111 size_t symbolSize = 0;
112
113 // If this is a section header, patch straight to it.
114 if (pSymbols && ST_TYPE(pSymbols[R_SYM(rel.info)].info) == 3) {
115 // Section type - the name will be the name of the section header it
116 // refers to.
117 int shndx = pSymbols[R_SYM(rel.info)].shndx;
118 ElfSectionHeader_t* pReferencedSh = &m_pSectionHeaders[shndx];
119 S = pReferencedSh->addr;
120 symbolSize = pSymbols[R_SYM(rel.info)].size;
121 } else if (pSymbols && R_TYPE(rel.info) != R_X86_64_RELATIVE) // Relative
122 // doesn't need
123 // a symbol!
124 {
125 const char* pStr = pStringTable + pSymbols[R_SYM(rel.info)].name;
126
127 if (pSymtab == 0)
128 pSymtab = &m_SymbolTable;
129
130 if (R_TYPE(rel.info) == R_X86_64_COPY)
132 S = pSymtab->lookup(String(pStr), this, policy);
133 if (S == 0) {
134 // Failed to find - fall back to kernel symbol table.
135 VERBOSE_NOTICE("Falling back to kernel symbol table for '" << pStr << "'");
136 S = KernelElf::instance().getSymbolTable()->lookup(String(pStr), this, policy);
137 }
138
139 if (S == 0 && ST_BIND(pSymbols[R_SYM(rel.info)].info) == 2) {
140 // Weak relocation that couldn't be found, which is OK.
141 S = ~0UL;
142 }
143
144 if (S == 0) {
145 WARNING("Relocation failed for symbol \"" << pStr << "\" (relocation=" << R_TYPE(rel.info)
146 << ")");
147 WARNING("Relocation at " << Hex << address << " (offset=" << rel.offset << ")...");
148 }
149
150 symbolName.assign(pStr);
151 symbolSize = pSymbols[R_SYM(rel.info)].size;
152 }
153
154 if (S == 0 && (R_TYPE(rel.info) != R_X86_64_RELATIVE))
155 return false;
156 if (S == ~0UL)
157 S = 0; // weak relocation, undefined
158
159 // Base address
160 uint64_t B = loadBase;
161
162 uint8_t r_type = R_TYPE(rel.info);
163 const bool writes32 = r_type == R_X86_64_PC32 || r_type == R_X86_64_32 || r_type == R_X86_64_32S;
164 const size_t resultSize = writes32 ? sizeof(uint32_t) : sizeof(uint64_t);
165 const uintptr_t resultAddress = destinationAddress ? destinationAddress : address;
166 if (destinationEnd &&
167 (resultAddress > destinationEnd || destinationEnd - resultAddress < resultSize)) {
168 ERROR("Relocation crosses the demand-page staging boundary");
169 return false;
170 }
171
172 uint64_t result = writes32 ? *reinterpret_cast<uint32_t*>(resultAddress)
173 : *reinterpret_cast<uint64_t*>(resultAddress);
174 uint64_t tmp = 0;
175
176 VERBOSE_NOTICE("");
177 VERBOSE_NOTICE("Relocation for " << symbolName);
178 VERBOSE_NOTICE("A=" << Hex << A << " B=" << B << " S=" << S << " P=" << P);
179
180 switch (r_type) {
181 case R_X86_64_NONE:
182 VERBOSE_NOTICE("R_X86_64_NONE");
183 break;
184 case R_X86_64_64:
185 VERBOSE_NOTICE("R_X86_64_64");
186 result = S + A;
187 break;
188 case R_X86_64_PC32:
189 VERBOSE_NOTICE("R_X86_64_PC32");
190 result = (S + A - P) & 0xFFFFFFFF;
191 break;
192 case R_X86_64_COPY:
193 VERBOSE_NOTICE("R_X86_64_COPY");
194 if (!S) {
195 ERROR(
196 "Cannot perform a R_X86_64_COPY relocation for a weak "
197 "symbol.");
198 return false;
199 }
200
201 NOTICE("Copy needed, " << symbolSize << " bytes wanted");
202 result = *reinterpret_cast<uintptr_t*>(S);
203 break;
204 case R_X86_64_JUMP_SLOT:
205 case R_X86_64_GLOB_DAT:
206 VERBOSE_NOTICE("R_X86_64_JUMP_SLOT/R_X86_64_GLOB_DAT");
207
208 result = S;
209 break;
210 case R_X86_64_RELATIVE:
211 VERBOSE_NOTICE("R_X86_64_RELATIVE");
212 result = B + A;
213 break;
214 case R_X86_64_32:
215 case R_X86_64_32S:
216 VERBOSE_NOTICE("R_X86_64_32(S)");
217 tmp = S + A;
218
219 if ((r_type == R_X86_64_32) && ((tmp & 0xFFFFFFFF00000000ULL) != 0)) {
220 ERROR("Relocation for symbol '" << symbolName << "' will be truncated to fit!");
221 } else if (r_type == R_X86_64_32S) {
222 // did this sign extend?
223 uint64_t sign = (tmp & 0x80000000ULL) >> 31ULL;
224 uint64_t top = (tmp & 0xFFFFFFFF00000000ULL) >> 32ULL;
225 if ((sign * 0xFFFFFFFFUL) != top) {
226 ERROR("Relocation for symbol '" << symbolName
227 << "' will be truncated to fit (sign-extension was "
228 "incorrect)");
229 }
230 }
231
232 result = tmp & 0xFFFFFFFFUL;
233 break;
234 default:
235 ERROR("Relocation not supported for symbol \"" << symbolName << "\": " << Dec
236 << R_TYPE(rel.info));
237 }
238
239 VERBOSE_NOTICE("result=" << Hex << result);
240 VERBOSE_NOTICE("");
241
242 // Write back the result.
243 if (writes32)
244 *reinterpret_cast<uint32_t*>(resultAddress) = static_cast<uint32_t>(result);
245 else
246 *reinterpret_cast<uint64_t*>(resultAddress) = result;
247 return true;
248}
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
@ Hex
Definition Log.h:124
Definition elf.h:81