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/linker/Elf.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/linker/KernelElf.h"
23 
24 #define VERBOSE_X64_ELF 0
25 
26 #if VERBOSE_X64_ELF
27 #define VERBOSE_NOTICE(x) NOTICE(x)
28 #else
29 #define VERBOSE_NOTICE(x)
30 #endif
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  ElfRel_t rel, ElfSectionHeader_t *pSh, SymbolTable *pSymtab,
57  uintptr_t loadBase, SymbolTable::Policy policy)
58 {
59  ERROR("The X64 architecture does not use REL entries!");
60  return false;
61 }
62 
64  ElfRela_t rel, ElfSectionHeader_t *pSh, SymbolTable *pSymtab,
65  uintptr_t loadBase, SymbolTable::Policy policy)
66 {
67  // Section not loaded?
68  if (pSh && pSh->addr == 0)
69  {
70  return true; // Not a fatal error.
71  }
72 
73  // Avoid NONE relocations.
74  if (R_TYPE(rel.info) == R_X86_64_NONE)
75  {
76  return true;
77  }
78 
79  if (!loadBase)
80  {
81  loadBase = pSh ? pSh->addr - pSh->offset : 0;
82  if (!loadBase)
83  {
84  ERROR("Cannot apply relocation, no load base given.");
85  return false;
86  }
87  }
88 
89  // Get the address of the unit to be relocated.
90  // NOTE: offsets are against the binary start, not the section
91  uint64_t address = loadBase + rel.offset;
92 
93  // Addend is the value currently at the given address.
94  Elf_Sxword A = rel.addend;
95 
96  // 'Place' is the address.
97  uint64_t P = address;
98 
99  // Symbol location.
100  uint64_t S = 0;
101  ElfSymbol_t *pSymbols = 0;
102  if (!m_pDynamicSymbolTable)
103  {
104  pSymbols = m_pSymbolTable;
105  }
106  else
107  {
108  pSymbols = m_pDynamicSymbolTable;
109  }
110 
111  const char *pStringTable = 0;
112  if (!m_pDynamicStringTable)
113  {
114  pStringTable = reinterpret_cast<const char *>(m_pStringTable);
115  }
116  else
117  {
118  pStringTable = m_pDynamicStringTable;
119  }
120 
121  String symbolName("(unknown)");
122 
123  size_t symbolSize = 0;
124 
125  // If this is a section header, patch straight to it.
126  if (pSymbols && ST_TYPE(pSymbols[R_SYM(rel.info)].info) == 3)
127  {
128  // Section type - the name will be the name of the section header it
129  // refers to.
130  int shndx = pSymbols[R_SYM(rel.info)].shndx;
131  ElfSectionHeader_t *pReferencedSh = &m_pSectionHeaders[shndx];
132  S = pReferencedSh->addr;
133  symbolSize = pSymbols[R_SYM(rel.info)].size;
134  }
135  else if (pSymbols && R_TYPE(rel.info) != R_X86_64_RELATIVE) // Relative
136  // doesn't need
137  // a symbol!
138  {
139  const char *pStr = pStringTable + pSymbols[R_SYM(rel.info)].name;
140 
141  if (pSymtab == 0)
142  pSymtab = &m_SymbolTable;
143 
144  if (R_TYPE(rel.info) == R_X86_64_COPY)
146  S = pSymtab->lookup(String(pStr), this, policy);
147  if (S == 0)
148  {
149  // Failed to find - fall back to kernel symbol table.
150  S = KernelElf::instance().getSymbolTable()->lookup(
151  String(pStr), this, policy);
152  }
153 
154  if (S == 0 && ST_BIND(pSymbols[R_SYM(rel.info)].info) == 2)
155  {
156  // Weak relocation that couldn't be found, which is OK.
157  S = ~0UL;
158  }
159 
160  if (S == 0)
161  {
162  WARNING(
163  "Relocation failed for symbol \""
164  << pStr << "\" (relocation=" << R_TYPE(rel.info) << ")");
165  WARNING(
166  "Relocation at " << Hex << address << " (offset=" << rel.offset
167  << ")...");
168  }
169 
170  symbolName = pStr;
171  symbolSize = pSymbols[R_SYM(rel.info)].size;
172  }
173 
174  if (S == 0 && (R_TYPE(rel.info) != R_X86_64_RELATIVE))
175  return false;
176  if (S == ~0UL)
177  S = 0; // weak relocation, undefined
178 
179  // Base address
180  uint64_t B = loadBase;
181 
182  uint64_t *pResult = reinterpret_cast<uint64_t *>(address);
183  uint64_t result = *pResult;
184 
185  uint64_t tmp = 0;
186  uint8_t r_type = R_TYPE(rel.info);
187 
188  VERBOSE_NOTICE("");
189  VERBOSE_NOTICE("Relocation for " << symbolName);
190  VERBOSE_NOTICE("A=" << Hex << A << " B=" << B << " S=" << S << " P=" << P);
191 
192  switch (r_type)
193  {
194  case R_X86_64_NONE:
195  VERBOSE_NOTICE("R_X86_64_NONE");
196  break;
197  case R_X86_64_64:
198  VERBOSE_NOTICE("R_X86_64_64");
199  result = S + A;
200  break;
201  case R_X86_64_PC32:
202  VERBOSE_NOTICE("R_X86_64_PC32");
203  result = (result & 0xFFFFFFFF00000000) | ((S + A - P) & 0xFFFFFFFF);
204  break;
205  case R_X86_64_COPY:
206  VERBOSE_NOTICE("R_X86_64_COPY");
207  if (!S)
208  {
209  ERROR("Cannot perform a R_X86_64_COPY relocation for a weak "
210  "symbol.");
211  return false;
212  }
213 
214  NOTICE("Copy needed, " << symbolSize << " bytes wanted");
215  result = *reinterpret_cast<uintptr_t *>(S);
216  break;
217  case R_X86_64_JUMP_SLOT:
218  case R_X86_64_GLOB_DAT:
219  VERBOSE_NOTICE("R_X86_64_JUMP_SLOT/R_X86_64_GLOB_DAT");
220 
221  result = S;
222  break;
223  case R_X86_64_RELATIVE:
224  VERBOSE_NOTICE("R_X86_64_RELATIVE");
225  result = B + A;
226  break;
227  case R_X86_64_32:
228  case R_X86_64_32S:
229  VERBOSE_NOTICE("R_X86_64_32(S)");
230  tmp = S + A;
231 
232  if ((r_type == R_X86_64_32) && ((tmp & 0xFFFFFFFF00000000ULL) != 0))
233  {
234  ERROR(
235  "Relocation for symbol '" << symbolName
236  << "' will be truncated to fit!");
237  }
238  else if (r_type == R_X86_64_32S)
239  {
240  // did this sign extend?
241  uint64_t sign = (tmp & 0x80000000ULL) >> 31ULL;
242  uint64_t top = (tmp & 0xFFFFFFFF00000000ULL) >> 32ULL;
243  if ((sign * 0xFFFFFFFFUL) != top)
244  {
245  ERROR(
246  "Relocation for symbol '"
247  << symbolName
248  << "' will be truncated to fit (sign-extension was "
249  "incorrect)");
250  }
251  }
252 
253  result = (result & 0xFFFFFFFF00000000) | (tmp & 0xFFFFFFFFUL);
254  break;
255  default:
256  ERROR(
257  "Relocation not supported for symbol \""
258  << symbolName << "\": " << Dec << R_TYPE(rel.info));
259  }
260 
261  VERBOSE_NOTICE("result=" << Hex << result);
262  VERBOSE_NOTICE("");
263 
264  // Write back the result.
265  *pResult = result;
266  return true;
267 }
uintptr_t EXPORTED_PUBLIC lookup(const HashedStringView &name, Elf *pElf, Policy policy=LocalFirst, Binding *pBinding=0)
Definition: SymbolTable.cc:126
Definition: String.h:49
static KernelElf & instance()
Definition: KernelElf.h:129
Definition: elf.h:84
#define WARNING(text)
Definition: Log.h:78
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
bool applyRelocation(ElfRel_t rel, ElfSectionHeader_t *pSh, SymbolTable *pSymtab=0, uintptr_t loadBase=0, SymbolTable::Policy policy=SymbolTable::LocalFirst)
#define ERROR(text)
Definition: Log.h:82
Definition: Log.h:138