summaryrefslogtreecommitdiff
path: root/Libraries/LibELF/ELFDynamicObject.h
diff options
context:
space:
mode:
authorAndrew Kaster <andrewdkaster@gmail.com>2019-12-31 16:45:50 -0500
committerAndreas Kling <awesomekling@gmail.com>2020-01-01 17:48:41 +0100
commita18b37880e6feb1f89ebabdf6a826abdf6f0caf6 (patch)
tree9cbe14fffadc20c765225366a506f05fdc9738fa /Libraries/LibELF/ELFDynamicObject.h
parentb6590b7f83ebfe8937a32f0cfef9e002aadb70de (diff)
downloadserenity-a18b37880e6feb1f89ebabdf6a826abdf6f0caf6.zip
LibELF: Add ELFDynamicObject to dynamically load libaries
This patch also adds some missing relocation defines to exec_elf.h, and a few helper classes/methods to ELFImage so that we can use it for our dynamically loaded libs and not just main program images from the kernel :)
Diffstat (limited to 'Libraries/LibELF/ELFDynamicObject.h')
-rw-r--r--Libraries/LibELF/ELFDynamicObject.h122
1 files changed, 122 insertions, 0 deletions
diff --git a/Libraries/LibELF/ELFDynamicObject.h b/Libraries/LibELF/ELFDynamicObject.h
new file mode 100644
index 0000000000..98f09e9b1a
--- /dev/null
+++ b/Libraries/LibELF/ELFDynamicObject.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#include <LibELF/ELFImage.h>
+#include <LibELF/exec_elf.h>
+#include <dlfcn.h>
+#include <mman.h>
+
+#include <AK/OwnPtr.h>
+#include <AK/RefCounted.h>
+#include <AK/String.h>
+
+#define ALIGN_ROUND_UP(x, align) ((((size_t)(x)) + align - 1) & (~(align - 1)))
+
+class ELFDynamicObject : public RefCounted<ELFDynamicObject> {
+public:
+ static NonnullRefPtr<ELFDynamicObject> construct(const char* filename, int fd, size_t file_size);
+
+ ~ELFDynamicObject();
+
+ bool is_valid() const { return m_valid; }
+
+ // FIXME: How can we resolve all of the symbols without having the original elf image for our process?
+ // RTLD_LAZY only at first probably... though variables ('objects') need resolved at load time every time
+ bool load(unsigned flags);
+
+ // Intended for use by dlsym or other internal methods
+ void* symbol_for_name(const char*);
+
+ void dump();
+
+private:
+ class ProgramHeaderRegion {
+ public:
+ ProgramHeaderRegion(const Elf32_Phdr& header)
+ : m_program_header(header)
+ {
+ }
+
+ VirtualAddress load_address() const { return m_load_address; }
+ VirtualAddress base_address() const { return m_image_base_address; }
+
+ void set_load_address(VirtualAddress addr) { m_load_address = addr; }
+ void set_base_address(VirtualAddress addr) { m_image_base_address = addr; }
+
+ // Information from ELF Program header
+ u32 type() const { return m_program_header.p_type; }
+ u32 flags() const { return m_program_header.p_flags; }
+ u32 offset() const { return m_program_header.p_offset; }
+ VirtualAddress desired_load_address() const { return VirtualAddress(m_program_header.p_vaddr); }
+ u32 size_in_memory() const { return m_program_header.p_memsz; }
+ u32 size_in_image() const { return m_program_header.p_filesz; }
+ u32 alignment() const { return m_program_header.p_align; }
+ u32 mmap_prot() const;
+ bool is_readable() const { return flags() & PF_R; }
+ bool is_writable() const { return flags() & PF_W; }
+ bool is_executable() const { return flags() & PF_X; }
+ bool is_tls_template() const { return type() == PT_TLS; }
+ bool is_load() const { return type() == PT_LOAD; }
+ bool is_dynamic() const { return type() == PT_DYNAMIC; }
+
+ u32 required_load_size() { return ALIGN_ROUND_UP(m_program_header.p_memsz, m_program_header.p_align); }
+
+ private:
+ Elf32_Phdr m_program_header; // Explictly a copy of the PHDR in the image
+ VirtualAddress m_load_address { 0 };
+ VirtualAddress m_image_base_address { 0 };
+ };
+
+ explicit ELFDynamicObject(const char* filename, int fd, size_t file_size);
+
+ String m_filename;
+ size_t m_file_size { 0 };
+ int m_image_fd { -1 };
+ void* m_file_mapping { nullptr };
+ bool m_valid { false };
+
+ OwnPtr<ELFImage> m_image;
+
+ void parse_dynamic_section();
+ void do_relocations();
+
+ static void patch_plt_entry(u32 got_offset, void* dso_got_tag);
+
+ Vector<ProgramHeaderRegion> m_program_header_regions;
+ ProgramHeaderRegion* m_text_region { nullptr };
+ ProgramHeaderRegion* m_data_region { nullptr };
+ ProgramHeaderRegion* m_tls_region { nullptr };
+
+ // Begin Section information collected from DT_* entries
+ uintptr_t m_init_offset { 0 };
+ uintptr_t m_fini_offset { 0 };
+
+ uintptr_t m_init_array_offset { 0 };
+ size_t m_init_array_size { 0 };
+
+ uintptr_t m_hash_table_offset { 0 };
+
+ uintptr_t m_string_table_offset { 0 };
+ uintptr_t m_symbol_table_offset { 0 };
+ size_t m_size_of_string_table { 0 };
+ size_t m_size_of_symbol_table_entry { 0 };
+
+ Elf32_Sword m_procedure_linkage_table_relocation_type { -1 };
+ uintptr_t m_plt_relocation_offset_location { 0 }; // offset of PLT relocations, at end of relocations
+ size_t m_size_of_plt_relocation_entry_list { 0 };
+ uintptr_t m_procedure_linkage_table_offset { 0 };
+
+ // NOTE: We'll only ever either RELA or REL entries, not both (thank god)
+ size_t m_number_of_relocations { 0 };
+ size_t m_size_of_relocation_entry { 0 };
+ size_t m_size_of_relocation_table { 0 };
+ uintptr_t m_relocation_table_offset { 0 };
+
+ // DT_FLAGS
+ bool m_should_process_origin = false;
+ bool m_requires_symbolic_symbol_resolution = false;
+ // Text relocations meaning: we need to edit the .text section which is normally mapped PROT_READ
+ bool m_has_text_relocations = false;
+ bool m_must_bind_now = false; // FIXME: control with an environment var as well?
+ bool m_has_static_thread_local_storage = false;
+ // End Section information from DT_* entries
+};