1#pragma once
2
3#include <elf.h>
4#include <glob.h>
5
6#include <filesystem>
7#include <fstream>
8#include <map>
9#include <memory>
10#include <optional>
11#include <queue>
12#include <set>
13#include <tuple>
14
15#include "utils.h"
16
17class ELFBinary {
18public:
19 ELFBinary(const std::filesystem::path path);
20 ELFBinary(const ELFBinary&) = default;
21
22 const std::string filename() const { return path_.filename().string(); }
23 const Elf64_Addr GetSymbolAddr(const size_t symbol_index);
24 const std::vector<std::string> neededs() const { return neededs_; }
25 const std::vector<Elf64_Sym>& symtabs() const { return symtabs_; }
26 const std::optional<std::filesystem::path> runpath() const { return runpath_; }
27 const std::optional<std::filesystem::path> rpath() const { return rpath_; }
28 const bool has_tls() const { return has_tls_; }
29 const Elf64_Phdr file_tls() const { return file_tls_; }
30 const Elf64_Addr base_addr() const { return base_addr_; }
31 const Elf64_Addr end_addr() const { return end_addr_; }
32 const std::filesystem::path path() const { return path_; }
33 const std::vector<Elf64_Rela> relas() const { return relas_; }
34 const std::vector<Elf64_Rela> pltrelas() const { return pltrelas_; }
35 const Elf64_Xword init() const { return init_; }
36 const Elf64_Xword fini() const { return fini_; }
37 const Elf64_Xword init_arraysz() const { return init_arraysz_; }
38 const Elf64_Xword init_array() const { return init_array_; }
39 const Elf64_Xword fini_arraysz() const { return fini_arraysz_; }
40 const Elf64_Xword fini_array() const { return fini_array_; }
41 const char* strtab() const { return strtab_; }
42 const Elf64_Ehdr ehdr() const { return ehdr_; }
43
44 Elf64_Addr Load(Elf64_Addr base_addr, std::shared_ptr<std::ofstream> map_file);
45 void ParseDynamic();
46
47private:
48 // To generate copy constructor, we cannot make member variables const.
49 std::filesystem::path path_;
50 char* file_base_addr_;
51 Elf64_Addr base_addr_ = 0;
52 Elf64_Addr end_addr_ = 0;
53 Elf64_Ehdr ehdr_;
54 Elf64_Rela* rela_ = nullptr;
55 Elf64_Rela* jmprel_ = nullptr;
56 std::vector<Elf64_Rela> relas_;
57 std::vector<Elf64_Rela> pltrelas_;
58 Elf64_Xword relasz_ = 0;
59 Elf64_Xword relacount_ = 0; // What's this?
60 Elf64_Xword relaent_ = 0;
61 Elf64_Xword pltrelsz_ = 0;
62 Elf64_Xword pltrel_ = 0;
63 Elf64_Xword pltrelent_ = 0;
64 Elf64_Xword init_ = 0;
65 Elf64_Xword fini_ = 0;
66 Elf64_Xword init_arraysz_ = 0;
67 Elf64_Xword init_array_ = 0;
68 Elf64_Xword fini_arraysz_ = 0;
69 Elf64_Xword fini_array_ = 0;
70 Elf64_Sym* symtab_ = nullptr;
71 std::vector<Elf64_Sym> symtabs_;
72 Elf64_Xword syment_ = 0;
73 std::vector<Elf64_Phdr> file_phdrs_;
74 Elf64_Phdr file_dynamic_ = {.p_filesz = 0};
75 bool has_tls_ = false;
76 Elf64_Phdr file_tls_;
77 std::vector<std::string> neededs_;
78 std::optional<std::filesystem::path> runpath_ = std::nullopt;
79 std::optional<std::filesystem::path> rpath_ = std::nullopt;
80 char* strtab_ = nullptr;
81 Elf64_Xword strsz_ = 0;
82};
83
84class DynLoader {
85public:
86 DynLoader(const std::filesystem::path& main_path, const std::vector<std::string>& args, const std::vector<std::string>& envs);
87 // The main function
88 void Run();
89
90 void LoadDependingLibs(const std::filesystem::path& root_path);
91 void Relocate();
92 std::optional<std::pair<size_t, size_t>> SearchSym(const std::string& name, bool skip_main);
93 std::vector<ELFBinary> binaries_;
94
95private:
96 std::filesystem::path main_path_;
97 std::shared_ptr<std::ofstream> map_file_;
98 const std::vector<std::string> args_;
99 const std::vector<std::string> envs_;
100 Elf64_Addr next_base_addr_;
101 std::set<std::string> loaded_;
102 std::map<std::filesystem::path, bool> relocated_;
103
104 void Execute(std::vector<std::string> args, std::vector<std::string> envs);
105 void __attribute__((noinline)) ExecuteCore(uint64_t* stack, size_t stack_num, uint64_t entry);
106 Elf64_Addr TLSSymOffset(const std::string& name);
107};
108
109void InitializeDynLoader(const std::filesystem::path& main_path, const std::vector<std::string>& envs,
110 const std::vector<std::string>& argv);
111
112std::shared_ptr<DynLoader> GetDynLoader();
113
114std::filesystem::path FindLibrary(std::string library_name, std::optional<std::filesystem::path> runpath,
115 std::optional<std::filesystem::path> rpath);
116