dlelf.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * Copyright (c) 2006-2024 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018/08/29 Bernard first version
  9. * 2021/04/23 chunyexixiaoyu distinguish 32-bit and 64-bit
  10. */
  11. #include "dlmodule.h"
  12. #include "dlelf.h"
  13. #define DBG_TAG "DLMD"
  14. #define DBG_LVL DBG_INFO
  15. #include <rtdbg.h> /* must after of DEBUG_ENABLE or some other options*/
  16. /**
  17. * @brief Load a shared object file into memory.
  18. *
  19. * @param module A pointer to a rt_dlmodule object for holding the module's information.
  20. * @param module_ptr A pointer to the raw memory of the ELF file (shared object) that is being loaded.
  21. * @return rt_err_t On success, it returns RT_EOK. Otherwise, it returns the error code.
  22. *
  23. * @note This function loads a shared object (ELF file) into memory, broken down into steps:
  24. * 1. Initialization and Validation: it begins by validating the module pointer
  25. * and checking if the ELF file has been linked by comparing its magic number (RTMMAG).
  26. * If matched, the module is considered linked.
  27. * 2. Calculating the ELF Image Size: it iterates over the ELF program headers to compute the total size of the ELF image
  28. * by adding the sizes of loadable segments. It also ensures there are no overlaps or invalid addresses in the segments.
  29. * 3. Allocating Memory for the Module: After determining the module size, the function allocates memory (module->mem_space) for the ELF image
  30. * and initializes it to zero. Then, it copies the relevant program segments from the ELF file into this allocated memory.
  31. * 4. Setting the Module Entry Point: it sets the entry point address (module->entry_addr) based on the ELF entry point adjusted by the calculated base address.
  32. * 5. Handling Relocation Sections: It processes each relocation section in the ELF file.
  33. * For each relocation entry, it either resolves the symbol from the module's own symbol table
  34. * or looks up the symbol in the kernel symbol table if it was not found locally.
  35. * 6. Building the Module's Symbol Table: it looks for the .dynsym section to extract global function symbols.
  36. * It creates a symbol table (module->symtab) and populates it with the function names and addresses for all global symbols of type STT_FUNC.
  37. * 7. Extracting Additional Parameters: It extracts additional parameters, such as thread priority (dlmodule_thread_priority) and stack size (dlmodule_thread_stacksize),
  38. * from the symbol table and assigns them to the module if valid.
  39. */
  40. rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_ptr)
  41. {
  42. rt_bool_t linked = RT_FALSE;
  43. rt_ubase_t index, module_size = 0;
  44. Elf_Addr vstart_addr, vend_addr;
  45. rt_bool_t has_vstart;
  46. RT_ASSERT(module_ptr != RT_NULL);
  47. if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) == 0)
  48. {
  49. /* rtmlinker finished */
  50. linked = RT_TRUE;
  51. }
  52. /* get the ELF image size */
  53. has_vstart = RT_FALSE;
  54. vstart_addr = vend_addr = RT_NULL;
  55. for (index = 0; index < elf_module->e_phnum; index++)
  56. {
  57. if (phdr[index].p_type != PT_LOAD)
  58. continue;
  59. LOG_D("LOAD segment: %d, 0x%p, 0x%08x", index, phdr[index].p_vaddr, phdr[index].p_memsz);
  60. if (phdr[index].p_memsz < phdr[index].p_filesz)
  61. {
  62. rt_kprintf("invalid elf: segment %d: p_memsz: %d, p_filesz: %d\n",
  63. index, phdr[index].p_memsz, phdr[index].p_filesz);
  64. return RT_NULL;
  65. }
  66. if (!has_vstart)
  67. {
  68. vstart_addr = phdr[index].p_vaddr;
  69. vend_addr = phdr[index].p_vaddr + phdr[index].p_memsz;
  70. has_vstart = RT_TRUE;
  71. if (vend_addr < vstart_addr)
  72. {
  73. LOG_E("invalid elf: segment %d: p_vaddr: %d, p_memsz: %d\n",
  74. index, phdr[index].p_vaddr, phdr[index].p_memsz);
  75. return RT_NULL;
  76. }
  77. }
  78. else
  79. {
  80. if (phdr[index].p_vaddr < vend_addr)
  81. {
  82. LOG_E("invalid elf: segment should be sorted and not overlapped\n");
  83. return RT_NULL;
  84. }
  85. if (phdr[index].p_vaddr > vend_addr + 16)
  86. {
  87. /* There should not be too much padding in the object files. */
  88. LOG_W("warning: too much padding before segment %d", index);
  89. }
  90. vend_addr = phdr[index].p_vaddr + phdr[index].p_memsz;
  91. if (vend_addr < phdr[index].p_vaddr)
  92. {
  93. LOG_E("invalid elf: "
  94. "segment %d address overflow\n", index);
  95. return RT_NULL;
  96. }
  97. }
  98. }
  99. module_size = vend_addr - vstart_addr;
  100. LOG_D("module size: %d, vstart_addr: 0x%p", module_size, vstart_addr);
  101. if (module_size == 0)
  102. {
  103. LOG_E("Module: size error\n");
  104. return -RT_ERROR;
  105. }
  106. module->vstart_addr = vstart_addr;
  107. module->nref = 0;
  108. /* allocate module space */
  109. module->mem_space = rt_malloc(module_size);
  110. if (module->mem_space == RT_NULL)
  111. {
  112. LOG_E("Module: allocate space failed.\n");
  113. return -RT_ERROR;
  114. }
  115. module->mem_size = module_size;
  116. /* zero all space */
  117. rt_memset(module->mem_space, 0, module_size);
  118. for (index = 0; index < elf_module->e_phnum; index++)
  119. {
  120. if (phdr[index].p_type == PT_LOAD)
  121. {
  122. rt_memcpy(module->mem_space + phdr[index].p_vaddr - vstart_addr,
  123. (rt_uint8_t *)elf_module + phdr[index].p_offset,
  124. phdr[index].p_filesz);
  125. }
  126. }
  127. /* set module entry */
  128. module->entry_addr = module->mem_space + elf_module->e_entry - vstart_addr;
  129. /* handle relocation section */
  130. for (index = 0; index < elf_module->e_shnum; index ++)
  131. {
  132. rt_ubase_t i, nr_reloc;
  133. Elf_Sym *symtab;
  134. Elf_Rel *rel;
  135. rt_uint8_t *strtab;
  136. static rt_bool_t unsolved = RT_FALSE;
  137. #if (defined(__arm__) || defined(__i386__) || (__riscv_xlen == 32))
  138. if (!IS_REL(shdr[index]))
  139. continue;
  140. #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64))
  141. if (!IS_RELA(shdr[index]))
  142. continue;
  143. #endif
  144. /* get relocate item */
  145. rel = (Elf_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
  146. /* locate .rel.plt and .rel.dyn section */
  147. symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr +
  148. shdr[shdr[index].sh_link].sh_offset);
  149. strtab = (rt_uint8_t *)module_ptr +
  150. shdr[shdr[shdr[index].sh_link].sh_link].sh_offset;
  151. nr_reloc = (rt_ubase_t)(shdr[index].sh_size / sizeof(Elf_Rel));
  152. /* relocate every items */
  153. for (i = 0; i < nr_reloc; i ++)
  154. {
  155. #if (defined(__arm__) || defined(__i386__) || (__riscv_xlen == 32))
  156. Elf_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)];
  157. #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64))
  158. Elf_Sym *sym = &symtab[ELF64_R_SYM(rel->r_info)];
  159. #endif
  160. LOG_D("relocate symbol %s shndx %d", strtab + sym->st_name, sym->st_shndx);
  161. if ((sym->st_shndx != SHT_NULL) ||(ELF_ST_BIND(sym->st_info) == STB_LOCAL))
  162. {
  163. Elf_Addr addr;
  164. addr = (Elf_Addr)(module->mem_space + sym->st_value - vstart_addr);
  165. dlmodule_relocate(module, rel, addr);
  166. }
  167. else if (!linked)
  168. {
  169. Elf_Addr addr;
  170. LOG_D("relocate symbol: %s", strtab + sym->st_name);
  171. /* need to resolve symbol in kernel symbol table */
  172. addr = dlmodule_symbol_find((const char *)(strtab + sym->st_name));
  173. if (addr == 0)
  174. {
  175. LOG_E("Module: can't find %s in kernel symbol table", strtab + sym->st_name);
  176. unsolved = RT_TRUE;
  177. }
  178. else
  179. {
  180. dlmodule_relocate(module, rel, addr);
  181. }
  182. }
  183. rel ++;
  184. }
  185. if (unsolved)
  186. return -RT_ERROR;
  187. }
  188. /* construct module symbol table */
  189. for (index = 0; index < elf_module->e_shnum; index ++)
  190. {
  191. /* find .dynsym section */
  192. rt_uint8_t *shstrab;
  193. shstrab = (rt_uint8_t *)module_ptr +
  194. shdr[elf_module->e_shstrndx].sh_offset;
  195. if (rt_strcmp((const char *)(shstrab + shdr[index].sh_name), ELF_DYNSYM) == 0)
  196. break;
  197. }
  198. /* found .dynsym section */
  199. if (index != elf_module->e_shnum)
  200. {
  201. int i, count = 0;
  202. Elf_Sym *symtab = RT_NULL;
  203. rt_uint8_t *strtab = RT_NULL;
  204. symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
  205. strtab = (rt_uint8_t *)module_ptr + shdr[shdr[index].sh_link].sh_offset;
  206. for (i = 0; i < shdr[index].sh_size / sizeof(Elf_Sym); i++)
  207. {
  208. if ((ELF_ST_BIND(symtab[i].st_info) == STB_GLOBAL) &&
  209. (ELF_ST_TYPE(symtab[i].st_info) == STT_FUNC))
  210. count ++;
  211. }
  212. module->symtab = (struct rt_module_symtab *)rt_malloc
  213. (count * sizeof(struct rt_module_symtab));
  214. module->nsym = count;
  215. for (i = 0, count = 0; i < shdr[index].sh_size / sizeof(Elf_Sym); i++)
  216. {
  217. rt_size_t length;
  218. if ((ELF_ST_BIND(symtab[i].st_info) != STB_GLOBAL) ||
  219. (ELF_ST_TYPE(symtab[i].st_info) != STT_FUNC))
  220. continue;
  221. length = rt_strlen((const char *)(strtab + symtab[i].st_name)) + 1;
  222. module->symtab[count].addr =
  223. (void *)(module->mem_space + symtab[i].st_value - module->vstart_addr);
  224. module->symtab[count].name = rt_malloc(length);
  225. rt_memset((void *)module->symtab[count].name, 0, length);
  226. rt_memcpy((void *)module->symtab[count].name,
  227. strtab + symtab[i].st_name,
  228. length);
  229. count ++;
  230. }
  231. /* get priority & stack size params*/
  232. rt_uint32_t flag = 0;
  233. rt_uint16_t priority;
  234. rt_uint32_t stacksize;
  235. for (i = 0; i < shdr[index].sh_size / sizeof(Elf_Sym); i++)
  236. {
  237. if (((flag & 0x01) == 0) &&
  238. (rt_strcmp((const char *)(strtab + symtab[i].st_name), "dlmodule_thread_priority") == 0))
  239. {
  240. flag |= 0x01;
  241. priority = *(rt_uint16_t*)(module->mem_space + symtab[i].st_value - module->vstart_addr);
  242. if (priority < RT_THREAD_PRIORITY_MAX)
  243. {
  244. module->priority = priority;
  245. }
  246. }
  247. if (((flag & 0x02) == 0) &&
  248. (rt_strcmp((const char *)(strtab + symtab[i].st_name), "dlmodule_thread_stacksize") == 0))
  249. {
  250. flag |= 0x02;
  251. stacksize = *(rt_uint32_t*)(module->mem_space + symtab[i].st_value - module->vstart_addr);
  252. if ((stacksize < 2048) || (stacksize > 1024 * 32))
  253. {
  254. module->stack_size = stacksize;
  255. }
  256. }
  257. if ((flag & 0x03) == 0x03)
  258. {
  259. break;
  260. }
  261. }
  262. }
  263. return RT_EOK;
  264. }
  265. /**
  266. * @brief Load a relocatable file into memory.
  267. *
  268. * @param module A pointer to a rt_dlmodule object for holding the module's information.
  269. * @param module_ptr A pointer to the raw memory of the ELF file (relocatable file) that is being loaded.
  270. * @return rt_err_t On success, it returns RT_EOK. Otherwise, it returns the error code.
  271. *
  272. * @note This function loads a relocatable file (ELF file) into memory, broken down step by step:
  273. * 1. Calculate Module Size: iterates over the ELF sections (text, data, rodata, and bss) to calculate the total size of the module
  274. * and identifies the start address for each section.
  275. * 2. Allocate Memory: It allocates memory for the module based on the calculated size. If allocation fails, an error is returned.
  276. * 3. Load Sections into Memory: The function loads the text, rodata, data, and BSS sections into the allocated memory.
  277. * The BSS section is zeroed out, while the others are copied from the ELF image.
  278. * 4. Set Entry Point: The entry point of the module is set by calculating the address relative to the start of the allocated memory.
  279. * 5. Handle Relocation: It processes the relocation entries, resolving symbol addresses and relocating them as needed.
  280. * This includes functions, sections (rodata, bss, data), and external symbols from the kernel symbol table.
  281. */
  282. rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module_ptr)
  283. {
  284. rt_ubase_t index, rodata_addr = 0, bss_addr = 0, data_addr = 0;
  285. rt_ubase_t module_addr = 0, module_size = 0;
  286. rt_uint8_t *ptr, *strtab, *shstrab;
  287. /* get the ELF image size */
  288. for (index = 0; index < elf_module->e_shnum; index ++)
  289. {
  290. /* text */
  291. if (IS_PROG(shdr[index]) && IS_AX(shdr[index]))
  292. {
  293. module_size += shdr[index].sh_size;
  294. module_addr = shdr[index].sh_addr;
  295. }
  296. /* rodata */
  297. if (IS_PROG(shdr[index]) && IS_ALLOC(shdr[index]))
  298. {
  299. module_size += shdr[index].sh_size;
  300. }
  301. /* data */
  302. if (IS_PROG(shdr[index]) && IS_AW(shdr[index]))
  303. {
  304. module_size += shdr[index].sh_size;
  305. }
  306. /* bss */
  307. if (IS_NOPROG(shdr[index]) && IS_AW(shdr[index]))
  308. {
  309. module_size += shdr[index].sh_size;
  310. }
  311. }
  312. /* no text, data and bss on image */
  313. if (module_size == 0) return RT_NULL;
  314. module->vstart_addr = 0;
  315. /* allocate module space */
  316. module->mem_space = rt_malloc(module_size);
  317. if (module->mem_space == RT_NULL)
  318. {
  319. LOG_E("Module: allocate space failed.\n");
  320. return -RT_ERROR;
  321. }
  322. module->mem_size = module_size;
  323. /* zero all space */
  324. ptr = module->mem_space;
  325. rt_memset(ptr, 0, module_size);
  326. /* load text and data section */
  327. for (index = 0; index < elf_module->e_shnum; index ++)
  328. {
  329. /* load text section */
  330. if (IS_PROG(shdr[index]) && IS_AX(shdr[index]))
  331. {
  332. rt_memcpy(ptr,
  333. (rt_uint8_t *)elf_module + shdr[index].sh_offset,
  334. shdr[index].sh_size);
  335. LOG_D("load text 0x%x, size %d", ptr, shdr[index].sh_size);
  336. ptr += shdr[index].sh_size;
  337. }
  338. /* load rodata section */
  339. if (IS_PROG(shdr[index]) && IS_ALLOC(shdr[index]))
  340. {
  341. rt_memcpy(ptr,
  342. (rt_uint8_t *)elf_module + shdr[index].sh_offset,
  343. shdr[index].sh_size);
  344. rodata_addr = (rt_ubase_t)ptr;
  345. LOG_D("load rodata 0x%x, size %d, rodata 0x%x", ptr,
  346. shdr[index].sh_size, *(rt_ubase_t *)rodata_addr);
  347. ptr += shdr[index].sh_size;
  348. }
  349. /* load data section */
  350. if (IS_PROG(shdr[index]) && IS_AW(shdr[index]))
  351. {
  352. rt_memcpy(ptr,
  353. (rt_uint8_t *)elf_module + shdr[index].sh_offset,
  354. shdr[index].sh_size);
  355. data_addr = (rt_ubase_t)ptr;
  356. LOG_D("load data 0x%x, size %d, data 0x%x", ptr,
  357. shdr[index].sh_size, *(rt_ubase_t *)data_addr);
  358. ptr += shdr[index].sh_size;
  359. }
  360. /* load bss section */
  361. if (IS_NOPROG(shdr[index]) && IS_AW(shdr[index]))
  362. {
  363. rt_memset(ptr, 0, shdr[index].sh_size);
  364. bss_addr = (rt_ubase_t)ptr;
  365. LOG_D("load bss 0x%x, size %d", ptr, shdr[index].sh_size);
  366. }
  367. }
  368. /* set module entry */
  369. module->entry_addr = (rt_dlmodule_entry_func_t)((rt_uint8_t *)module->mem_space + elf_module->e_entry - module_addr);
  370. /* handle relocation section */
  371. for (index = 0; index < elf_module->e_shnum; index ++)
  372. {
  373. rt_ubase_t i, nr_reloc;
  374. Elf_Sym *symtab;
  375. Elf_Rel *rel;
  376. #if (defined(__arm__) || defined(__i386__) || (__riscv_xlen == 32))
  377. if (!IS_REL(shdr[index]))
  378. continue;
  379. #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64))
  380. if (!IS_RELA(shdr[index]))
  381. continue;
  382. #endif
  383. /* get relocate item */
  384. rel = (Elf_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
  385. /* locate .dynsym and .dynstr */
  386. symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr +
  387. shdr[shdr[index].sh_link].sh_offset);
  388. strtab = (rt_uint8_t *)module_ptr +
  389. shdr[shdr[shdr[index].sh_link].sh_link].sh_offset;
  390. shstrab = (rt_uint8_t *)module_ptr +
  391. shdr[elf_module->e_shstrndx].sh_offset;
  392. nr_reloc = (rt_uint32_t)(shdr[index].sh_size / sizeof(Elf_Rel));
  393. /* relocate every items */
  394. for (i = 0; i < nr_reloc; i ++)
  395. {
  396. #if (defined(__arm__) || defined(__i386__) || (__riscv_xlen == 32))
  397. Elf_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)];
  398. #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64))
  399. Elf_Sym *sym = &symtab[ELF64_R_SYM(rel->r_info)];
  400. #endif
  401. LOG_D("relocate symbol: %s", strtab + sym->st_name);
  402. if (sym->st_shndx != STN_UNDEF)
  403. {
  404. Elf_Addr addr = 0;
  405. if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) ||
  406. (ELF_ST_TYPE(sym->st_info) == STT_OBJECT))
  407. {
  408. if (rt_strncmp((const char *)(shstrab +
  409. shdr[sym->st_shndx].sh_name), ELF_RODATA, 8) == 0)
  410. {
  411. /* relocate rodata section */
  412. LOG_D("rodata");
  413. addr = (Elf_Addr)(rodata_addr + sym->st_value);
  414. }
  415. else if (rt_strncmp((const char *)
  416. (shstrab + shdr[sym->st_shndx].sh_name), ELF_BSS, 5) == 0)
  417. {
  418. /* relocate bss section */
  419. LOG_D("bss");
  420. addr = (Elf_Addr)bss_addr + sym->st_value;
  421. }
  422. else if (rt_strncmp((const char *)(shstrab + shdr[sym->st_shndx].sh_name),
  423. ELF_DATA, 6) == 0)
  424. {
  425. /* relocate data section */
  426. LOG_D("data");
  427. addr = (Elf_Addr)data_addr + sym->st_value;
  428. }
  429. if (addr != 0) dlmodule_relocate(module, rel, addr);
  430. }
  431. else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
  432. {
  433. addr = (Elf_Addr)((rt_uint8_t *) module->mem_space - module_addr + sym->st_value);
  434. /* relocate function */
  435. dlmodule_relocate(module, rel, addr);
  436. }
  437. }
  438. else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
  439. {
  440. /* relocate function */
  441. dlmodule_relocate(module, rel,
  442. (Elf_Addr)((rt_uint8_t *)
  443. module->mem_space
  444. - module_addr
  445. + sym->st_value));
  446. }
  447. else
  448. {
  449. Elf_Addr addr;
  450. if (ELF32_R_TYPE(rel->r_info) != R_ARM_V4BX)
  451. {
  452. LOG_D("relocate symbol: %s", strtab + sym->st_name);
  453. /* need to resolve symbol in kernel symbol table */
  454. addr = dlmodule_symbol_find((const char *)(strtab + sym->st_name));
  455. if (addr != (Elf_Addr)RT_NULL)
  456. {
  457. dlmodule_relocate(module, rel, addr);
  458. LOG_D("symbol addr 0x%x", addr);
  459. }
  460. else
  461. LOG_E("Module: can't find %s in kernel symbol table",
  462. strtab + sym->st_name);
  463. }
  464. else
  465. {
  466. addr = (Elf_Addr)((rt_uint8_t *) module->mem_space - module_addr + sym->st_value);
  467. dlmodule_relocate(module, rel, addr);
  468. }
  469. }
  470. rel ++;
  471. }
  472. }
  473. return RT_EOK;
  474. }