Serenity Operating System
1/*
2 * Copyright (c) 2019-2020, Andrew Kaster <andrewdkaster@gmail.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/Assertions.h>
30#include <LibBareMetal/Memory/VirtualAddress.h>
31#include <LibELF/exec_elf.h>
32
33class ELFDynamicObject {
34public:
35 explicit ELFDynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_address);
36 ~ELFDynamicObject();
37 void dump() const;
38
39 class DynamicEntry;
40 class Section;
41 class RelocationSection;
42 class Symbol;
43 class Relocation;
44 class HashSection;
45
46 class DynamicEntry {
47 public:
48 DynamicEntry(const Elf32_Dyn& dyn)
49 : m_dyn(dyn)
50 {
51 }
52
53 ~DynamicEntry() {}
54
55 Elf32_Sword tag() const { return m_dyn.d_tag; }
56 Elf32_Addr ptr() const { return m_dyn.d_un.d_ptr; }
57 Elf32_Word val() const { return m_dyn.d_un.d_val; }
58
59 private:
60 const Elf32_Dyn& m_dyn;
61 };
62
63 class Symbol {
64 public:
65 Symbol(const ELFDynamicObject& dynamic, unsigned index, const Elf32_Sym& sym)
66 : m_dynamic(dynamic)
67 , m_sym(sym)
68 , m_index(index)
69 {
70 }
71
72 ~Symbol() {}
73
74 const char* name() const { return m_dynamic.symbol_string_table_string(m_sym.st_name); }
75 unsigned section_index() const { return m_sym.st_shndx; }
76 unsigned value() const { return m_sym.st_value; }
77 unsigned size() const { return m_sym.st_size; }
78 unsigned index() const { return m_index; }
79 unsigned type() const { return ELF32_ST_TYPE(m_sym.st_info); }
80 unsigned bind() const { return ELF32_ST_BIND(m_sym.st_info); }
81 bool is_undefined() const { return this == &m_dynamic.the_undefined_symbol(); }
82 VirtualAddress address() const { return m_dynamic.base_address().offset(value()); }
83
84 private:
85 const ELFDynamicObject& m_dynamic;
86 const Elf32_Sym& m_sym;
87 const unsigned m_index;
88 };
89
90 class Section {
91 public:
92 Section(const ELFDynamicObject& dynamic, unsigned section_offset, unsigned section_size_bytes, unsigned entry_size, const char* name)
93 : m_dynamic(dynamic)
94 , m_section_offset(section_offset)
95 , m_section_size_bytes(section_size_bytes)
96 , m_entry_size(entry_size)
97 , m_name(name)
98 {
99 }
100 ~Section() {}
101
102 const char* name() const { return m_name; }
103 unsigned offset() const { return m_section_offset; }
104 unsigned size() const { return m_section_size_bytes; }
105 unsigned entry_size() const { return m_entry_size; }
106 unsigned entry_count() const { return !entry_size() ? 0 : size() / entry_size(); }
107 VirtualAddress address() const { return m_dynamic.base_address().offset(m_section_offset); }
108
109 protected:
110 friend class RelocationSection;
111 friend class HashSection;
112 const ELFDynamicObject& m_dynamic;
113 unsigned m_section_offset;
114 unsigned m_section_size_bytes;
115 unsigned m_entry_size;
116 const char* m_name { nullptr };
117 };
118
119 class RelocationSection : public Section {
120 public:
121 RelocationSection(const Section& section)
122 : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name)
123 {
124 }
125 unsigned relocation_count() const { return entry_count(); }
126 const Relocation relocation(unsigned index) const;
127 const Relocation relocation_at_offset(unsigned offset) const;
128 template<typename F>
129 void for_each_relocation(F) const;
130 };
131
132 class Relocation {
133 public:
134 Relocation(const ELFDynamicObject& dynamic, const Elf32_Rel& rel, unsigned offset_in_section)
135 : m_dynamic(dynamic)
136 , m_rel(rel)
137 , m_offset_in_section(offset_in_section)
138 {
139 }
140
141 ~Relocation() {}
142
143 unsigned offset_in_section() const { return m_offset_in_section; }
144 unsigned offset() const { return m_rel.r_offset; }
145 unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); }
146 unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); }
147 const Symbol symbol() const { return m_dynamic.symbol(symbol_index()); }
148 VirtualAddress address() const { return m_dynamic.base_address().offset(offset()); }
149
150 private:
151 const ELFDynamicObject& m_dynamic;
152 const Elf32_Rel& m_rel;
153 const unsigned m_offset_in_section;
154 };
155
156 enum class HashType {
157 SYSV,
158 GNU
159 };
160
161 class HashSection : public Section {
162 public:
163 HashSection(const Section& section, HashType hash_type = HashType::SYSV)
164 : Section(section.m_dynamic, section.m_section_offset, section.m_section_size_bytes, section.m_entry_size, section.m_name)
165 {
166 switch (hash_type) {
167 case HashType::SYSV:
168 m_hash_function = &HashSection::calculate_elf_hash;
169 break;
170 case HashType::GNU:
171 m_hash_function = &HashSection::calculate_gnu_hash;
172 break;
173 default:
174 ASSERT_NOT_REACHED();
175 break;
176 }
177 }
178
179 const Symbol lookup_symbol(const char*) const;
180
181 private:
182 u32 calculate_elf_hash(const char* name) const;
183 u32 calculate_gnu_hash(const char* name) const;
184
185 typedef u32 (HashSection::*HashFunction)(const char*) const;
186 HashFunction m_hash_function;
187 };
188
189 unsigned symbol_count() const { return m_symbol_count; }
190
191 const Symbol symbol(unsigned) const;
192 const Symbol& the_undefined_symbol() const { return m_the_undefined_symbol; }
193
194 const Section init_section() const;
195 const Section fini_section() const;
196 const Section init_array_section() const;
197 const Section fini_array_section() const;
198
199 const HashSection hash_section() const;
200
201 const RelocationSection relocation_section() const;
202 const RelocationSection plt_relocation_section() const;
203
204 bool should_process_origin() const { return m_dt_flags & DF_ORIGIN; }
205 bool requires_symbolic_symbol_resolution() const { return m_dt_flags & DF_SYMBOLIC; }
206 // Text relocations meaning: we need to edit the .text section which is normally mapped PROT_READ
207 bool has_text_relocations() const { return m_dt_flags & DF_TEXTREL; }
208 bool must_bind_now() const { return m_dt_flags & DF_BIND_NOW; }
209 bool has_static_thread_local_storage() const { return m_dt_flags & DF_STATIC_TLS; }
210
211 VirtualAddress plt_got_base_address() const { return m_base_address.offset(m_procedure_linkage_table_offset); }
212 VirtualAddress base_address() const { return m_base_address; }
213
214private:
215 const char* symbol_string_table_string(Elf32_Word) const;
216 void parse();
217
218 template<typename F>
219 void for_each_symbol(F) const;
220
221 template<typename F>
222 void for_each_dynamic_entry(F) const;
223
224 VirtualAddress m_base_address;
225 VirtualAddress m_dynamic_address;
226 Symbol m_the_undefined_symbol { *this, 0, {} };
227
228 unsigned m_symbol_count { 0 };
229
230 // Begin Section information collected from DT_* entries
231 FlatPtr m_init_offset { 0 };
232 FlatPtr m_fini_offset { 0 };
233
234 FlatPtr m_init_array_offset { 0 };
235 size_t m_init_array_size { 0 };
236 FlatPtr m_fini_array_offset { 0 };
237 size_t m_fini_array_size { 0 };
238
239 FlatPtr m_hash_table_offset { 0 };
240
241 FlatPtr m_string_table_offset { 0 };
242 size_t m_size_of_string_table { 0 };
243 FlatPtr m_symbol_table_offset { 0 };
244 size_t m_size_of_symbol_table_entry { 0 };
245
246 Elf32_Sword m_procedure_linkage_table_relocation_type { -1 };
247 FlatPtr m_plt_relocation_offset_location { 0 }; // offset of PLT relocations, at end of relocations
248 size_t m_size_of_plt_relocation_entry_list { 0 };
249 FlatPtr m_procedure_linkage_table_offset { 0 };
250
251 // NOTE: We'll only ever either RELA or REL entries, not both (thank god)
252 // NOTE: The x86 ABI will only ever genrerate REL entries.
253 size_t m_number_of_relocations { 0 };
254 size_t m_size_of_relocation_entry { 0 };
255 size_t m_size_of_relocation_table { 0 };
256 FlatPtr m_relocation_table_offset { 0 };
257
258 // DT_FLAGS
259 Elf32_Word m_dt_flags { 0 };
260 // End Section information from DT_* entries
261};
262
263template<typename F>
264inline void ELFDynamicObject::RelocationSection::for_each_relocation(F func) const
265{
266 for (unsigned i = 0; i < relocation_count(); ++i) {
267 if (func(relocation(i)) == IterationDecision::Break)
268 break;
269 }
270}
271
272template<typename F>
273inline void ELFDynamicObject::for_each_symbol(F func) const
274{
275 for (unsigned i = 0; i < symbol_count(); ++i) {
276 if (func(symbol(i)) == IterationDecision::Break)
277 break;
278 }
279}
280
281template<typename F>
282inline void ELFDynamicObject::for_each_dynamic_entry(F func) const
283{
284 auto* dyns = reinterpret_cast<const Elf32_Dyn*>(m_dynamic_address.as_ptr());
285 for (unsigned i = 0;; ++i) {
286 auto&& dyn = DynamicEntry(dyns[i]);
287 if (dyn.tag() == DT_NULL)
288 break;
289 if (func(dyn) == IterationDecision::Break)
290 break;
291 }
292}