lwp_elf.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. /*
  2. * Copyright (c) 2006-2025 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-08-23 zhangsz first version
  9. */
  10. #include <rtthread.h>
  11. #ifdef RT_USING_LDSO
  12. #include <dfs_file.h>
  13. #include <unistd.h>
  14. #include <stdio.h>
  15. #include <fcntl.h>
  16. #include <lwp_elf.h>
  17. #include "lwp.h"
  18. #include "lwp_arch.h"
  19. #ifdef ARCH_MM_MMU
  20. #include <lwp_user_mm.h>
  21. #endif
  22. #ifdef RT_USING_VDSO
  23. #include <vdso.h>
  24. #endif
  25. #define DBG_TAG "load.elf"
  26. #ifdef ELF_DEBUG_ENABLE
  27. #define DBG_LVL DBG_LOG
  28. #else
  29. #define DBG_LVL DBG_INFO
  30. #endif
  31. #include <rtdbg.h>
  32. #define ELF_INVALID_FD -1
  33. #define ELF_PHDR_NUM_MAX 128
  34. #define FILE_LENGTH_MAX 0xC0000000
  35. #define MEM_SIZE_MAX 0xC0000000
  36. #define ELF_PATH_MAX 256
  37. #define FLF_PATH_MIN 1
  38. #define ELF_PAGESTART(_v) ((_v) & ~(rt_ubase_t)(ARCH_PAGE_SIZE - 1))
  39. #define ELF_PAGEOFFSET(_v) ((_v) & (ARCH_PAGE_SIZE - 1))
  40. #define ELF_PAGEALIGN(_v) (((_v) + ARCH_PAGE_SIZE - 1) & ~(ARCH_PAGE_SIZE - 1))
  41. #define ELF_EXEC_LOAD_ADDR USER_VADDR_START
  42. #define ELF_INTERP_LOAD_ADDR LDSO_LOAD_VADDR
  43. #define ELF_AUX_ENT(aux, id, val) \
  44. do \
  45. { \
  46. rt_base_t a = id; \
  47. lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \
  48. a = val; \
  49. lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \
  50. } while (0)
  51. /**
  52. * @brief Structure to hold information about an ELF file.
  53. *
  54. */
  55. typedef struct
  56. {
  57. int fd; /* File descriptor for the ELF file */
  58. char *filename; /* Path to the ELF file */
  59. rt_size_t file_len; /* Length of the ELF file */
  60. Elf_Ehdr ehdr; /* ELF header */
  61. Elf_Phdr *phdr; /* Pointer to the program header table */
  62. rt_ubase_t map_size; /* Total size required for memory mapping */
  63. } elf_info_t;
  64. /**
  65. * @brief Structure to hold information about an ELF executable and its interpreter.
  66. */
  67. typedef struct
  68. {
  69. struct rt_lwp *lwp; /* Pointer to the Light Weight Process (LWP) structure */
  70. struct process_aux *aux; /* Pointer to auxiliary process information */
  71. elf_info_t exec_info; /* Information about the main ELF executable */
  72. elf_info_t interp_info; /* Information about the ELF interpreter (if any) */
  73. rt_ubase_t load_addr; /* Base address where the ELF is loaded */
  74. rt_ubase_t e_entry; /* Entry point address of the ELF */
  75. rt_ubase_t interp_base; /* Base address of the interpreter */
  76. } elf_load_info_t;
  77. /**
  78. * @brief Dump the contents of a user-space memory region for debugging.
  79. *
  80. * This function reads and prints the contents of a specified user-space memory region
  81. * in hexadecimal format. It is primarily used for debugging ELF loading and execution.
  82. *
  83. * @param lwp Pointer to the Light Weight Process (LWP) structure.
  84. * @param va Virtual address of the memory region to dump.
  85. * @param len Length of the memory region to dump.
  86. */
  87. static void elf_user_dump(struct rt_lwp *lwp, void *va, size_t len)
  88. {
  89. #ifdef ELF_DEBUG_DUMP
  90. uint8_t *k_va;
  91. int ret;
  92. if (len < 16)
  93. len = 16;
  94. rt_kprintf("\r\n");
  95. rt_kprintf("%s : user va : %p, len : 0x%x(%d)\n", __func__, va, len, len);
  96. k_va = rt_malloc(len);
  97. if (k_va == RT_NULL)
  98. {
  99. rt_kprintf("%s : malloc failed\n", __func__);
  100. return;
  101. }
  102. rt_memset(k_va, 0, len);
  103. ret = lwp_data_get(lwp, k_va, va, len);
  104. if (ret != len)
  105. {
  106. rt_kprintf("%s : lwp_get_from_user failed, ret = %d\n", __func__, ret);
  107. return;
  108. }
  109. rt_kprintf("%s : k_va : %p\n", __func__, k_va);
  110. for (size_t i = 0; i < len; i += 16)
  111. {
  112. rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x ", k_va[i], k_va[i+1], k_va[i+2], k_va[i+3],
  113. k_va[i+4], k_va[i+5], k_va[i+6], k_va[i+7]);
  114. rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x \n", k_va[i+8], k_va[i+9], k_va[i+10], k_va[i+11],
  115. k_va[i+12], k_va[i+13], k_va[i+14], k_va[i+15]);
  116. }
  117. rt_kprintf("\r\n");
  118. rt_free(k_va);
  119. #endif
  120. }
  121. /**
  122. * @brief Generate a random offset for ELF loading.
  123. *
  124. * @return Random offset aligned to page size.
  125. */
  126. rt_ubase_t elf_random_offset(void)
  127. {
  128. #ifdef ELF_LOAD_RANDOMIZE
  129. return (rt_tick_get() % 65535) * ARCH_PAGE_SIZE;
  130. #else
  131. return ELF_PAGEALIGN(0);
  132. #endif
  133. }
  134. /**
  135. * @brief Map a file into the process's address space.
  136. *
  137. * This function maps a file into the process's virtual memory using the specified
  138. * address, size, protection flags, and offset. It ensures the mapping is properly
  139. * aligned and verifies the mapping operation.
  140. *
  141. * @param lwp Pointer to the Light Weight Process (LWP) structure.
  142. * @param fd File descriptor of the file to map.
  143. * @param load_addr Desired virtual address for mapping.
  144. * @param map_size Size of the memory mapping.
  145. * @param prot Memory protection flags (e.g., PROT_READ, PROT_WRITE).
  146. * @param flags Mapping flags (e.g., MAP_FIXED, MAP_PRIVATE).
  147. * @param offset File offset where mapping should begin.
  148. *
  149. * @return Virtual address where the file is mapped on success, NULL on failure.
  150. */
  151. static void *file_mmap(struct rt_lwp *lwp, int fd, rt_ubase_t load_addr,
  152. rt_ubase_t map_size, size_t prot, size_t flags, rt_ubase_t offset)
  153. {
  154. uint8_t *map_va;
  155. map_va = (uint8_t *)lwp_mmap2(lwp, (void *)load_addr, map_size, prot, flags, fd, offset >> ARCH_PAGE_SHIFT);
  156. if (!map_va || (map_va != (uint8_t *)load_addr))
  157. {
  158. LOG_E("%s : lwp map user failed!", __func__);
  159. return RT_NULL;
  160. }
  161. LOG_D(" %s : map va = %p load_addr : %p size : 0x%x", __func__, map_va, load_addr, map_size);
  162. return map_va;
  163. }
  164. static int elf_file_open(const char *filename)
  165. {
  166. int fd = -1;
  167. fd = open(filename, O_BINARY | O_RDONLY, 0);
  168. if (fd < 0)
  169. {
  170. LOG_E("%s : elf file [%s] open failed!", __func__, filename);
  171. }
  172. return fd;
  173. }
  174. static int elf_file_close(int fd)
  175. {
  176. return close(fd);
  177. }
  178. /**
  179. * @brief Get the length of an ELF file.
  180. *
  181. * @param filename Path to the ELF file.
  182. * @param file_len Pointer to store the file length.
  183. * @return RT_EOK on success, -RT_ERROR on failure.
  184. */
  185. static int elf_file_length(char *filename, rt_size_t *file_len)
  186. {
  187. int ret;
  188. struct stat s = { 0 };
  189. ret = stat(filename, &s);
  190. if (ret != 0)
  191. {
  192. LOG_E("%s : error", __func__);
  193. return -RT_ERROR;
  194. }
  195. *file_len = (rt_size_t)s.st_size;
  196. return RT_EOK;
  197. }
  198. /**
  199. * @brief Read data from an ELF file at a specific offset.
  200. *
  201. * @param fd File descriptor of the ELF file.
  202. * @param buffer Pointer to the buffer where the read data will be stored.
  203. * @param size Number of bytes to read.
  204. * @param offset File offset where reading should begin.
  205. * @return RT_EOK on success, -RT_ERROR if seek or read operations fail.
  206. */
  207. static int elf_file_read(rt_int32_t fd, rt_uint8_t *buffer, size_t size, off_t offset)
  208. {
  209. ssize_t read_len;
  210. off_t pos;
  211. if (size > 0)
  212. {
  213. pos = lseek(fd, offset, SEEK_SET);
  214. if (pos != offset)
  215. {
  216. LOG_E("%s : seek file offset: 0x%x failed", __func__, offset);
  217. return -RT_ERROR;
  218. }
  219. read_len = read(fd, buffer, size);
  220. if (read_len != size)
  221. {
  222. LOG_E("%s : read from offset: 0x%x error", __func__, offset);
  223. return -RT_ERROR;
  224. }
  225. }
  226. return RT_EOK;
  227. }
  228. /**
  229. * @brief Validate an ELF header.
  230. *
  231. * @param ehdr Pointer to the ELF header to validate.
  232. * @param file_len Length of the ELF file.
  233. * @return RT_EOK if valid, -RT_ERROR if invalid.
  234. */
  235. static rt_int32_t elf_check_ehdr(const Elf_Ehdr *ehdr, rt_uint32_t file_len)
  236. {
  237. if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
  238. {
  239. LOG_E("%s : e_ident error", __func__);
  240. return -RT_ERROR;
  241. }
  242. if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN))
  243. {
  244. LOG_E("%s : e_type error", __func__);
  245. return -RT_ERROR;
  246. }
  247. if (ehdr->e_machine == EM_NONE)
  248. {
  249. LOG_E("%s : e_machine is EM_NONE", __func__);
  250. return -RT_ERROR;
  251. }
  252. if (ehdr->e_phnum > ELF_PHDR_NUM_MAX)
  253. {
  254. LOG_E("%s : e_phnum error", __func__);
  255. return -RT_ERROR;
  256. }
  257. if (ehdr->e_phoff > file_len)
  258. {
  259. LOG_E("%s : e_phoff error", __func__);
  260. return -RT_ERROR;
  261. }
  262. LOG_D("%s : e_entry : 0x%x", __func__, ehdr->e_entry);
  263. return RT_EOK;
  264. }
  265. /**
  266. * @brief Validate an ELF program header.
  267. *
  268. * @param phdr Pointer to the ELF program header to validate.
  269. * @return RT_EOK if valid, -RT_ERROR if invalid.
  270. */
  271. static int elf_check_phdr(const Elf_Phdr *phdr)
  272. {
  273. if (phdr->p_filesz > FILE_LENGTH_MAX)
  274. {
  275. LOG_E("%s : phdr p_filesz 0x%x error", __func__, phdr->p_filesz);
  276. return -RT_ERROR;
  277. }
  278. if (phdr->p_offset > FILE_LENGTH_MAX)
  279. {
  280. LOG_E("%s : phdr p_offset 0x%x error", __func__, phdr->p_offset);
  281. return -RT_ERROR;
  282. }
  283. if (phdr->p_memsz > MEM_SIZE_MAX)
  284. {
  285. LOG_E("%s[%d], phdr p_memsz 0x%x error", __func__, phdr->p_memsz);
  286. return -RT_ERROR;
  287. }
  288. LOG_D("%s : phdr p_vaddr : 0x%x", __func__, phdr->p_vaddr);
  289. return RT_EOK;
  290. }
  291. /**
  292. * @brief Load and validate the ELF header from a file.
  293. *
  294. * This function opens the ELF file, reads its elf header, and performs basic validation
  295. * to ensure it's a valid ELF file. It also retrieves the file size and stores the
  296. * file descriptor for subsequent operations.
  297. *
  298. * @param elf_info Pointer to the ELF file information structure.
  299. * @return RT_EOK on success, -RT_ERROR on failure.
  300. */
  301. static int elf_load_ehdr(elf_info_t *elf_info)
  302. {
  303. int ret;
  304. ret = elf_file_open(elf_info->filename);
  305. if (ret < 0)
  306. {
  307. LOG_E("%s : elf_file_open %s failed", __func__, elf_info->filename);
  308. return ret;
  309. }
  310. elf_info->fd = ret;
  311. ret = elf_file_length(elf_info->filename, &elf_info->file_len);
  312. if (ret != RT_EOK)
  313. {
  314. return -RT_ERROR;
  315. }
  316. ret = elf_file_read(elf_info->fd, (rt_uint8_t *)&elf_info->ehdr, sizeof(Elf_Ehdr), 0);
  317. if (ret != RT_EOK)
  318. {
  319. LOG_E("%s : elf_file_read failed, ret : %d", __func__, ret);
  320. return -RT_ERROR;
  321. }
  322. ret = elf_check_ehdr(&elf_info->ehdr, elf_info->file_len);
  323. if (ret != RT_EOK)
  324. {
  325. LOG_E("%s : elf_check_ehdr failed, ret : %d", __func__, ret);
  326. return -RT_ERROR;
  327. }
  328. return RT_EOK;
  329. }
  330. /**
  331. * @brief Load the program header table from an ELF file.
  332. *
  333. * This function reads and validates the program header table from the ELF file.
  334. * It ensures the program header table is properly aligned and within the file bounds.
  335. *
  336. * @param elf_info Pointer to the ELF file information structure.
  337. * @return RT_EOK on success, -RT_ERROR on failure.
  338. */
  339. static int elf_load_phdr(elf_info_t *elf_info)
  340. {
  341. Elf_Ehdr *ehdr = &elf_info->ehdr;
  342. uint32_t size;
  343. int ret;
  344. if (ehdr->e_phnum < 1)
  345. {
  346. return -RT_ERROR;
  347. }
  348. if (ehdr->e_phentsize != sizeof(Elf_Phdr))
  349. {
  350. return -RT_ERROR;
  351. }
  352. size = sizeof(Elf_Phdr) * ehdr->e_phnum;
  353. if ((ehdr->e_phoff + size) > elf_info->file_len)
  354. {
  355. return -RT_ERROR;
  356. }
  357. elf_info->phdr = rt_malloc(size);
  358. if (elf_info->phdr == RT_NULL)
  359. {
  360. LOG_E("%s : alloc phdr failed", __func__);
  361. return -RT_ENOMEM;
  362. }
  363. ret = elf_file_read(elf_info->fd, (rt_uint8_t *)elf_info->phdr, size, ehdr->e_phoff);
  364. if (ret != RT_EOK)
  365. {
  366. rt_free(elf_info->phdr);
  367. elf_info->phdr = RT_NULL;
  368. LOG_E("%s : elf_file_read failed, ret = %d", __func__, ret);
  369. return -RT_ERROR;
  370. }
  371. return RT_EOK;
  372. }
  373. /**
  374. * @brief Load the ELF interpreter specified in the program header.
  375. *
  376. * This function searches for the PT_INTERP segment in the program headers,
  377. * validates its properties, and loads the interpreter's filename and
  378. * associated ELF information.
  379. *
  380. * @param load_info Pointer to the ELF loading context structure.
  381. * @return RT_EOK on success, -RT_ERROR on failure.
  382. */
  383. static int elf_load_interp(elf_load_info_t *load_info)
  384. {
  385. Elf_Phdr *phdr = load_info->exec_info.phdr;
  386. int ret;
  387. int i;
  388. for (i = 0; i < load_info->exec_info.ehdr.e_phnum; ++i, ++phdr)
  389. {
  390. if (phdr->p_type != PT_INTERP)
  391. {
  392. continue;
  393. }
  394. if (elf_check_phdr(phdr) != RT_EOK)
  395. {
  396. return -RT_ERROR;
  397. }
  398. if ((phdr->p_filesz > ELF_PATH_MAX) || (phdr->p_filesz < FLF_PATH_MIN))
  399. {
  400. LOG_E("%s : phdr p_filesz error", __func__, phdr->p_filesz);
  401. return -RT_ERROR;
  402. }
  403. if (phdr->p_offset + phdr->p_filesz > load_info->exec_info.file_len)
  404. {
  405. LOG_E("%s : phdr p_offset error", __func__, phdr->p_offset);
  406. return -RT_ERROR;
  407. }
  408. load_info->interp_info.filename = rt_malloc(phdr->p_filesz);
  409. if (load_info->interp_info.filename == RT_NULL)
  410. {
  411. LOG_E("%s : alloc elf interpreter failed", __func__);
  412. return -RT_ENOMEM;
  413. }
  414. ret = elf_file_read(load_info->exec_info.fd, (rt_uint8_t *)load_info->interp_info.filename,
  415. phdr->p_filesz, phdr->p_offset);
  416. if (ret != RT_EOK)
  417. {
  418. LOG_E("%s : elf_file_read failed, ret = %d", __func__, ret);
  419. ret = -RT_ERROR;
  420. goto error_exit;
  421. }
  422. if (load_info->interp_info.filename[phdr->p_filesz - 1] != '\0')
  423. {
  424. LOG_E("%s : elf interpreter is invalid", __func__);
  425. ret = -RT_ERROR;
  426. goto error_exit;
  427. }
  428. LOG_D("%s : elf interpreter : %s", __func__, load_info->interp_info.filename);
  429. ret = elf_load_ehdr(&load_info->interp_info);
  430. if (ret != RT_EOK)
  431. {
  432. LOG_E("%s : elf_load_ehdr failed, ret = %d", __func__, ret);
  433. goto error_exit;
  434. }
  435. ret = elf_load_phdr(&load_info->interp_info);
  436. if (ret != RT_EOK)
  437. {
  438. LOG_E("%s : elf_load_phdr failed, ret = %d", __func__, ret);
  439. goto error_exit;
  440. }
  441. break;
  442. }
  443. return RT_EOK;
  444. error_exit:
  445. return ret;
  446. }
  447. /**
  448. * @brief Calculate the total size required to map all loadable ELF segments.
  449. *
  450. * @param elf_info Pointer to the ELF file information structure.
  451. * @return 0 on success, -1 if no loadable segments are found.
  452. */
  453. static int total_mapping_size(elf_info_t *elf_info)
  454. {
  455. int i;
  456. int first_idx = -1;
  457. int last_idx = -1;
  458. for (i = 0; i < elf_info->ehdr.e_phnum; i++)
  459. {
  460. if (elf_info->phdr[i].p_type == PT_LOAD)
  461. {
  462. last_idx = i;
  463. if (first_idx == -1)
  464. first_idx = i;
  465. }
  466. }
  467. if (first_idx == -1)
  468. return -1;
  469. elf_info->map_size = elf_info->phdr[last_idx].p_vaddr + elf_info->phdr[last_idx].p_memsz -
  470. ELF_PAGESTART(elf_info->phdr[first_idx].p_vaddr);
  471. return 0;
  472. }
  473. /**
  474. * @brief Map an ELF segment into the process's address space.
  475. *
  476. * This function maps a specific ELF segment into the process's virtual memory space.
  477. * It handles page alignment, calculates the correct offset, and performs the actual
  478. * memory mapping operation.
  479. *
  480. * @param lwp Pointer to the Light Weight Process (LWP) structure.
  481. * @param elf_phdr Pointer to the ELF program header describing the segment.
  482. * @param fd File descriptor of the ELF file.
  483. * @param addr Desired virtual address for mapping.
  484. * @param prot Memory protection flags (e.g., PROT_READ, PROT_WRITE).
  485. * @param flags Mapping flags (e.g., MAP_FIXED, MAP_PRIVATE).
  486. * @param map_size Size of the memory mapping (0 for automatic calculation).
  487. *
  488. * @return Virtual address where the segment is mapped on success.
  489. * @return 0 on failure.
  490. */
  491. static rt_ubase_t elf_map(struct rt_lwp *lwp, const Elf_Phdr *elf_phdr, int fd, rt_ubase_t addr, size_t prot, size_t flags, rt_ubase_t map_size)
  492. {
  493. rt_ubase_t map_va = 0;
  494. rt_ubase_t va_offset;
  495. addr = ELF_PAGESTART(addr);
  496. va_offset = elf_phdr->p_offset - ELF_PAGEOFFSET(elf_phdr->p_vaddr);
  497. rt_ubase_t size;
  498. if (map_size != 0)
  499. {
  500. size = map_size;
  501. }
  502. else
  503. {
  504. size = elf_phdr->p_memsz + ELF_PAGEOFFSET(elf_phdr->p_vaddr);
  505. if (size == 0)
  506. {
  507. return addr;
  508. }
  509. }
  510. map_va = (rt_ubase_t)file_mmap(lwp, fd, addr, size, prot, flags, va_offset);
  511. return map_va;
  512. }
  513. static int elf_zero_bss(struct rt_lwp *lwp, int fd, const Elf_Phdr *phdr, rt_ubase_t bss_start,
  514. rt_ubase_t bss_end)
  515. {
  516. lwp_data_set(lwp, (void *)bss_start, 0, bss_end - bss_start);
  517. return RT_EOK;
  518. }
  519. /**
  520. * @brief Map ELF segments into memory.
  521. *
  522. * This function maps the loadable segments of an ELF file into the process's address space.
  523. * It handles both executable and shared library files, manages BSS sections, and sets up
  524. * the load address and base address for dynamic libraries.
  525. *
  526. * @param load_info Pointer to the structure containing ELF loading context.
  527. * @param elf_info Pointer to the structure containing ELF file information.
  528. * @param elfload_addr Pointer to store the final load address of the ELF file.
  529. * @param map_size Size of the memory mapping (0 for automatic calculation).
  530. * @param load_base Base address for loading (used for position-independent code).
  531. *
  532. * @return RT_EOK on success.
  533. * @return -RT_ERROR if memory mapping fails.
  534. * @return -ENOMEM if memory allocation fails.
  535. */
  536. static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ubase_t *elfload_addr,
  537. rt_uint32_t map_size, rt_ubase_t *load_base)
  538. {
  539. int ret, i;
  540. rt_ubase_t map_va, bss_start, bss_end;
  541. Elf_Ehdr *ehdr = &elf_info->ehdr; /* ELF header */
  542. Elf_Phdr *phdr = elf_info->phdr; /* Program header array */
  543. const Elf_Phdr *tmp_phdr = phdr; /* Current program header */
  544. int fd = elf_info->fd; /* File descriptor for ELF file */
  545. rt_ubase_t load_addr; /* Calculated load address */
  546. size_t prot = PROT_READ | PROT_WRITE; /* Memory protection flags */
  547. size_t flags = MAP_FIXED | MAP_PRIVATE; /* Memory mapping flags */
  548. /* Iterate through all program headers */
  549. for (i = 0; i < ehdr->e_phnum; ++i, ++tmp_phdr)
  550. {
  551. /* Only process PT_LOAD segments (loadable segments) */
  552. if (tmp_phdr->p_type != PT_LOAD)
  553. {
  554. continue;
  555. }
  556. /* For executable files, validate the program header */
  557. if (ehdr->e_type == ET_EXEC)
  558. {
  559. if (elf_check_phdr(tmp_phdr) != RT_EOK)
  560. {
  561. LOG_E("%s : elf_check_phdr failed", __func__);
  562. return -RT_ERROR;
  563. }
  564. }
  565. load_addr = tmp_phdr->p_vaddr + *load_base;
  566. LOG_D("%s : p_vaddr : 0x%x, load_addr : 0x%x", __func__, tmp_phdr->p_vaddr, load_addr);
  567. /* When both the segment's virtual address and the load base are 0, the segment is loaded at any available
  568. address rather than a fixed one. This behavior is particularly useful for Position-Independent Code (PIC)
  569. or shared libraries. */
  570. if ((tmp_phdr->p_vaddr == 0) && (*load_base == 0))
  571. {
  572. flags &= ~MAP_FIXED;
  573. }
  574. /* Map the segment into memory */
  575. map_va = elf_map(load_info->lwp, tmp_phdr, fd, load_addr, prot, flags, map_size);
  576. if (!map_va)
  577. {
  578. LOG_E("%s : elf_map failed", __func__);
  579. return -ENOMEM;
  580. }
  581. map_size = 0;
  582. elf_user_dump(load_info->lwp, (void *)load_addr, 64);
  583. /* Handle BSS section (zero-initialized data) */
  584. if ((tmp_phdr->p_memsz > tmp_phdr->p_filesz) && (tmp_phdr->p_flags & PF_W))
  585. {
  586. bss_start = load_addr + tmp_phdr->p_filesz;
  587. bss_end = load_addr + tmp_phdr->p_memsz;
  588. ret = elf_zero_bss(load_info->lwp, fd, tmp_phdr, bss_start, bss_end);
  589. if (ret)
  590. {
  591. LOG_E("%s : elf_zero_bss error", __func__);
  592. return ret;
  593. }
  594. }
  595. if (*elfload_addr == 0)
  596. {
  597. *elfload_addr = map_va + ELF_PAGEOFFSET(tmp_phdr->p_vaddr);
  598. LOG_D("%s elf_load_addr : %p, vAddr : %p, load_base : %p, map_va : %p", __func__,
  599. *elfload_addr, tmp_phdr->p_vaddr, *load_base, map_va);
  600. }
  601. if ((*load_base == 0) && (ehdr->e_type == ET_DYN))
  602. {
  603. *load_base = map_va;
  604. }
  605. }
  606. return RT_EOK;
  607. }
  608. /**
  609. * @brief Load the ELF interpreter into memory.
  610. *
  611. * @param load_info Pointer to the ELF loading context.
  612. * @param interp_base Pointer to store the interpreter's base address.
  613. *
  614. * @return RT_EOK on success, -RT_ERROR on failure.
  615. */
  616. static int load_elf_interp(elf_load_info_t *load_info, rt_ubase_t *interp_base)
  617. {
  618. int ret;
  619. rt_ubase_t load_base = ELF_INTERP_LOAD_ADDR + elf_random_offset();
  620. ret = total_mapping_size(&load_info->interp_info);
  621. if (ret)
  622. {
  623. LOG_E("%s : total_mapping_size failed", __func__);
  624. return -RT_ERROR;
  625. }
  626. LOG_D("%s : total_mapping_size 0x%x", __func__, load_info->interp_info.map_size);
  627. return elf_file_mmap(load_info, &load_info->interp_info, interp_base,
  628. load_info->interp_info.map_size, &load_base);
  629. }
  630. /**
  631. * @brief Populate the auxiliary vector for an ELF-loaded process.
  632. *
  633. * This function sets up the auxiliary vector that provides essential information
  634. * to the ELF executable about the runtime environment. It includes information
  635. * about page size, program headers, entry point, and other system-specific details.
  636. *
  637. * @param load_info Pointer to the structure containing ELF loading information.
  638. *
  639. * @return 0 on success, -1 if the auxiliary structure is invalid, or -RT_ERROR
  640. * if memory mapping fails.
  641. *
  642. * @note The auxiliary vector is crucial for proper initialization of the ELF
  643. * executable and its interaction with the runtime environment.
  644. */
  645. static int elf_aux_fill(elf_load_info_t *load_info)
  646. {
  647. uint8_t *random;
  648. struct process_aux *aux = load_info->aux;
  649. elf_addr_t *aux_info;
  650. uint32_t random_value = rt_tick_get();
  651. size_t prot = PROT_READ | PROT_WRITE;
  652. size_t flags = MAP_FIXED | MAP_PRIVATE;
  653. rt_lwp_t lwp = load_info->lwp;
  654. void *va;
  655. if (!aux)
  656. {
  657. LOG_E("%s : aux is null", __func__);
  658. return -1;
  659. }
  660. aux_info = (elf_addr_t *)aux->item;
  661. ELF_AUX_ENT(aux_info, AT_PAGESZ, ARCH_PAGE_SIZE);
  662. va = lwp_mmap2(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), ARCH_PAGE_SIZE, prot, flags, -1, 0);
  663. if (!va)
  664. {
  665. LOG_E("lwp map user failed!");
  666. return -RT_ERROR;
  667. }
  668. random = (uint8_t *)(USER_VADDR_TOP - ARCH_PAGE_SIZE - sizeof(char[16]));
  669. lwp_data_put(load_info->lwp, random, &random_value, sizeof(random_value));
  670. ELF_AUX_ENT(aux_info, AT_RANDOM, (size_t)random);
  671. ELF_AUX_ENT(aux_info, AT_PHDR, (size_t)load_info->load_addr + load_info->exec_info.ehdr.e_phoff);
  672. ELF_AUX_ENT(aux_info, AT_PHNUM, (size_t)load_info->exec_info.ehdr.e_phnum);
  673. ELF_AUX_ENT(aux_info, AT_PHENT, sizeof(Elf_Phdr));
  674. ELF_AUX_ENT(aux_info, AT_BASE, load_info->interp_base);
  675. ELF_AUX_ENT(aux_info, AT_FLAGS, 0);
  676. ELF_AUX_ENT(aux_info, AT_ENTRY, load_info->exec_info.ehdr.e_entry);
  677. ELF_AUX_ENT(aux_info, AT_UID, 0);
  678. ELF_AUX_ENT(aux_info, AT_EUID, 0);
  679. ELF_AUX_ENT(aux_info, AT_GID, 0);
  680. ELF_AUX_ENT(aux_info, AT_EGID, 0);
  681. ELF_AUX_ENT(aux_info, AT_HWCAP, 0);
  682. ELF_AUX_ENT(aux_info, AT_CLKTCK, 0);
  683. ELF_AUX_ENT(aux_info, AT_SECURE, 0);
  684. #ifdef RT_USING_VDSO
  685. if(RT_EOK == arch_setup_additional_pages(load_info->lwp))
  686. {
  687. ELF_AUX_ENT(aux_info, AT_SYSINFO_EHDR, (size_t)load_info->lwp->vdso_vbase);
  688. }
  689. else
  690. {
  691. LOG_W("vdso map error,VDSO currently only supports aarch64 architecture!");
  692. }
  693. #endif
  694. return 0;
  695. }
  696. /**
  697. * @brief Load the segments of an ELF file into memory.
  698. *
  699. * This function is responsible for loading the segments of an ELF file into memory,
  700. * including handling dynamic libraries and setting up the entry point for execution.
  701. *
  702. * @param load_info Pointer to the structure containing ELF loading information.
  703. * @return RT_EOK if the segments are successfully loaded and prepared for execution.
  704. * @return -RT_ERROR if any error occurs during the loading process, including:
  705. * - Memory allocation failure
  706. * - File mapping errors
  707. * - Interpreter loading errors
  708. */
  709. static int elf_load_segment(elf_load_info_t *load_info)
  710. {
  711. int ret;
  712. rt_ubase_t app_load_base = 0; /* Base address for loading the application. */
  713. load_info->load_addr = 0; /* Load address for the ELF file. */
  714. load_info->interp_base = 0; /* Base address for loading the interpreter. */
  715. load_info->exec_info.map_size = 0; /* Total size of the mapped segments. */
  716. if (load_info->exec_info.ehdr.e_type == ET_DYN)
  717. {
  718. ret = total_mapping_size(&load_info->exec_info);
  719. if (ret)
  720. {
  721. LOG_E("%s : total_mapping_size failed", __func__);
  722. return -RT_ERROR;
  723. }
  724. LOG_D("%s : map_size : 0x%x", __func__, load_info->exec_info.map_size);
  725. /* Calculate the base address for loading the ELF file by adding a random offset to the default load address.
  726. This randomization enhances security by making it harder for attackers to predict the memory layout. */
  727. app_load_base = ELF_EXEC_LOAD_ADDR + elf_random_offset();
  728. }
  729. /* Map the segments of the ELF file into memory */
  730. ret = elf_file_mmap(load_info, &load_info->exec_info, &load_info->load_addr,
  731. load_info->exec_info.map_size, &app_load_base);
  732. elf_file_close(load_info->exec_info.fd);
  733. if (ret != RT_EOK)
  734. {
  735. LOG_W("%s : elf_file_close exec failed", __func__);
  736. }
  737. load_info->exec_info.fd = ELF_INVALID_FD;
  738. if (load_info->interp_info.fd != ELF_INVALID_FD)
  739. {
  740. ret = load_elf_interp(load_info, &load_info->interp_base); /* load the interpreter */
  741. if (ret)
  742. {
  743. LOG_E("%s : load_elf_interp failed, ret = %d", __func__, ret);
  744. return ret;
  745. }
  746. elf_file_close(load_info->interp_info.fd);
  747. if (ret != RT_EOK)
  748. {
  749. LOG_W("%s : elf_file_close interp failed, ret = %d", __func__, ret);
  750. }
  751. load_info->interp_info.fd = ELF_INVALID_FD;
  752. /* if a interpreter exist, first jump to the interpreter's entry to handle dynamic libs' loading. */
  753. load_info->e_entry = load_info->interp_info.ehdr.e_entry + load_info->interp_base;
  754. load_info->exec_info.ehdr.e_entry = load_info->exec_info.ehdr.e_entry + app_load_base; /* Update the ELF file's entry address by adding the base address. */
  755. }
  756. else
  757. {
  758. /* If there is no interpreter, use the ELF file's entry address directly. */
  759. load_info->e_entry = load_info->exec_info.ehdr.e_entry;
  760. }
  761. load_info->lwp->text_entry = (void *)load_info->e_entry;
  762. LOG_D("%s : lwp->text_entry : %p loadaddr : %p", __func__, load_info->lwp->text_entry, app_load_base);
  763. /* Debug information: dump user space data. */
  764. elf_user_dump(load_info->lwp, load_info->lwp->text_entry, 64);
  765. /* Fill auxiliary information. */
  766. ret = elf_aux_fill(load_info);
  767. if (ret)
  768. {
  769. LOG_E("%s : elf_aux_fill failed", __func__);
  770. return ret;
  771. }
  772. return RT_EOK;
  773. }
  774. /**
  775. * @brief Clean up resources allocated during ELF loading.
  776. *
  777. * This function releases all resources (file descriptors, memory, etc.) that were
  778. * allocated during the ELF loading process. It ensures that no memory leaks occur
  779. * and all file descriptors are properly closed.
  780. *
  781. * @param load_info Pointer to the structure containing ELF loading information.
  782. */
  783. static void elf_load_deinit(elf_load_info_t *load_info)
  784. {
  785. if (load_info->exec_info.fd != ELF_INVALID_FD)
  786. {
  787. elf_file_close(load_info->exec_info.fd);
  788. }
  789. if (load_info->interp_info.fd != ELF_INVALID_FD)
  790. {
  791. elf_file_close(load_info->interp_info.fd);
  792. }
  793. if (load_info->exec_info.phdr != RT_NULL)
  794. {
  795. rt_free(load_info->exec_info.phdr);
  796. }
  797. if (load_info->exec_info.filename != RT_NULL)
  798. {
  799. rt_free(load_info->exec_info.filename);
  800. }
  801. if (load_info->interp_info.phdr != RT_NULL)
  802. {
  803. rt_free(load_info->interp_info.phdr);
  804. }
  805. if (load_info->interp_info.filename != RT_NULL)
  806. {
  807. rt_free(load_info->interp_info.filename);
  808. }
  809. }
  810. /**
  811. * @brief Load the ELF header and program header information.
  812. *
  813. * @param exec_info Pointer to the elf_info_t structure containing elf file information.
  814. *
  815. * @return RT_EOK if the ELF header and program header information are successfully loaded.
  816. * @return -RT_ERROR if any error occurs during the loading process.
  817. */
  818. static int elf_load_app(elf_info_t *exec_info)
  819. {
  820. int ret;
  821. /* load elf header */
  822. ret = elf_load_ehdr(exec_info);
  823. if (ret != RT_EOK)
  824. {
  825. return ret;
  826. }
  827. /* load the ELF program header */
  828. ret = elf_load_phdr(exec_info);
  829. if (ret != RT_EOK)
  830. {
  831. return ret;
  832. }
  833. return ret;
  834. }
  835. /**
  836. * @brief Load an ELF file into memory.
  837. *
  838. * @param load_info Pointer to the elf_load_info_t structure containing information about the ELF file.
  839. *
  840. * @return RT_EOK if the ELF file is successfully loaded.
  841. * @return -RT_ERROR if any error occurs during the loading process.
  842. */
  843. static int elf_file_load(elf_load_info_t *load_info)
  844. {
  845. int ret;
  846. /* Load basic information of the ELF application (ELF header and program header) */
  847. ret = elf_load_app(&load_info->exec_info);
  848. if (ret != RT_EOK)
  849. {
  850. goto OUT;
  851. }
  852. /* Load the interpreter (if any) */
  853. ret = elf_load_interp(load_info);
  854. if (ret != RT_EOK)
  855. {
  856. goto OUT;
  857. }
  858. /* Load each segment of the ELF file into memory */
  859. ret = elf_load_segment(load_info);
  860. if (ret != RT_EOK)
  861. {
  862. goto OUT;
  863. }
  864. OUT:
  865. /* Perform resource cleanup regardless of success or failure */
  866. elf_load_deinit(load_info);
  867. return ret;
  868. }
  869. /**
  870. * @brief Load an ELF executable file into memory and prepare it for execution.
  871. *
  872. * This function is responsible for loading an ELF format executable file into memory,
  873. * setting up the necessary process structures, and preparing it for execution.
  874. *
  875. * @param filename The path to the ELF file to be loaded.
  876. * @param lwp Pointer to the Light Weight Process (LWP) structure that will execute the program.
  877. * @param load_addr The memory address where the ELF should be loaded.
  878. * @param addr_size The size of the memory area available for loading.
  879. * @param aux_ua Pointer to the auxiliary information structure for process initialization.
  880. *
  881. * @return RT_EOK if the ELF file is successfully loaded and prepared for execution.
  882. * @return -RT_ERROR if any error occurs during the loading process, including:
  883. * - Invalid filename or path
  884. * - Memory allocation failure
  885. * - ELF file format errors
  886. *
  887. * @see dfs_normalize_path, elf_file_load
  888. */
  889. int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size,
  890. struct process_aux *aux_ua)
  891. {
  892. elf_load_info_t load_info = { 0 };
  893. int len;
  894. int ret;
  895. /* Validate input filename */
  896. if (filename == RT_NULL)
  897. {
  898. LOG_E("%s : file is NULL", __func__);
  899. return -RT_ERROR;
  900. }
  901. /* Check filename length constraints */
  902. len = rt_strlen(filename);
  903. if (len < FLF_PATH_MIN || len > ELF_PATH_MAX)
  904. {
  905. LOG_E("%s : file length (%d) invalid", __func__, len);
  906. return -RT_ERROR;
  907. }
  908. /* Allocate memory for filename and copy it */
  909. load_info.exec_info.filename = rt_malloc(len + 1);
  910. if (!load_info.exec_info.filename)
  911. {
  912. LOG_E("%s : alloc filename failed", __func__, len);
  913. return -RT_ERROR;
  914. }
  915. else
  916. {
  917. rt_memset(load_info.exec_info.filename, 0, len + 1);
  918. rt_strncpy(load_info.exec_info.filename, filename, len);
  919. }
  920. /* Initialize load information structure */
  921. load_info.lwp = lwp;
  922. load_info.aux = aux_ua;
  923. load_info.exec_info.fd = ELF_INVALID_FD;
  924. load_info.interp_info.fd = ELF_INVALID_FD;
  925. load_info.load_addr = (rt_ubase_t)load_addr;
  926. /* copy file name to process name */
  927. rt_strncpy(lwp->cmd, filename, RT_NAME_MAX);
  928. lwp->exe_file = dfs_normalize_path(NULL, filename); /* malloc */
  929. /* Load and process the ELF file */
  930. ret = elf_file_load(&load_info);
  931. if (ret != RT_EOK)
  932. {
  933. LOG_E("%s : elf_file_load error, ret : %d", __func__, ret);
  934. return ret;
  935. }
  936. return RT_EOK;
  937. }
  938. #endif