The Pedigree Project 0.1
core/processor/armv7/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 ArmRelocation {
7 R_ARM_NONE = 0,
8 R_ARM_ABS32 = 2,
9 R_ARM_REL32 = 3,
10 R_ARM_COPY = 20,
11 R_ARM_GLOB_DAT = 21,
12 R_ARM_JUMP_SLOT = 22,
13 R_ARM_RELATIVE = 23,
14};
15}
16
18 uintptr_t loadBase, SymbolTable::Policy policy,
19 uintptr_t destinationAddress, uintptr_t destinationEnd) {
20 if ((section && !section->addr) || R_TYPE(rel.info) == R_ARM_NONE) {
21 return true;
22 }
23 if (!loadBase && section) {
24 loadBase = section->addr - section->offset;
25 }
26 if (!loadBase) {
27 ERROR("ARM relocation has no load base");
28 return false;
29 }
30 const uintptr_t place = loadBase + rel.offset;
31 const uintptr_t destination = destinationAddress ? destinationAddress : place;
32 if (destinationEnd && (destination > destinationEnd || destinationEnd - destination < 4)) {
33 ERROR("ARM REL relocation crosses the demand-page staging boundary");
34 return false;
35 }
36 const intptr_t addend = *reinterpret_cast<const int32_t*>(destination);
37 return applyArmRelocation(R_TYPE(rel.info), R_SYM(rel.info), rel.offset, addend, section, symbols,
38 loadBase, policy, destinationAddress, destinationEnd);
39}
40
41bool Elf::applyRelocation(ElfRela_t rel, ElfSectionHeader_t* section, SymbolTable* symbols,
42 uintptr_t loadBase, SymbolTable::Policy policy,
43 uintptr_t destinationAddress, uintptr_t destinationEnd) {
44 return applyArmRelocation(R_TYPE(rel.info), R_SYM(rel.info), rel.offset, rel.addend, section,
45 symbols, loadBase, policy, destinationAddress, destinationEnd);
46}
47
48bool Elf::applyArmRelocation(Elf_Word type, Elf_Word symbolIndex, uintptr_t offset, intptr_t addend,
49 ElfSectionHeader_t* section, SymbolTable* symbols, uintptr_t loadBase,
50 SymbolTable::Policy policy, uintptr_t destinationAddress,
51 uintptr_t destinationEnd) {
52 if (section && !section->addr) {
53 return true;
54 }
55 if (type == R_ARM_NONE) {
56 return true;
57 }
58 if (!loadBase) {
59 loadBase = section ? section->addr - section->offset : 0;
60 if (!loadBase) {
61 ERROR("ARM relocation has no load base");
62 return false;
63 }
64 }
65
66 const uintptr_t place = loadBase + offset;
67 const uintptr_t destination = destinationAddress ? destinationAddress : place;
68 ElfSymbol_t* elfSymbols = m_pDynamicSymbolTable ? m_pDynamicSymbolTable : m_pSymbolTable;
69 const char* strings = m_pDynamicStringTable ? m_pDynamicStringTable : m_pStringTable;
70 uintptr_t symbol = 0;
71 size_t symbolSize = 0;
72
73 if (type != R_ARM_RELATIVE) {
74 if (!elfSymbols) {
75 ERROR("ARM relocation has no symbol table");
76 return false;
77 }
78 const ElfSymbol_t& entry = elfSymbols[symbolIndex];
79 symbolSize = entry.size;
80 if (ST_TYPE(entry.info) == 3) {
81 if (!m_pSectionHeaders || entry.shndx >= m_nSectionHeaders) {
82 return false;
83 }
84 symbol = m_pSectionHeaders[entry.shndx].addr;
85 } else {
86 if (!strings) {
87 return false;
88 }
89 const char* name = strings + entry.name;
90 if (type == R_ARM_COPY) {
92 }
93 if (!symbols) {
94 symbols = &m_SymbolTable;
95 }
96 symbol = symbols->lookup(String(name), this, policy);
97 if (!symbol) {
98 symbol = KernelElf::instance().getSymbolTable()->lookup(String(name), this, policy);
99 }
100 if (!symbol && ST_BIND(entry.info) != 2) {
101 WARNING("ARM relocation failed for symbol \"" << name << "\"");
102 return false;
103 }
104 }
105 }
106
107 const size_t writeSize = type == R_ARM_COPY ? symbolSize : sizeof(uint32_t);
108 if (destinationEnd &&
109 (destination > destinationEnd || destinationEnd - destination < writeSize)) {
110 ERROR("ARM relocation crosses the demand-page staging boundary");
111 return false;
112 }
113
114 switch (type) {
115 case R_ARM_ABS32:
116 *reinterpret_cast<uint32_t*>(destination) = symbol + addend;
117 return true;
118 case R_ARM_REL32:
119 *reinterpret_cast<uint32_t*>(destination) = symbol + addend - place;
120 return true;
121 case R_ARM_GLOB_DAT:
122 case R_ARM_JUMP_SLOT:
123 *reinterpret_cast<uint32_t*>(destination) = symbol;
124 return true;
125 case R_ARM_RELATIVE:
126 *reinterpret_cast<uint32_t*>(destination) = loadBase + addend;
127 return true;
128 case R_ARM_COPY:
129 if (!symbol) {
130 ERROR("ARM 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 ARM ELF relocation " << Dec << type);
139 return false;
140 }
141}
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