linker.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. /**
  2. * @file linker/linker.c
  3. * @brief ELF Dynamic Linker/Loader
  4. *
  5. * Loads ELF executables and links them at runtime to their
  6. * shared library dependencies.
  7. *
  8. * As of writing, this is a simplistic and not-fully-compliant
  9. * implementation of ELF dynamic linking. It suffers from a number
  10. * of issues, including not actually sharing libraries (there
  11. * isn't a sufficient mechanism in the kernel at the moment for
  12. * doing that - we need something with copy-on-write, preferably
  13. * an mmap-file mechanism), as well as not handling symbol
  14. * resolution correctly.
  15. *
  16. * However, it's sufficient for our purposes, and works well enough
  17. * to load Python C modules.
  18. *
  19. * @copyright
  20. * This file is part of ToaruOS and is released under the terms
  21. * of the NCSA / University of Illinois License - see LICENSE.md
  22. * Copyright (C) 2016-2021 K. Lange
  23. */
  24. #include <stdlib.h>
  25. #include <stdint.h>
  26. #include <alloca.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include <sys/stat.h>
  31. #include <sys/types.h>
  32. #include <sys/sysfunc.h>
  33. #include <kernel/elf.h>
  34. void * (*_malloc)(size_t size) = malloc;
  35. void (*_free)(void * ptr) = free;
  36. #undef malloc
  37. #undef free
  38. #define malloc ld_x_malloc
  39. #define free ld_x_free
  40. uintptr_t _malloc_minimum = 0;
  41. static void * malloc(size_t size) {
  42. return _malloc(size);
  43. }
  44. static void free(void * ptr) {
  45. if ((uintptr_t)ptr < _malloc_minimum) return;
  46. _free(ptr);
  47. }
  48. /*
  49. * When the LD_DEBUG environment variable is set, TRACE_LD messages
  50. * will be printed to stderr
  51. */
  52. #define TRACE_APP_NAME "ld.so"
  53. #define TRACE_LD(...) do { if (__trace_ld) { TRACE(__VA_ARGS__); } } while (0)
  54. static int __trace_ld = 0;
  55. #include <toaru/trace.h>
  56. /*
  57. * This libraries are included in source form to avoid having
  58. * to build separate objects for them and complicate linking,
  59. * since ld is specially built as a static object.
  60. */
  61. #include "../lib/list.c"
  62. #include "../lib/hashmap.c"
  63. typedef int (*entry_point_t)(int, char *[], char**);
  64. /* Global linking state */
  65. static hashmap_t * dumb_symbol_table;
  66. static hashmap_t * glob_dat;
  67. static hashmap_t * objects_map;
  68. static hashmap_t * tls_map;
  69. static size_t current_tls_offset = 0;
  70. /* Used for dlerror */
  71. static char * last_error = NULL;
  72. static int _target_is_suid = 0;
  73. typedef struct elf_object {
  74. FILE * file;
  75. /* Full copy of the header. */
  76. Elf64_Header header;
  77. char * dyn_string_table;
  78. size_t dyn_string_table_size;
  79. Elf64_Sym * dyn_symbol_table;
  80. size_t dyn_symbol_table_size;
  81. Elf64_Dyn * dynamic;
  82. Elf64_Word * dyn_hash;
  83. void (*init)(void);
  84. void (**init_array)(void);
  85. size_t init_array_size;
  86. uintptr_t base;
  87. list_t * dependencies;
  88. int loaded;
  89. } elf_t;
  90. static elf_t * _main_obj = NULL;
  91. /* Locate library for LD_LIBRARY PATH */
  92. static char * find_lib(const char * file) {
  93. /* If it was an absolute path, there's no need to find it. */
  94. if (strchr(file, '/')) return strdup(file);
  95. /* Collect the environment variable. */
  96. char * path = _target_is_suid ? NULL : getenv("LD_LIBRARY_PATH");
  97. if (!path) {
  98. /* Not set - this is the default state. Should probably read from config file? */
  99. path = "/lib:/usr/lib";
  100. }
  101. /* Duplicate so we can tokenize without editing */
  102. char * xpath = strdup(path);
  103. char * p, * last;
  104. for ((p = strtok_r(xpath, ":", &last)); p; p = strtok_r(NULL, ":", &last)) {
  105. /* Go through each LD_LIBRARY_PATH entry */
  106. int r;
  107. struct stat stat_buf;
  108. /* Append the requested file to that path */
  109. char * exe = malloc(strlen(p) + strlen(file) + 2);
  110. *exe = '\0';
  111. strcat(exe, p);
  112. strcat(exe, "/");
  113. strcat(exe, file);
  114. /* See if it exists */
  115. r = stat(exe, &stat_buf);
  116. if (r != 0) {
  117. /* Nope. */
  118. free(exe);
  119. continue;
  120. }
  121. /* It exists, so this is what we want. */
  122. return exe;
  123. }
  124. free(xpath);
  125. /* No match found. */
  126. return NULL;
  127. }
  128. /* Open an object file */
  129. static elf_t * open_object(const char * path) {
  130. /* If no path (eg. dlopen(NULL)), return the main object (the executable). */
  131. if (!path) {
  132. return _main_obj;
  133. }
  134. /* If we've already opened a file with this name, return it - don't load things twice. */
  135. if (hashmap_has(objects_map, (void*)path)) {
  136. elf_t * object = hashmap_get(objects_map, (void*)path);
  137. return object;
  138. }
  139. /* Locate the library */
  140. char * file = find_lib(path);
  141. if (!file) {
  142. last_error = "Could not find library.";
  143. return NULL;
  144. }
  145. /* Open the library. */
  146. FILE * f = fopen(file, "r");
  147. /* Free the expanded path, we don't need it anymore. */
  148. free(file);
  149. /* Failed to open? Unlikely, but could mean permissions problems. */
  150. if (!f) {
  151. last_error = "Could not open library.";
  152. return NULL;
  153. }
  154. /* Initialize a fresh object object. */
  155. elf_t * object = malloc(sizeof(elf_t));
  156. memset(object, 0, sizeof(elf_t));
  157. hashmap_set(objects_map, (void*)path, object);
  158. /* Really unlikely... */
  159. if (!object) {
  160. last_error = "Could not allocate space.";
  161. return NULL;
  162. }
  163. object->file = f;
  164. /* Read the header */
  165. size_t r = fread(&object->header, sizeof(Elf64_Header), 1, object->file);
  166. /* Header failed to read? */
  167. if (!r) {
  168. last_error = "Failed to read object header.";
  169. free(object);
  170. return NULL;
  171. }
  172. /* Is this actually an ELF object? */
  173. if (object->header.e_ident[0] != ELFMAG0 ||
  174. object->header.e_ident[1] != ELFMAG1 ||
  175. object->header.e_ident[2] != ELFMAG2 ||
  176. object->header.e_ident[3] != ELFMAG3) {
  177. last_error = "Not an ELF object.";
  178. free(object);
  179. return NULL;
  180. }
  181. /* Prepare a list for tracking dependencies. */
  182. object->dependencies = list_create();
  183. return object;
  184. }
  185. /* Calculate the size of an object file by examining its phdrs */
  186. static size_t object_calculate_size(elf_t * object) {
  187. uintptr_t base_addr = (uintptr_t)-1;
  188. uintptr_t end_addr = 0x0;
  189. size_t headers = 0;
  190. while (headers < object->header.e_phnum) {
  191. Elf64_Phdr phdr;
  192. /* Read the phdr */
  193. fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET);
  194. fread(&phdr, object->header.e_phentsize, 1, object->file);
  195. switch (phdr.p_type) {
  196. case PT_LOAD:
  197. {
  198. /* If this loads lower than our current base... */
  199. if (phdr.p_vaddr < base_addr) {
  200. base_addr = phdr.p_vaddr;
  201. }
  202. /* Or higher than our current end address... */
  203. if (phdr.p_memsz + phdr.p_vaddr > end_addr) {
  204. end_addr = phdr.p_memsz + phdr.p_vaddr;
  205. }
  206. }
  207. break;
  208. /* TODO: Do we care about other PHDR types here? */
  209. default:
  210. break;
  211. }
  212. headers++;
  213. }
  214. /* If base_addr is still -1, then no valid phdrs were found, and the object has no loaded size. */
  215. if (base_addr == (uintptr_t)-1) return 0;
  216. return end_addr - base_addr;
  217. }
  218. /* Load an object into memory */
  219. static uintptr_t object_load(elf_t * object, uintptr_t base) {
  220. uintptr_t end_addr = 0x0;
  221. object->base = base;
  222. size_t headers = 0;
  223. while (headers < object->header.e_phnum) {
  224. Elf64_Phdr phdr;
  225. /* Read the phdr */
  226. fseek(object->file, object->header.e_phoff + object->header.e_phentsize * headers, SEEK_SET);
  227. fread(&phdr, object->header.e_phentsize, 1, object->file);
  228. switch (phdr.p_type) {
  229. case PT_LOAD:
  230. {
  231. /* Request memory to load this PHDR into */
  232. char * args[] = {(char *)(base + phdr.p_vaddr), (char *)phdr.p_memsz};
  233. sysfunc(TOARU_SYS_FUNC_MMAP, args);
  234. /* Copy the code into memory */
  235. fseek(object->file, phdr.p_offset, SEEK_SET);
  236. fread((void *)(base + phdr.p_vaddr), phdr.p_filesz, 1, object->file);
  237. /* Zero the remaining area */
  238. size_t r = phdr.p_filesz;
  239. while (r < phdr.p_memsz) {
  240. *(char *)(phdr.p_vaddr + base + r) = 0;
  241. r++;
  242. }
  243. /* If this expands our end address, be sure to update it */
  244. if (end_addr < phdr.p_vaddr + base + phdr.p_memsz) {
  245. end_addr = phdr.p_vaddr + base + phdr.p_memsz;
  246. }
  247. }
  248. break;
  249. case PT_DYNAMIC:
  250. {
  251. /* Keep a reference to the dynamic section, which is actually loaded by a PT_LOAD normally. */
  252. object->dynamic = (Elf64_Dyn *)(base + phdr.p_vaddr);
  253. }
  254. break;
  255. default:
  256. break;
  257. }
  258. headers++;
  259. }
  260. return end_addr;
  261. }
  262. /* Perform cleanup after loading */
  263. static int object_postload(elf_t * object) {
  264. /* If there is a dynamic table, parse it. */
  265. if (object->dynamic) {
  266. Elf64_Dyn * table;
  267. /* Locate string tables */
  268. table = object->dynamic;
  269. while (table->d_tag) {
  270. switch (table->d_tag) {
  271. case DT_HASH:
  272. object->dyn_hash = (Elf64_Word *)(object->base + table->d_un.d_ptr);
  273. object->dyn_symbol_table_size = object->dyn_hash[1];
  274. break;
  275. case DT_STRTAB:
  276. object->dyn_string_table = (char *)(object->base + table->d_un.d_ptr);
  277. break;
  278. case DT_SYMTAB:
  279. object->dyn_symbol_table = (Elf64_Sym *)(object->base + table->d_un.d_ptr);
  280. break;
  281. case DT_STRSZ: /* Size of string table */
  282. object->dyn_string_table_size = table->d_un.d_val;
  283. break;
  284. case DT_INIT: /* DT_INIT - initialization function */
  285. object->init = (void (*)(void))(table->d_un.d_ptr + object->base);
  286. break;
  287. case DT_INIT_ARRAY: /* DT_INIT_ARRAY - array of constructors */
  288. object->init_array = (void (**)(void))(table->d_un.d_ptr + object->base);
  289. break;
  290. case DT_INIT_ARRAYSZ: /* DT_INIT_ARRAYSZ - size of the table of constructors */
  291. object->init_array_size = table->d_un.d_val / sizeof(uintptr_t);
  292. break;
  293. }
  294. table++;
  295. }
  296. /*
  297. * Read through dependencies
  298. * We have to do this separately from the above to make sure
  299. * we have the dynamic string tables loaded first, as they
  300. * are needed for the dependency names.
  301. */
  302. table = object->dynamic;
  303. while (table->d_tag) {
  304. switch (table->d_tag) {
  305. case 1:
  306. list_insert(object->dependencies, object->dyn_string_table + table->d_un.d_val);
  307. break;
  308. }
  309. table++;
  310. }
  311. }
  312. return 0;
  313. }
  314. /* Whether symbol addresses is needed for a relocation type */
  315. static int need_symbol_for_type(unsigned char type) {
  316. switch(type) {
  317. case 1:
  318. case 2:
  319. case 5:
  320. case 6:
  321. case 7:
  322. case 14:
  323. case R_X86_64_TPOFF64:
  324. return 1;
  325. default:
  326. return 0;
  327. }
  328. }
  329. /* Apply ELF relocations */
  330. static int object_relocate(elf_t * object) {
  331. /* If there is a dynamic symbol table, load symbols */
  332. if (object->dyn_symbol_table) {
  333. Elf64_Sym * table = object->dyn_symbol_table;
  334. size_t i = 0;
  335. while (i < object->dyn_symbol_table_size) {
  336. char * symname = (char *)((uintptr_t)object->dyn_string_table + table->st_name);
  337. /* If we haven't added this symbol to our symbol table, do so now. */
  338. if (!hashmap_has(dumb_symbol_table, symname)) {
  339. if (table->st_shndx) {
  340. hashmap_set(dumb_symbol_table, symname, (void*)(table->st_value + object->base));
  341. }
  342. }
  343. table++;
  344. i++;
  345. }
  346. }
  347. /* Find relocation table */
  348. for (uintptr_t x = 0; x < object->header.e_shentsize * object->header.e_shnum; x += object->header.e_shentsize) {
  349. Elf64_Shdr shdr;
  350. /* Load section header */
  351. fseek(object->file, object->header.e_shoff + x, SEEK_SET);
  352. fread(&shdr, object->header.e_shentsize, 1, object->file);
  353. /* Relocation table found */
  354. if (shdr.sh_type == SHT_REL) {
  355. TRACE_LD("Found a REL section, this is not handled.");
  356. } else if (shdr.sh_type == SHT_RELA) {
  357. Elf64_Rela * table = (Elf64_Rela *)(shdr.sh_addr + object->base);
  358. while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) {
  359. unsigned int symbol = ELF64_R_SYM(table->r_info);
  360. unsigned int type = ELF64_R_TYPE(table->r_info);
  361. Elf64_Sym * sym = &object->dyn_symbol_table[symbol];
  362. /* If we need symbol for this, get it. */
  363. char * symname = NULL;
  364. uintptr_t x = sym->st_value + object->base;
  365. if (need_symbol_for_type(type) || (type == 5)) {
  366. symname = (char *)((uintptr_t)object->dyn_string_table + sym->st_name);
  367. if (symname && hashmap_has(dumb_symbol_table, symname)) {
  368. x = (uintptr_t)hashmap_get(dumb_symbol_table, symname);
  369. sym->st_value = x;
  370. } else {
  371. /* This isn't fatal, but do log a message if debugging is enabled. */
  372. TRACE_LD("Symbol not found: %s", symname);
  373. x = 0x0;
  374. }
  375. }
  376. /* Relocations, symbol lookups, etc. */
  377. switch (type) {
  378. case R_X86_64_GLOB_DAT: /* 6 */
  379. if (symname && hashmap_has(glob_dat, symname)) {
  380. x = (uintptr_t)hashmap_get(glob_dat, symname);
  381. } /* fallthrough */
  382. case R_X86_64_JUMP_SLOT: /* 7 */
  383. memcpy((void*)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  384. break;
  385. case R_X86_64_RELATIVE: /* 8*/
  386. x = object->base;
  387. x += table->r_addend;
  388. //*((ssize_t *)(table->r_offset + object->base));
  389. memcpy((void*)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  390. break;
  391. case R_X86_64_64: /* 1 */
  392. x += table->r_addend;
  393. memcpy((void*)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  394. break;
  395. case R_X86_64_COPY: /* 5 */
  396. memcpy((void *)(table->r_offset + object->base), (void *)x, sym->st_size);
  397. break;
  398. case R_X86_64_TPOFF64:
  399. x = *((ssize_t *)(table->r_offset + object->base));
  400. if (!hashmap_has(tls_map, symname)) {
  401. if (!sym->st_size) {
  402. fprintf(stderr, "Haven't placed %s in static TLS yet but don't know its size?\n", symname);
  403. }
  404. current_tls_offset += sym->st_size; /* TODO alignment restrictions */
  405. hashmap_set(tls_map, symname, (void*)(current_tls_offset));
  406. x -= current_tls_offset;
  407. } else {
  408. x -= (size_t)hashmap_get(tls_map, symname);
  409. }
  410. memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  411. break;
  412. #if 0
  413. case 6: /* GLOB_DAT */
  414. if (symname && hashmap_has(glob_dat, symname)) {
  415. x = (uintptr_t)hashmap_get(glob_dat, symname);
  416. }
  417. case 7: /* JUMP_SLOT */
  418. memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  419. break;
  420. case 1: /* 32 */
  421. x += *((ssize_t *)(table->r_offset + object->base));
  422. memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  423. break;
  424. case 2: /* PC32 */
  425. x += *((ssize_t *)(table->r_offset + object->base));
  426. x -= (table->r_offset + object->base);
  427. memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  428. break;
  429. case 8: /* RELATIVE */
  430. x = object->base;
  431. x += *((ssize_t *)(table->r_offset + object->base));
  432. memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  433. break;
  434. case 5: /* COPY */
  435. memcpy((void *)(table->r_offset + object->base), (void *)x, sym->st_size);
  436. break;
  437. case 14: /* TLS_TPOFF */
  438. x = *((ssize_t *)(table->r_offset + object->base));
  439. if (!hashmap_has(tls_map, symname)) {
  440. if (!sym->st_size) {
  441. fprintf(stderr, "Haven't placed %s in static TLS yet but don't know its size?\n", symname);
  442. }
  443. current_tls_offset += sym->st_size; /* TODO alignment restrictions */
  444. hashmap_set(tls_map, symname, (void*)(current_tls_offset));
  445. x -= current_tls_offset;
  446. } else {
  447. x -= (size_t)hashmap_get(tls_map, symname);
  448. }
  449. memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t));
  450. break;
  451. #endif
  452. default:
  453. TRACE_LD("Unknown relocation type: %d", type);
  454. }
  455. table++;
  456. }
  457. }
  458. }
  459. return 0;
  460. }
  461. /* Copy relocations are special and need to be located before other relocations. */
  462. static void object_find_copy_relocations(elf_t * object) {
  463. for (uintptr_t x = 0; x < object->header.e_shentsize * object->header.e_shnum; x += object->header.e_shentsize) {
  464. Elf64_Shdr shdr;
  465. fseek(object->file, object->header.e_shoff + x, SEEK_SET);
  466. fread(&shdr, object->header.e_shentsize, 1, object->file);
  467. /* Relocation table found */
  468. if (shdr.sh_type == SHT_REL) {
  469. Elf64_Rel * table = (Elf64_Rel *)(shdr.sh_addr + object->base);
  470. while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) {
  471. unsigned int type = ELF64_R_TYPE(table->r_info);
  472. if (type == R_X86_64_COPY) {
  473. unsigned int symbol = ELF64_R_SYM(table->r_info);
  474. Elf64_Sym * sym = &object->dyn_symbol_table[symbol];
  475. char * symname = (char *)((uintptr_t)object->dyn_string_table + sym->st_name);
  476. hashmap_set(glob_dat, symname, (void *)table->r_offset);
  477. }
  478. table++;
  479. }
  480. }
  481. if (shdr.sh_type == SHT_RELA) {
  482. Elf64_Rela * table = (Elf64_Rela *)(shdr.sh_addr + object->base);
  483. while ((uintptr_t)table - ((uintptr_t)shdr.sh_addr + object->base) < shdr.sh_size) {
  484. unsigned int type = ELF64_R_TYPE(table->r_info);
  485. if (type == R_X86_64_COPY) {
  486. unsigned int symbol = ELF64_R_SYM(table->r_info);
  487. Elf64_Sym * sym = &object->dyn_symbol_table[symbol];
  488. char * symname = (char *)((uintptr_t)object->dyn_string_table + sym->st_name);
  489. hashmap_set(glob_dat, symname, (void *)table->r_offset);
  490. }
  491. table++;
  492. }
  493. }
  494. }
  495. }
  496. /* Find a symbol in a specific object. */
  497. static void * object_find_symbol(elf_t * object, const char * symbol_name) {
  498. if (!object->dyn_symbol_table) {
  499. last_error = "lib does not have a symbol table";
  500. return NULL;
  501. }
  502. Elf64_Sym * table = object->dyn_symbol_table;
  503. size_t i = 0;
  504. while (i < object->dyn_symbol_table_size) {
  505. if (!strcmp(symbol_name, (char *)((uintptr_t)object->dyn_string_table + table->st_name))) {
  506. return (void *)(table->st_value + object->base);
  507. }
  508. table++;
  509. i++;
  510. }
  511. last_error = "symbol not found in library";
  512. return NULL;
  513. }
  514. /* Fully load an object. */
  515. static void * do_actual_load(const char * filename, elf_t * lib, int flags) {
  516. (void)flags;
  517. if (!lib) {
  518. last_error = "could not open library (not found, or other failure)";
  519. TRACE_LD("could not open library");
  520. return NULL;
  521. }
  522. size_t lib_size = object_calculate_size(lib);
  523. /* Needs to be at least a page. */
  524. if (lib_size < 4096) {
  525. lib_size = 4096;
  526. }
  527. /*
  528. * Allocate space to load the library
  529. * This is where we should really be loading things into COW
  530. * but we don't have the functionality available.
  531. */
  532. uintptr_t load_addr = (uintptr_t)malloc(lib_size);
  533. object_load(lib, load_addr);
  534. /* Perform cleanup steps */
  535. object_postload(lib);
  536. /* Ensure dependencies are available */
  537. node_t * item;
  538. while ((item = list_pop(lib->dependencies))) {
  539. elf_t * _lib = open_object(item->value);
  540. if (!_lib) {
  541. /* Missing dependencies are fatal to this process, but
  542. * not to the entire application. */
  543. free((void *)load_addr);
  544. last_error = "Failed to load a dependency.";
  545. lib->loaded = 0;
  546. TRACE_LD("Failed to load object: %s", item->value);
  547. return NULL;
  548. }
  549. if (!_lib->loaded) {
  550. do_actual_load(item->value, _lib, 0);
  551. TRACE_LD("Loaded %s at 0x%x", item->value, lib->base);
  552. }
  553. }
  554. /* Perform relocations */
  555. TRACE_LD("Relocating %s", filename);
  556. object_relocate(lib);
  557. /* We're done with the file. */
  558. fclose(lib->file);
  559. /* If there was an init_array, call everything in it */
  560. if (lib->init_array) {
  561. for (size_t i = 0; i < lib->init_array_size; i++) {
  562. TRACE_LD(" 0x%x()", lib->init_array[i]);
  563. lib->init_array[i]();
  564. }
  565. }
  566. /* If the library has an init function, call that last. */
  567. if (lib->init) {
  568. lib->init();
  569. }
  570. lib->loaded = 1;
  571. /* And return an object for the loaded library */
  572. return (void *)lib;
  573. }
  574. static uintptr_t end_addr = 0;
  575. /**
  576. * Half loads an object using the dumb allocator and performs dependency
  577. * resolution. This is a separate process from do_actual_load and dlopen_ld
  578. * to avoid problems with malloc and library functions while loading.
  579. * Preloaded objects will be fully loaded everything is relocated.
  580. */
  581. static elf_t * preload(hashmap_t * libs, list_t * load_libs, char * lib_name) {
  582. /* Find and open the library */
  583. elf_t * lib = open_object(lib_name);
  584. if (!lib) {
  585. fprintf(stderr, "Failed to load dependency '%s'.\n", lib_name);
  586. return NULL;
  587. }
  588. /* Skip already loaded libraries */
  589. if (lib->loaded) return lib;
  590. /* Mark this library available */
  591. hashmap_set(libs, lib_name, lib);
  592. TRACE_LD("Loading %s at 0x%x", lib_name, end_addr);
  593. /* Adjust dumb allocator */
  594. while (end_addr & 0xFFF) {
  595. end_addr++;
  596. }
  597. /* Load PHDRs */
  598. end_addr = object_load(lib, end_addr);
  599. /* Extract information */
  600. object_postload(lib);
  601. /* Mark loaded */
  602. lib->loaded = 1;
  603. /* Verify dependencies are loaded before we relocate */
  604. foreach(node, lib->dependencies) {
  605. if (!hashmap_has(libs, node->value)) {
  606. TRACE_LD("Need unloaded dependency %s", node->value);
  607. preload(libs, load_libs, node->value);
  608. }
  609. }
  610. /* Add this to the (forward scan) list of libraries to finish loading */
  611. list_insert(load_libs, lib);
  612. return lib;
  613. }
  614. /* exposed dlopen() method */
  615. static void * dlopen_ld(const char * filename, int flags) {
  616. TRACE_LD("dlopen(%s,0x%x)", filename, flags);
  617. elf_t * lib = open_object(filename);
  618. if (!lib) {
  619. return NULL;
  620. }
  621. if (lib->loaded) {
  622. return lib;
  623. }
  624. void * ret = do_actual_load(filename, lib, flags);
  625. if (!ret) {
  626. /* Dependency load failure, remove us from hash */
  627. TRACE_LD("Dependency load failure");
  628. hashmap_remove(objects_map, (void*)filename);
  629. }
  630. TRACE_LD("Loaded %s at 0x%x", filename, lib->base);
  631. return ret;
  632. }
  633. /* exposed dlclose() method - XXX not fully implemented */
  634. static int dlclose_ld(elf_t * lib) {
  635. /* TODO close dependencies? Make sure nothing references this. */
  636. free((void *)lib->base);
  637. return 0;
  638. }
  639. /* exposed dlerror() method */
  640. static char * dlerror_ld(void) {
  641. char * this_error = last_error;
  642. last_error = NULL;
  643. return this_error;
  644. }
  645. /* Specially used by libc */
  646. static void * _argv_value = NULL;
  647. static char * argv_value(void) {
  648. return _argv_value;
  649. }
  650. static uintptr_t dl_symbol_table_ptr_addr(void) {
  651. return (uintptr_t)&dumb_symbol_table;
  652. }
  653. static uintptr_t dl_objects_table_ptr_addr(void) {
  654. return (uintptr_t)&objects_map;
  655. }
  656. /* Exported methods (dlfcn) */
  657. typedef struct {
  658. char * name;
  659. void * symbol;
  660. } ld_exports_t;
  661. ld_exports_t ld_builtin_exports[] = {
  662. {"dlopen", dlopen_ld},
  663. {"dlsym", object_find_symbol},
  664. {"dlclose", dlclose_ld},
  665. {"dlerror", dlerror_ld},
  666. {"__get_argv", argv_value},
  667. {"__ld_symbol_table", dl_symbol_table_ptr_addr},
  668. {"__ld_objects_table", dl_objects_table_ptr_addr},
  669. {NULL, NULL},
  670. };
  671. int main(int argc, char * argv[]) {
  672. if (argc < 2) {
  673. fprintf(stderr,
  674. "ld.so - dynamic binary loader\n"
  675. "\n"
  676. "usage: %s [-e] [EXECUTABLE PATH]\n"
  677. "\n"
  678. " -e \033[3mAdjust argument offset\033[0m\n"
  679. "\n", argv[0]);
  680. return -1;
  681. }
  682. char * file = argv[1];
  683. size_t arg_offset = 1;
  684. if (!strcmp(argv[1], "-e")) {
  685. arg_offset = 3;
  686. file = argv[2];
  687. }
  688. _argv_value = argv+arg_offset;
  689. /* Enable tracing if requested */
  690. char * trace_ld_env = getenv("LD_DEBUG");
  691. if (trace_ld_env && (!strcmp(trace_ld_env,"1") || !strcmp(trace_ld_env,"yes"))) {
  692. __trace_ld = 1;
  693. }
  694. /* Initialize hashmaps for symbols, GLOB_DATs, and objects */
  695. dumb_symbol_table = hashmap_create(10);
  696. glob_dat = hashmap_create(10);
  697. objects_map = hashmap_create(10);
  698. tls_map = hashmap_create(10);
  699. /* Setup symbols for built-in exports */
  700. ld_exports_t * ex = ld_builtin_exports;
  701. while (ex->name) {
  702. hashmap_set(dumb_symbol_table, ex->name, ex->symbol);
  703. ex++;
  704. }
  705. /* Technically there's a potential time-of-use probably if we check like this but
  706. * this is a toy linker for a toy OS so the fact that we even need to check suid
  707. * bits at all is outrageous
  708. */
  709. struct stat buf;
  710. if (stat(file, &buf)) {
  711. fprintf(stderr, "%s: target binary '%s' not available\n", argv[0], file);
  712. }
  713. /* Technically there's a way to know we're running suid, but let's check the actual file */
  714. if (buf.st_mode & S_ISUID) {
  715. _target_is_suid = 1;
  716. }
  717. /* Open the requested main object */
  718. elf_t * main_obj = open_object(file);
  719. _main_obj = main_obj;
  720. if (!main_obj) {
  721. fprintf(stderr, "%s: error: failed to open object '%s'.\n", argv[0], file);
  722. return 1;
  723. }
  724. /* Load the main object */
  725. end_addr = object_load(main_obj, 0x0);
  726. object_postload(main_obj);
  727. object_find_copy_relocations(main_obj);
  728. /* Load library dependencies */
  729. hashmap_t * libs = hashmap_create(10);
  730. while (end_addr & 0xFFF) {
  731. end_addr++;
  732. }
  733. /* Load dependent libraries, recursively. */
  734. TRACE_LD("Loading dependencies.");
  735. list_t * load_libs = list_create();
  736. node_t * item;
  737. while ((item = list_pop(main_obj->dependencies))) {
  738. char * lib_name = item->value;
  739. /* Skip libg.so which is a fake library that doesn't really exist.
  740. * XXX: Only binaries should depend on this I think? */
  741. if (!strcmp(lib_name, "libg.so")) goto nope;
  742. /* Preload library */
  743. elf_t * lib = preload(libs, load_libs, lib_name);
  744. /* Failed to load */
  745. if (!lib) return 1;
  746. nope:
  747. free(item);
  748. }
  749. list_t * ctor_libs = list_create();
  750. list_t * init_libs = list_create();
  751. while ((item = list_dequeue(load_libs))) {
  752. elf_t * lib = item->value;
  753. /* Complete relocation */
  754. object_relocate(lib);
  755. /* Close the underlying file */
  756. fclose(lib->file);
  757. /* Store constructors for later execution */
  758. if (lib->init_array) {
  759. list_insert(ctor_libs, lib);
  760. }
  761. if (lib->init) {
  762. list_insert(init_libs, lib);
  763. }
  764. free(item);
  765. }
  766. /* Relocate the main object */
  767. TRACE_LD("Relocating main object");
  768. object_relocate(main_obj);
  769. fclose(main_obj->file);
  770. TRACE_LD("Placing heap at end");
  771. while (end_addr & 0xFFF) {
  772. end_addr++;
  773. }
  774. /* Move heap start (kind of like a weird sbrk) */
  775. {
  776. char * args[] = {(char*)end_addr};
  777. sysfunc(TOARU_SYS_FUNC_SETHEAP, args);
  778. }
  779. /* Call constructors for loaded dependencies */
  780. char * ld_no_ctors = getenv("LD_DISABLE_CTORS");
  781. if (ld_no_ctors && (!strcmp(ld_no_ctors,"1") || !strcmp(ld_no_ctors,"yes"))) {
  782. TRACE_LD("skipping ctors because LD_DISABLE_CTORS was set");
  783. } else {
  784. foreach(node, ctor_libs) {
  785. elf_t * lib = node->value;
  786. if (lib->init_array) {
  787. TRACE_LD("Executing init_array...");
  788. for (size_t i = 0; i < lib->init_array_size; i++) {
  789. TRACE_LD(" 0x%x()", lib->init_array[i]);
  790. lib->init_array[i]();
  791. }
  792. }
  793. }
  794. }
  795. foreach(node, init_libs) {
  796. elf_t * lib = node->value;
  797. lib->init();
  798. }
  799. /* If main object had constructors, call them. */
  800. if (main_obj->init_array) {
  801. for (size_t i = 0; i < main_obj->init_array_size; i++) {
  802. TRACE_LD(" 0x%x()", main_obj->init_array[i]);
  803. main_obj->init_array[i]();
  804. }
  805. }
  806. if (main_obj->init) {
  807. main_obj->init();
  808. }
  809. main_obj->loaded = 1;
  810. /* Set heap functions for later usage */
  811. if (hashmap_has(dumb_symbol_table, "malloc")) _malloc = hashmap_get(dumb_symbol_table, "malloc");
  812. if (hashmap_has(dumb_symbol_table, "free")) _free = hashmap_get(dumb_symbol_table, "free");
  813. _malloc_minimum = 0x40000000;
  814. /* Jump to the entry for the main object */
  815. TRACE_LD("Jumping to entry point 0x%lx", main_obj->header.e_entry);
  816. entry_point_t entry = (entry_point_t)main_obj->header.e_entry;
  817. entry(argc-arg_offset,argv+arg_offset,environ);
  818. return 0;
  819. }