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/linker/Elf.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/linker/KernelElf.h"
23 #include "pedigree/kernel/utilities/utility.h"
24 
25 namespace __pedigree_hosted
26 {
27 #include <dlfcn.h>
28 }
29 
30 #define R_X86_64_NONE 0
31 #define R_X86_64_64 1
32 #define R_X86_64_PC32 2
33 #define R_X86_64_GOT32 3
34 #define R_X86_64_PLT32 4
35 #define R_X86_64_COPY 5
36 #define R_X86_64_GLOB_DAT 6
37 #define R_X86_64_JUMP_SLOT 7
38 #define R_X86_64_RELATIVE 8
39 #define R_X86_64_GOTPCREL 9
40 #define R_X86_64_32 10
41 #define R_X86_64_32S 11
42 #define R_X86_64_PC64 24
43 #define R_X86_64_GOTOFF64 25
44 #define R_X86_64_GOTPC32 26
45 #define R_X86_64_GOT64 27
46 #define R_X86_64_GOTPCREL64 28
47 #define R_X86_64_GOTPC64 29
48 #define R_X86_64_GOTPLT64 30
49 #define R_X86_64_PLTOFF64 31
50 
51 #define TWO_GIGABYTES 0x80000000ULL
52 
53 static bool
54 checkPc32Displacement(uint64_t S, uint64_t A, uint64_t P, uint64_t &diff)
55 {
56  if (abs_difference(S + A, P) >= 0x80000000ULL)
57  {
58  return false;
59  }
60 
61  diff = (((S + A) - P) & 0xFFFFFFFFULL);
62  return true;
63 }
64 
66  ElfRel_t rel, ElfSectionHeader_t *pSh, SymbolTable *pSymtab,
67  uintptr_t loadBase, SymbolTable::Policy policy)
68 {
69  return false;
70 }
71 
73  ElfRela_t rel, ElfSectionHeader_t *pSh, SymbolTable *pSymtab,
74  uintptr_t loadBase, SymbolTable::Policy policy)
75 {
76  // Section not loaded?
77  if (pSh && pSh->addr == 0)
78  return true; // Not a fatal error.
79 
80  // Avoid NONE relocations.
81  if (R_TYPE(rel.info) == R_X86_64_NONE)
82  return true;
83 
84  // Get the address of the unit to be relocated.
85  uint64_t address = ((pSh) ? pSh->addr : loadBase) + rel.offset;
86 
87  // Addend is the value currently at the given address.
88  uint64_t 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  const char *pStringTable = 0;
102  if (!m_pDynamicStringTable)
103  pStringTable = reinterpret_cast<const char *>(m_pStringTable);
104  else
105  pStringTable = m_pDynamicStringTable;
106 
107  String symbolName("(unknown)");
108 
109  // If this is a section header, patch straight to it.
110  if (pSymbols && ST_TYPE(pSymbols[R_SYM(rel.info)].info) == 3)
111  {
112  // Section type - the name will be the name of the section header it
113  // refers to.
114  int shndx = pSymbols[R_SYM(rel.info)].shndx;
115  ElfSectionHeader_t *pSh = &m_pSectionHeaders[shndx];
116  S = pSh->addr;
117  }
118  else if (R_TYPE(rel.info) != R_X86_64_RELATIVE) // Relative doesn't need a
119  // symbol!
120  {
121  const char *pStr = pStringTable + pSymbols[R_SYM(rel.info)].name;
122 
123  if (pSymtab == 0)
124  pSymtab = KernelElf::instance().getSymbolTable();
125 
126  if (R_TYPE(rel.info) == R_X86_64_COPY)
128  S = pSymtab->lookup(String(pStr), this, policy);
129 
130  if (S == 0)
131  {
132  // Try to find via dlsym (in case we're needing a libc symbol).
133  void *pSym = __pedigree_hosted::dlsym(RTLD_DEFAULT, pStr);
134  if (pSym)
135  {
136  S = reinterpret_cast<uint64_t>(pSym);
137  // WARNING("Internal relocation failed for symbol \"" << pStr <<
138  // "\" - using a dlsym lookup."); WARNING(" = " << Hex << S);
139  }
140  else
141  {
142  WARNING(
143  "Relocation failed for symbol \""
144  << pStr << "\" (relocation=" << R_TYPE(rel.info) << ")");
145  WARNING(
146  "Relocation at " << address << " (offset=" << rel.offset
147  << ")...");
148  }
149  }
150  // This is a weak relocation, but it was undefined.
151  else if (S == ~0UL)
152  WARNING("Weak relocation == 0 [undefined] for \"" << pStr << "\".");
153 
154  symbolName = pStr;
155  }
156 
157  if (S == 0 && (R_TYPE(rel.info) != R_X86_64_RELATIVE))
158  return false;
159  if (S == ~0UL)
160  S = 0; // undefined
161 
162  // Base address
163  uint64_t B = loadBase;
164 
165  uint64_t *pResult = reinterpret_cast<uint64_t *>(address);
166  uint64_t result = *pResult;
167 
168  switch (R_TYPE(rel.info))
169  {
170  case R_X86_64_NONE:
171  break;
172  case R_X86_64_64:
173  result = S + A;
174  break;
175  case R_X86_64_PC32:
176  {
177  uint64_t diff = 0;
178  if (!checkPc32Displacement(S, A, P, diff))
179  {
180  ERROR("PC32 relocation with >2GB displacement - not possible.");
181  ERROR("Symbol is " << symbolName << " at " << Hex << S);
182  return false;
183  }
184  result = (result & 0xFFFFFFFF00000000ULL) | diff;
185  }
186  break;
187  case R_X86_64_PC64:
188  result = (S + A) - P;
189  break;
190  case R_X86_64_COPY:
191  result = *reinterpret_cast<uintptr_t *>(S);
192  break;
193  case R_X86_64_JUMP_SLOT:
194  case R_X86_64_GLOB_DAT:
195  result = S;
196  break;
197  case R_X86_64_RELATIVE:
198  result = B + A;
199  break;
200  case R_X86_64_32:
201  case R_X86_64_32S:
202  result =
203  (result & 0xFFFFFFFF00000000ULL) | ((S + A) & 0xFFFFFFFFULL);
204  break;
205  default:
206  ERROR(
207  "Relocation not supported for symbol \""
208  << symbolName << "\": " << Dec << R_TYPE(rel.info));
209  }
210 
211  // Write back the result.
212  *pResult = result;
213  return true;
214 }
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
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