Serenity Operating System
1/*
2 * Copyright (c) 2019-2020, Andrew Kaster <akaster@serenityos.org>
3 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <AK/Assertions.h>
11#include <AK/DeprecatedString.h>
12#include <AK/OwnPtr.h>
13#include <AK/RefCounted.h>
14#include <LibC/elf.h>
15#include <LibELF/DynamicObject.h>
16#include <LibELF/Image.h>
17#include <bits/dlfcn_integration.h>
18#include <sys/mman.h>
19
20namespace ELF {
21
22class LoadedSegment {
23public:
24 LoadedSegment(VirtualAddress address, size_t size)
25 : m_address(address)
26 , m_size(size)
27 {
28 }
29
30 VirtualAddress address() const { return m_address; }
31 size_t size() const { return m_size; }
32
33private:
34 VirtualAddress m_address;
35 size_t m_size;
36};
37
38enum class ShouldInitializeWeak {
39 Yes,
40 No
41};
42
43class DynamicLoader : public RefCounted<DynamicLoader> {
44public:
45 static Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> try_create(int fd, DeprecatedString filepath);
46 ~DynamicLoader();
47
48 DeprecatedString const& filepath() const { return m_filepath; }
49
50 bool is_valid() const { return m_valid; }
51
52 // Load a full ELF image from file into the current process and create an DynamicObject
53 // from the SHT_DYNAMIC in the file.
54 // Note that the DynamicObject will not be linked yet. Callers are responsible for calling link() to finish it.
55 RefPtr<DynamicObject> map();
56
57 bool link(unsigned flags);
58
59 // Stage 2 of loading: dynamic object loading and primary relocations
60 bool load_stage_2(unsigned flags);
61
62 // Stage 3 of loading: lazy relocations
63 Result<NonnullRefPtr<DynamicObject>, DlErrorMessage> load_stage_3(unsigned flags);
64
65 // Stage 4 of loading: initializers
66 void load_stage_4();
67
68 void set_tls_offset(size_t offset) { m_tls_offset = offset; };
69 size_t tls_size_of_current_object() const { return m_tls_size_of_current_object; }
70 size_t tls_alignment_of_current_object() const { return m_tls_alignment_of_current_object; }
71 size_t tls_offset() const { return m_tls_offset; }
72 const ELF::Image& image() const { return *m_elf_image; }
73
74 template<typename F>
75 void for_each_needed_library(F) const;
76
77 VirtualAddress base_address() const { return m_base_address; }
78 Vector<LoadedSegment> const text_segments() const { return m_text_segments; }
79 bool is_dynamic() const { return image().is_dynamic(); }
80
81 static Optional<DynamicObject::SymbolLookupResult> lookup_symbol(const ELF::DynamicObject::Symbol&);
82 void copy_initial_tls_data_into(ByteBuffer& buffer) const;
83
84 DynamicObject const& dynamic_object() const;
85
86 bool is_fully_relocated() const { return m_fully_relocated; }
87 bool is_fully_initialized() const { return m_fully_initialized; }
88
89private:
90 DynamicLoader(int fd, DeprecatedString filepath, void* file_data, size_t file_size);
91
92 class ProgramHeaderRegion {
93 public:
94 void set_program_header(const ElfW(Phdr) & header) { m_program_header = header; }
95
96 // Information from ELF Program header
97 u32 type() const { return m_program_header.p_type; }
98 u32 flags() const { return m_program_header.p_flags; }
99 u32 offset() const { return m_program_header.p_offset; }
100 VirtualAddress desired_load_address() const { return VirtualAddress(m_program_header.p_vaddr); }
101 u32 size_in_memory() const { return m_program_header.p_memsz; }
102 u32 size_in_image() const { return m_program_header.p_filesz; }
103 u32 alignment() const { return m_program_header.p_align; }
104 bool is_readable() const { return flags() & PF_R; }
105 bool is_writable() const { return flags() & PF_W; }
106 bool is_executable() const { return flags() & PF_X; }
107 bool is_tls_template() const { return type() == PT_TLS; }
108 bool is_load() const { return type() == PT_LOAD; }
109 bool is_dynamic() const { return type() == PT_DYNAMIC; }
110 bool is_relro() const { return type() == PT_GNU_RELRO; }
111
112 private:
113 ElfW(Phdr) m_program_header; // Explicitly a copy of the PHDR in the image
114 };
115
116 // Stage 1
117 void load_program_headers();
118
119 // Stage 2
120 void do_main_relocations();
121
122 // Stage 3
123 void do_lazy_relocations();
124 void setup_plt_trampoline();
125
126 // Stage 4
127 void call_object_init_functions();
128
129 bool validate();
130
131 enum class RelocationResult : uint8_t {
132 Failed = 0,
133 Success = 1,
134 ResolveLater = 2,
135 };
136 RelocationResult do_relocation(DynamicObject::Relocation const&, ShouldInitializeWeak should_initialize_weak);
137 void do_relr_relocations();
138 void find_tls_size_and_alignment();
139
140 DeprecatedString m_filepath;
141 size_t m_file_size { 0 };
142 int m_image_fd { -1 };
143 void* m_file_data { nullptr };
144 OwnPtr<ELF::Image> m_elf_image;
145 bool m_valid { true };
146
147 RefPtr<DynamicObject> m_dynamic_object;
148
149 VirtualAddress m_base_address;
150 Vector<LoadedSegment> m_text_segments;
151
152 VirtualAddress m_relro_segment_address;
153 size_t m_relro_segment_size { 0 };
154
155 VirtualAddress m_dynamic_section_address;
156
157 ssize_t m_tls_offset { 0 };
158 size_t m_tls_size_of_current_object { 0 };
159 size_t m_tls_alignment_of_current_object { 0 };
160
161 Vector<DynamicObject::Relocation> m_unresolved_relocations;
162
163 mutable RefPtr<DynamicObject> m_cached_dynamic_object;
164
165 bool m_fully_relocated { false };
166 bool m_fully_initialized { false };
167};
168
169template<typename F>
170void DynamicLoader::for_each_needed_library(F func) const
171{
172 dynamic_object().for_each_needed_library(move(func));
173}
174
175} // end namespace ELF