linker.c 22 KB

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