main.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * Copyright (c) 2020, Itamar S. <itamar8910@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. #include <AK/HashMap.h>
  27. #include <AK/HashTable.h>
  28. #include <AK/LexicalPath.h>
  29. #include <AK/LogStream.h>
  30. #include <AK/ScopeGuard.h>
  31. #include <LibC/mman.h>
  32. #include <LibC/stdio.h>
  33. #include <LibC/sys/internals.h>
  34. #include <LibC/unistd.h>
  35. #include <LibCore/File.h>
  36. #include <LibELF/AuxiliaryVector.h>
  37. #include <LibELF/DynamicLoader.h>
  38. #include <LibELF/DynamicObject.h>
  39. #include <LibELF/Image.h>
  40. #include <LibELF/Loader.h>
  41. #include <LibELF/exec_elf.h>
  42. #include <dlfcn.h>
  43. #include <string.h>
  44. #include <sys/stat.h>
  45. #include <sys/types.h>
  46. // #define DYNAMIC_LOAD_VERBOSE
  47. #ifdef DYNAMIC_LOAD_VERBOSE
  48. # define VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__)
  49. #else
  50. # define VERBOSE(fmt, ...) \
  51. do { \
  52. } while (0)
  53. #endif
  54. #define TLS_VERBOSE(fmt, ...) dbgprintf(fmt, ##__VA_ARGS__)
  55. char* __static_environ[] = { nullptr }; // We don't get the environment without some libc workarounds..
  56. static HashMap<String, NonnullRefPtr<ELF::DynamicLoader>> g_loaders;
  57. static HashMap<String, NonnullRefPtr<ELF::DynamicObject>> g_loaded_objects;
  58. static size_t g_current_tls_offset = 0;
  59. static size_t g_total_tls_size = 0;
  60. static char** g_envp = nullptr;
  61. static void init_libc()
  62. {
  63. environ = __static_environ;
  64. __environ_is_malloced = false;
  65. __stdio_is_initialized = false;
  66. __malloc_init();
  67. }
  68. static void perform_self_relocations(auxv_t* auxvp)
  69. {
  70. // We need to relocate ourselves.
  71. // (these relocations seem to be generated because of our vtables)
  72. FlatPtr base_address = 0;
  73. bool found_base_address = false;
  74. for (; auxvp->a_type != AT_NULL; ++auxvp) {
  75. if (auxvp->a_type == AuxiliaryValue::BaseAddress) {
  76. base_address = auxvp->a_un.a_val;
  77. found_base_address = true;
  78. }
  79. }
  80. ASSERT(found_base_address);
  81. Elf32_Ehdr* header = (Elf32_Ehdr*)(base_address);
  82. Elf32_Phdr* pheader = (Elf32_Phdr*)(base_address + header->e_phoff);
  83. u32 dynamic_section_addr = 0;
  84. for (size_t i = 0; i < (size_t)header->e_phnum; ++i, ++pheader) {
  85. if (pheader->p_type != PT_DYNAMIC)
  86. continue;
  87. dynamic_section_addr = pheader->p_vaddr + base_address;
  88. }
  89. if (!dynamic_section_addr)
  90. exit(1);
  91. auto dynamic_object = ELF::DynamicObject::construct((VirtualAddress(base_address)), (VirtualAddress(dynamic_section_addr)));
  92. dynamic_object->relocation_section().for_each_relocation([base_address](auto& reloc) {
  93. if (reloc.type() != R_386_RELATIVE)
  94. return IterationDecision::Continue;
  95. *(u32*)reloc.address().as_ptr() += base_address;
  96. return IterationDecision::Continue;
  97. });
  98. }
  99. static ELF::DynamicObject::SymbolLookupResult global_symbol_lookup(const char* symbol_name)
  100. {
  101. VERBOSE("global symbol lookup: %s\n", symbol_name);
  102. for (auto& lib : g_loaded_objects) {
  103. VERBOSE("looking up in object: %s\n", lib.key.characters());
  104. auto res = lib.value->lookup_symbol(symbol_name);
  105. if (!res.has_value())
  106. continue;
  107. return res.value();
  108. }
  109. // ASSERT_NOT_REACHED();
  110. return {};
  111. }
  112. static void map_library(const String& name, int fd)
  113. {
  114. struct stat lib_stat;
  115. int rc = fstat(fd, &lib_stat);
  116. ASSERT(!rc);
  117. auto loader = ELF::DynamicLoader::construct(name.characters(), fd, lib_stat.st_size);
  118. loader->set_tls_offset(g_current_tls_offset);
  119. loader->set_global_symbol_lookup_function(global_symbol_lookup);
  120. g_loaders.set(name, loader);
  121. g_current_tls_offset += loader->tls_size();
  122. }
  123. static void map_library(const String& name)
  124. {
  125. // TODO: Do we want to also look for libs in other paths too?
  126. String path = String::format("/usr/lib/%s", name.characters());
  127. int fd = open(path.characters(), O_RDONLY);
  128. ASSERT(fd >= 0);
  129. map_library(name, fd);
  130. }
  131. static String get_library_name(const StringView& path)
  132. {
  133. return LexicalPath(path).basename();
  134. }
  135. static Vector<String> get_dependencies(const String& name)
  136. {
  137. auto lib = g_loaders.get(name).value();
  138. Vector<String> dependencies;
  139. lib->for_each_needed_library([&dependencies](auto needed_name) {
  140. dependencies.append(needed_name);
  141. return IterationDecision::Continue;
  142. });
  143. return dependencies;
  144. }
  145. static void map_dependencies(const String& name)
  146. {
  147. VERBOSE("mapping dependencies for: %s", name.characters());
  148. for (const auto& needed_name : get_dependencies(name)) {
  149. VERBOSE("needed library: %s", needed_name.characters());
  150. String library_name = get_library_name(needed_name);
  151. if (!g_loaders.contains(library_name)) {
  152. map_library(library_name);
  153. map_dependencies(library_name);
  154. }
  155. }
  156. }
  157. static void allocate_tls()
  158. {
  159. size_t total_tls_size = 0;
  160. for (const auto& data : g_loaders) {
  161. VERBOSE("%s: TLS Size: %u\n", data.key.characters(), data.value->tls_size());
  162. total_tls_size += data.value->tls_size();
  163. }
  164. if (total_tls_size) {
  165. void* tls_address = allocate_tls(total_tls_size);
  166. (void)tls_address;
  167. VERBOSE("from userspace, tls_address: %p", tls_address);
  168. }
  169. g_total_tls_size = total_tls_size;
  170. }
  171. static void initialize_libc()
  172. {
  173. // Traditionally, `_start` of the main program initializes libc.
  174. // However, since some libs use malloc() and getenv() in global constructors,
  175. // we have to initialize libc just after it is loaded.
  176. // Also, we can't just mark `__libc_init` with "__attribute__((constructor))"
  177. // because it uses getenv() internally, so `environ` has to be initialized before we call `__libc_init`.
  178. auto res = global_symbol_lookup("environ");
  179. *((char***)res.address) = g_envp;
  180. ASSERT(res.found);
  181. res = global_symbol_lookup("__environ_is_malloced");
  182. ASSERT(res.found);
  183. *((bool*)res.address) = false;
  184. res = global_symbol_lookup("__libc_init");
  185. ASSERT(res.found);
  186. typedef void libc_init_func(void);
  187. ((libc_init_func*)res.address)();
  188. }
  189. static void load_elf(const String& name)
  190. {
  191. VERBOSE("load_elf: %s", name.characters());
  192. auto loader = g_loaders.get(name).value();
  193. for (const auto& needed_name : get_dependencies(name)) {
  194. VERBOSE("needed library: %s", needed_name.characters());
  195. String library_name = get_library_name(needed_name);
  196. if (!g_loaded_objects.contains(library_name)) {
  197. load_elf(library_name);
  198. }
  199. }
  200. VERBOSE("loading: %s", name.characters());
  201. auto dynamic_object = loader->load_from_image(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size);
  202. ASSERT(!dynamic_object.is_null());
  203. g_loaded_objects.set(name, dynamic_object.release_nonnull());
  204. if (name == "libc.so") {
  205. initialize_libc();
  206. }
  207. }
  208. static void clear_temporary_objects_mappings()
  209. {
  210. g_loaders.clear();
  211. }
  212. static FlatPtr loader_main(auxv_t* auxvp)
  213. {
  214. int main_program_fd = -1;
  215. String main_program_name;
  216. for (; auxvp->a_type != AT_NULL; ++auxvp) {
  217. if (auxvp->a_type == AuxiliaryValue::ExecFileDescriptor) {
  218. main_program_fd = auxvp->a_un.a_val;
  219. }
  220. if (auxvp->a_type == AuxiliaryValue::ExecFilename) {
  221. main_program_name = (const char*)auxvp->a_un.a_ptr;
  222. }
  223. }
  224. ASSERT(main_program_fd >= 0);
  225. map_library(main_program_name, main_program_fd);
  226. map_dependencies(main_program_name);
  227. VERBOSE("loaded all dependencies");
  228. for (auto& lib : g_loaders) {
  229. (void)lib;
  230. VERBOSE("%s - tls size: $u, tls offset: %u", lib.key.characters(), lib.value->tls_size(), lib.value->tls_offset());
  231. }
  232. allocate_tls();
  233. load_elf(main_program_name);
  234. auto main_program_lib = g_loaders.get(main_program_name).value();
  235. FlatPtr entry_point = reinterpret_cast<FlatPtr>(main_program_lib->image().entry().as_ptr() + (FlatPtr)main_program_lib->text_segment_load_address().as_ptr());
  236. VERBOSE("entry point: %p", entry_point);
  237. // This will unmap the temporary memory maps we had for loading the libraries
  238. clear_temporary_objects_mappings();
  239. return entry_point;
  240. }
  241. extern "C" {
  242. // The compiler expects a previous declaration
  243. void _start(int, char**, char**);
  244. using MainFunction = int (*)(int, char**, char**);
  245. void _start(int argc, char** argv, char** envp)
  246. {
  247. g_envp = envp;
  248. char** env;
  249. for (env = envp; *env; ++env) {
  250. }
  251. auxv_t* auxvp = (auxv_t*)++env;
  252. perform_self_relocations(auxvp);
  253. init_libc();
  254. FlatPtr entry = loader_main(auxvp);
  255. VERBOSE("Loaded libs:\n");
  256. for (auto& obj : g_loaded_objects) {
  257. (void)obj;
  258. VERBOSE("%s: %p\n", obj.key.characters(), obj.value->base_address().as_ptr());
  259. }
  260. MainFunction main_function = (MainFunction)(entry);
  261. VERBOSE("jumping to main program entry point: %p", main_function);
  262. int rc = main_function(argc, argv, envp);
  263. VERBOSE("rc: %d", rc);
  264. _exit(rc);
  265. }
  266. }