The Pedigree Project 0.1
core/processor/hosted/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#include "pedigree/kernel/utilities/utility.h"
24
25namespace __pedigree_hosted {
26#include <dlfcn.h>
27}
28
29#define R_X86_64_NONE 0
30#define R_X86_64_64 1
31#define R_X86_64_PC32 2
32#define R_X86_64_GOT32 3
33#define R_X86_64_PLT32 4
34#define R_X86_64_COPY 5
35#define R_X86_64_GLOB_DAT 6
36#define R_X86_64_JUMP_SLOT 7
37#define R_X86_64_RELATIVE 8
38#define R_X86_64_GOTPCREL 9
39#define R_X86_64_32 10
40#define R_X86_64_32S 11
41#define R_X86_64_PC64 24
42#define R_X86_64_GOTOFF64 25
43#define R_X86_64_GOTPC32 26
44#define R_X86_64_GOT64 27
45#define R_X86_64_GOTPCREL64 28
46#define R_X86_64_GOTPC64 29
47#define R_X86_64_GOTPLT64 30
48#define R_X86_64_PLTOFF64 31
49
50#define TWO_GIGABYTES 0x80000000ULL
51
52static bool checkPc32Displacement(uint64_t S, uint64_t A, uint64_t P, uint64_t& diff) {
53 if (abs_difference(S + A, P) >= 0x80000000ULL) {
54 return false;
55 }
56
57 diff = (((S + A) - P) & 0xFFFFFFFFULL);
58 return true;
59}
60
62 uintptr_t loadBase, SymbolTable::Policy policy,
63 uintptr_t destinationAddress, uintptr_t destinationEnd) {
64 return false;
65}
66
67bool Elf::applyRelocation(ElfRela_t rel, ElfSectionHeader_t* pSh, SymbolTable* pSymtab,
68 uintptr_t loadBase, SymbolTable::Policy policy,
69 uintptr_t destinationAddress, uintptr_t destinationEnd) {
70 // Section not loaded?
71 if (pSh && pSh->addr == 0)
72 return true; // Not a fatal error.
73
74 // Avoid NONE relocations.
75 if (R_TYPE(rel.info) == R_X86_64_NONE)
76 return true;
77
78 if (!loadBase) {
79 loadBase = pSh ? pSh->addr - pSh->offset : 0;
80 if (!loadBase) {
81 ERROR("Cannot apply relocation, no load base given.");
82 return false;
83 }
84 }
85
86 // Get the address of the unit to be relocated.
87 uint64_t address = loadBase + rel.offset;
88
89 // Addend is the value currently at the given address.
90 Elf_Sxword A = rel.addend;
91
92 // 'Place' is the address.
93 uint64_t P = address;
94
95 // Symbol location.
96 uint64_t S = 0;
97 ElfSymbol_t* pSymbols = 0;
98 if (!m_pDynamicSymbolTable)
99 pSymbols = m_pSymbolTable;
100 else
101 pSymbols = m_pDynamicSymbolTable;
102
103 const char* pStringTable = 0;
104 if (!m_pDynamicStringTable)
105 pStringTable = reinterpret_cast<const char*>(m_pStringTable);
106 else
107 pStringTable = m_pDynamicStringTable;
108
109 String symbolName("(unknown)");
110
111 // If this is a section header, patch straight to it.
112 size_t symbolSize = 0;
113 if (pSymbols && ST_TYPE(pSymbols[R_SYM(rel.info)].info) == 3) {
114 // Section type - the name will be the name of the section header it
115 // refers to.
116 int shndx = pSymbols[R_SYM(rel.info)].shndx;
117 ElfSectionHeader_t* pSh = &m_pSectionHeaders[shndx];
118 S = pSh->addr;
119 symbolSize = pSymbols[R_SYM(rel.info)].size;
120 } else if (R_TYPE(rel.info) != R_X86_64_RELATIVE) // Relative doesn't need a
121 // symbol!
122 {
123 if (!pStringTable || !pSymbols)
124 return false;
125 const char* pStr = pStringTable + pSymbols[R_SYM(rel.info)].name;
126
127 if (R_TYPE(rel.info) == R_X86_64_COPY)
129
130 // Preserve module-local binding before looking outside this ELF.
131 S = m_SymbolTable.lookup(String(pStr), this, policy);
132
133 if (S == 0 && pSymtab && pSymtab != &m_SymbolTable) {
134 S = pSymtab->lookup(String(pStr), this, policy);
135 }
136
137 if (S == 0) {
138 // Ask the process linker for an exported kernel or host-library
139 // symbol before using the kernel's on-disk symbol table.
140 void* pSym = __pedigree_hosted::dlsym(RTLD_DEFAULT, pStr);
141 if (pSym) {
142 S = reinterpret_cast<uint64_t>(pSym);
143 }
144 }
145
146 if (S == 0) {
147 // Failed to find - fall back to kernel symbol table.
148 S = KernelElf::instance().getSymbolTable()->lookup(String(pStr), this, policy);
149 }
150
151 if (S == 0 && ST_BIND(pSymbols[R_SYM(rel.info)].info) == 2) {
152 // Weak relocation that couldn't be found, which is OK.
153 S = ~0UL;
154 }
155
156 if (S == 0) {
157 WARNING("Relocation failed for symbol \"" << pStr << "\" (relocation=" << R_TYPE(rel.info)
158 << ")");
159 WARNING("Relocation at " << address << " (offset=" << rel.offset << ")...");
160 }
161
162 symbolName.assign(pStr);
163 symbolSize = pSymbols[R_SYM(rel.info)].size;
164 }
165
166 if (S == 0 && (R_TYPE(rel.info) != R_X86_64_RELATIVE))
167 return false;
168 if (S == ~0UL)
169 S = 0; // undefined
170
171 // Base address
172 uint64_t B = loadBase;
173
174 uint8_t r_type = R_TYPE(rel.info);
175 const bool writes32 = r_type == R_X86_64_PC32 || r_type == R_X86_64_32 || r_type == R_X86_64_32S;
176 const size_t resultSize = writes32 ? sizeof(uint32_t) : sizeof(uint64_t);
177 const uintptr_t resultAddress = destinationAddress ? destinationAddress : address;
178 if (destinationEnd &&
179 (resultAddress > destinationEnd || destinationEnd - resultAddress < resultSize)) {
180 ERROR("Relocation crosses the demand-page staging boundary");
181 return false;
182 }
183
184 uint64_t result = writes32 ? *reinterpret_cast<uint32_t*>(resultAddress)
185 : *reinterpret_cast<uint64_t*>(resultAddress);
186 uint64_t tmp = 0;
187
188 switch (r_type) {
189 case R_X86_64_NONE:
190 break;
191 case R_X86_64_64:
192 result = S + A;
193 break;
194 case R_X86_64_PC32:
195 result = (S + A - P) & 0xFFFFFFFF;
196 break;
197 case R_X86_64_PC64:
198 result = (S + A) - P;
199 break;
200 case R_X86_64_COPY:
201 NOTICE("Copy needed, " << symbolSize << " bytes wanted");
202 if (!S)
203 return false;
204 result = *reinterpret_cast<uintptr_t*>(S);
205 break;
206 case R_X86_64_JUMP_SLOT:
207 case R_X86_64_GLOB_DAT:
208 result = S;
209 break;
210 case R_X86_64_RELATIVE:
211 result = B + A;
212 break;
213 case R_X86_64_32:
214 case R_X86_64_32S:
215 tmp = S + A;
216
217 if ((r_type == R_X86_64_32) && ((tmp & 0xFFFFFFFF00000000ULL) != 0)) {
218 ERROR("Relocation for symbol '" << symbolName << "' will be truncated to fit!");
219 } else if (r_type == R_X86_64_32S) {
220 // did this sign extend?
221 uint64_t sign = (tmp & 0x80000000ULL) >> 31ULL;
222 uint64_t top = (tmp & 0xFFFFFFFF00000000ULL) >> 32ULL;
223 if ((sign * 0xFFFFFFFFUL) != top) {
224 ERROR("Relocation for symbol '" << symbolName
225 << "' will be truncated to fit (sign-extension was "
226 "incorrect)");
227 }
228 }
229
230 result = tmp & 0xFFFFFFFFUL;
231 break;
232 break;
233 default:
234 ERROR("Relocation not supported for symbol \"" << symbolName << "\": " << Dec
235 << R_TYPE(rel.info));
236 }
237
238 // Write back the result.
239 if (writes32)
240 *reinterpret_cast<uint32_t*>(resultAddress) = static_cast<uint32_t>(result);
241 else
242 *reinterpret_cast<uint64_t*>(resultAddress) = result;
243 return true;
244}
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
Definition elf.h:81