|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright (c) 2006-2023, RT-Thread Development Team
|
|
|
+ * Copyright (c) 2006-2025 RT-Thread Development Team
|
|
|
*
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
*
|
|
@@ -60,27 +60,44 @@
|
|
|
lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \
|
|
|
} while (0)
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Structure to hold information about an ELF file.
|
|
|
+ *
|
|
|
+ */
|
|
|
typedef struct
|
|
|
{
|
|
|
- int fd;
|
|
|
- char *filename;
|
|
|
- rt_size_t file_len;
|
|
|
- Elf_Ehdr ehdr;
|
|
|
- Elf_Phdr *phdr;
|
|
|
- rt_ubase_t map_size;
|
|
|
+ int fd; /* File descriptor for the ELF file */
|
|
|
+ char *filename; /* Path to the ELF file */
|
|
|
+ rt_size_t file_len; /* Length of the ELF file */
|
|
|
+ Elf_Ehdr ehdr; /* ELF header */
|
|
|
+ Elf_Phdr *phdr; /* Pointer to the program header table */
|
|
|
+ rt_ubase_t map_size; /* Total size required for memory mapping */
|
|
|
} elf_info_t;
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Structure to hold information about an ELF executable and its interpreter.
|
|
|
+ */
|
|
|
typedef struct
|
|
|
{
|
|
|
- struct rt_lwp *lwp;
|
|
|
- struct process_aux *aux;
|
|
|
- elf_info_t exec_info;
|
|
|
- elf_info_t interp_info;
|
|
|
- rt_ubase_t load_addr;
|
|
|
- rt_ubase_t e_entry;
|
|
|
- rt_ubase_t interp_base;
|
|
|
+ struct rt_lwp *lwp; /* Pointer to the Light Weight Process (LWP) structure */
|
|
|
+ struct process_aux *aux; /* Pointer to auxiliary process information */
|
|
|
+ elf_info_t exec_info; /* Information about the main ELF executable */
|
|
|
+ elf_info_t interp_info; /* Information about the ELF interpreter (if any) */
|
|
|
+ rt_ubase_t load_addr; /* Base address where the ELF is loaded */
|
|
|
+ rt_ubase_t e_entry; /* Entry point address of the ELF */
|
|
|
+ rt_ubase_t interp_base; /* Base address of the interpreter */
|
|
|
} elf_load_info_t;
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Dump the contents of a user-space memory region for debugging.
|
|
|
+ *
|
|
|
+ * This function reads and prints the contents of a specified user-space memory region
|
|
|
+ * in hexadecimal format. It is primarily used for debugging ELF loading and execution.
|
|
|
+ *
|
|
|
+ * @param lwp Pointer to the Light Weight Process (LWP) structure.
|
|
|
+ * @param va Virtual address of the memory region to dump.
|
|
|
+ * @param len Length of the memory region to dump.
|
|
|
+ */
|
|
|
static void elf_user_dump(struct rt_lwp *lwp, void *va, size_t len)
|
|
|
{
|
|
|
#ifdef ELF_DEBUG_DUMP
|
|
@@ -120,6 +137,11 @@ static void elf_user_dump(struct rt_lwp *lwp, void *va, size_t len)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Generate a random offset for ELF loading.
|
|
|
+ *
|
|
|
+ * @return Random offset aligned to page size.
|
|
|
+ */
|
|
|
rt_ubase_t elf_random_offset(void)
|
|
|
{
|
|
|
#ifdef ELF_LOAD_RANDOMIZE
|
|
@@ -129,6 +151,23 @@ rt_ubase_t elf_random_offset(void)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Map a file into the process's address space.
|
|
|
+ *
|
|
|
+ * This function maps a file into the process's virtual memory using the specified
|
|
|
+ * address, size, protection flags, and offset. It ensures the mapping is properly
|
|
|
+ * aligned and verifies the mapping operation.
|
|
|
+ *
|
|
|
+ * @param lwp Pointer to the Light Weight Process (LWP) structure.
|
|
|
+ * @param fd File descriptor of the file to map.
|
|
|
+ * @param load_addr Desired virtual address for mapping.
|
|
|
+ * @param map_size Size of the memory mapping.
|
|
|
+ * @param prot Memory protection flags (e.g., PROT_READ, PROT_WRITE).
|
|
|
+ * @param flags Mapping flags (e.g., MAP_FIXED, MAP_PRIVATE).
|
|
|
+ * @param offset File offset where mapping should begin.
|
|
|
+ *
|
|
|
+ * @return Virtual address where the file is mapped on success, NULL on failure.
|
|
|
+ */
|
|
|
static void *file_mmap(struct rt_lwp *lwp, int fd, rt_ubase_t load_addr,
|
|
|
rt_ubase_t map_size, size_t prot, size_t flags, rt_ubase_t offset)
|
|
|
{
|
|
@@ -163,6 +202,13 @@ static int elf_file_close(int fd)
|
|
|
return close(fd);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Get the length of an ELF file.
|
|
|
+ *
|
|
|
+ * @param filename Path to the ELF file.
|
|
|
+ * @param file_len Pointer to store the file length.
|
|
|
+ * @return RT_EOK on success, -RT_ERROR on failure.
|
|
|
+ */
|
|
|
static int elf_file_length(char *filename, rt_size_t *file_len)
|
|
|
{
|
|
|
int ret;
|
|
@@ -179,6 +225,15 @@ static int elf_file_length(char *filename, rt_size_t *file_len)
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Read data from an ELF file at a specific offset.
|
|
|
+ *
|
|
|
+ * @param fd File descriptor of the ELF file.
|
|
|
+ * @param buffer Pointer to the buffer where the read data will be stored.
|
|
|
+ * @param size Number of bytes to read.
|
|
|
+ * @param offset File offset where reading should begin.
|
|
|
+ * @return RT_EOK on success, -RT_ERROR if seek or read operations fail.
|
|
|
+ */
|
|
|
static int elf_file_read(rt_int32_t fd, rt_uint8_t *buffer, size_t size, off_t offset)
|
|
|
{
|
|
|
ssize_t read_len;
|
|
@@ -204,6 +259,13 @@ static int elf_file_read(rt_int32_t fd, rt_uint8_t *buffer, size_t size, off_t o
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Validate an ELF header.
|
|
|
+ *
|
|
|
+ * @param ehdr Pointer to the ELF header to validate.
|
|
|
+ * @param file_len Length of the ELF file.
|
|
|
+ * @return RT_EOK if valid, -RT_ERROR if invalid.
|
|
|
+ */
|
|
|
static rt_int32_t elf_check_ehdr(const Elf_Ehdr *ehdr, rt_uint32_t file_len)
|
|
|
{
|
|
|
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
|
|
@@ -241,6 +303,12 @@ static rt_int32_t elf_check_ehdr(const Elf_Ehdr *ehdr, rt_uint32_t file_len)
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Validate an ELF program header.
|
|
|
+ *
|
|
|
+ * @param phdr Pointer to the ELF program header to validate.
|
|
|
+ * @return RT_EOK if valid, -RT_ERROR if invalid.
|
|
|
+ */
|
|
|
static int elf_check_phdr(const Elf_Phdr *phdr)
|
|
|
{
|
|
|
if (phdr->p_filesz > FILE_LENGTH_MAX)
|
|
@@ -266,6 +334,16 @@ static int elf_check_phdr(const Elf_Phdr *phdr)
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load and validate the ELF header from a file.
|
|
|
+ *
|
|
|
+ * This function opens the ELF file, reads its elf header, and performs basic validation
|
|
|
+ * to ensure it's a valid ELF file. It also retrieves the file size and stores the
|
|
|
+ * file descriptor for subsequent operations.
|
|
|
+ *
|
|
|
+ * @param elf_info Pointer to the ELF file information structure.
|
|
|
+ * @return RT_EOK on success, -RT_ERROR on failure.
|
|
|
+ */
|
|
|
static int elf_load_ehdr(elf_info_t *elf_info)
|
|
|
{
|
|
|
int ret;
|
|
@@ -302,6 +380,15 @@ static int elf_load_ehdr(elf_info_t *elf_info)
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load the program header table from an ELF file.
|
|
|
+ *
|
|
|
+ * This function reads and validates the program header table from the ELF file.
|
|
|
+ * It ensures the program header table is properly aligned and within the file bounds.
|
|
|
+ *
|
|
|
+ * @param elf_info Pointer to the ELF file information structure.
|
|
|
+ * @return RT_EOK on success, -RT_ERROR on failure.
|
|
|
+ */
|
|
|
static int elf_load_phdr(elf_info_t *elf_info)
|
|
|
{
|
|
|
Elf_Ehdr *ehdr = &elf_info->ehdr;
|
|
@@ -343,6 +430,16 @@ static int elf_load_phdr(elf_info_t *elf_info)
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load the ELF interpreter specified in the program header.
|
|
|
+ *
|
|
|
+ * This function searches for the PT_INTERP segment in the program headers,
|
|
|
+ * validates its properties, and loads the interpreter's filename and
|
|
|
+ * associated ELF information.
|
|
|
+ *
|
|
|
+ * @param load_info Pointer to the ELF loading context structure.
|
|
|
+ * @return RT_EOK on success, -RT_ERROR on failure.
|
|
|
+ */
|
|
|
static int elf_load_interp(elf_load_info_t *load_info)
|
|
|
{
|
|
|
Elf_Phdr *phdr = load_info->exec_info.phdr;
|
|
@@ -420,6 +517,12 @@ error_exit:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Calculate the total size required to map all loadable ELF segments.
|
|
|
+ *
|
|
|
+ * @param elf_info Pointer to the ELF file information structure.
|
|
|
+ * @return 0 on success, -1 if no loadable segments are found.
|
|
|
+ */
|
|
|
static int total_mapping_size(elf_info_t *elf_info)
|
|
|
{
|
|
|
int i;
|
|
@@ -445,6 +548,24 @@ static int total_mapping_size(elf_info_t *elf_info)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Map an ELF segment into the process's address space.
|
|
|
+ *
|
|
|
+ * This function maps a specific ELF segment into the process's virtual memory space.
|
|
|
+ * It handles page alignment, calculates the correct offset, and performs the actual
|
|
|
+ * memory mapping operation.
|
|
|
+ *
|
|
|
+ * @param lwp Pointer to the Light Weight Process (LWP) structure.
|
|
|
+ * @param elf_phdr Pointer to the ELF program header describing the segment.
|
|
|
+ * @param fd File descriptor of the ELF file.
|
|
|
+ * @param addr Desired virtual address for mapping.
|
|
|
+ * @param prot Memory protection flags (e.g., PROT_READ, PROT_WRITE).
|
|
|
+ * @param flags Mapping flags (e.g., MAP_FIXED, MAP_PRIVATE).
|
|
|
+ * @param map_size Size of the memory mapping (0 for automatic calculation).
|
|
|
+ *
|
|
|
+ * @return Virtual address where the segment is mapped on success.
|
|
|
+ * @return 0 on failure.
|
|
|
+ */
|
|
|
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)
|
|
|
{
|
|
|
rt_ubase_t map_va = 0;
|
|
@@ -478,26 +599,46 @@ static int elf_zero_bss(struct rt_lwp *lwp, int fd, const Elf_Phdr *phdr, rt_uba
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Map ELF segments into memory.
|
|
|
+ *
|
|
|
+ * This function maps the loadable segments of an ELF file into the process's address space.
|
|
|
+ * It handles both executable and shared library files, manages BSS sections, and sets up
|
|
|
+ * the load address and base address for dynamic libraries.
|
|
|
+ *
|
|
|
+ * @param load_info Pointer to the structure containing ELF loading context.
|
|
|
+ * @param elf_info Pointer to the structure containing ELF file information.
|
|
|
+ * @param elfload_addr Pointer to store the final load address of the ELF file.
|
|
|
+ * @param map_size Size of the memory mapping (0 for automatic calculation).
|
|
|
+ * @param load_base Base address for loading (used for position-independent code).
|
|
|
+ *
|
|
|
+ * @return RT_EOK on success.
|
|
|
+ * @return -RT_ERROR if memory mapping fails.
|
|
|
+ * @return -ENOMEM if memory allocation fails.
|
|
|
+ */
|
|
|
static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ubase_t *elfload_addr,
|
|
|
rt_uint32_t map_size, rt_ubase_t *load_base)
|
|
|
{
|
|
|
int ret, i;
|
|
|
rt_ubase_t map_va, bss_start, bss_end;
|
|
|
- Elf_Ehdr *ehdr = &elf_info->ehdr;
|
|
|
- Elf_Phdr *phdr = elf_info->phdr;
|
|
|
- const Elf_Phdr *tmp_phdr = phdr;
|
|
|
- int fd = elf_info->fd;
|
|
|
- rt_ubase_t load_addr;
|
|
|
- size_t prot = PROT_READ | PROT_WRITE;
|
|
|
- size_t flags = MAP_FIXED | MAP_PRIVATE;
|
|
|
-
|
|
|
+ Elf_Ehdr *ehdr = &elf_info->ehdr; /* ELF header */
|
|
|
+ Elf_Phdr *phdr = elf_info->phdr; /* Program header array */
|
|
|
+ const Elf_Phdr *tmp_phdr = phdr; /* Current program header */
|
|
|
+ int fd = elf_info->fd; /* File descriptor for ELF file */
|
|
|
+ rt_ubase_t load_addr; /* Calculated load address */
|
|
|
+ size_t prot = PROT_READ | PROT_WRITE; /* Memory protection flags */
|
|
|
+ size_t flags = MAP_FIXED | MAP_PRIVATE; /* Memory mapping flags */
|
|
|
+
|
|
|
+ /* Iterate through all program headers */
|
|
|
for (i = 0; i < ehdr->e_phnum; ++i, ++tmp_phdr)
|
|
|
{
|
|
|
+ /* Only process PT_LOAD segments (loadable segments) */
|
|
|
if (tmp_phdr->p_type != PT_LOAD)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
+ /* For executable files, validate the program header */
|
|
|
if (ehdr->e_type == ET_EXEC)
|
|
|
{
|
|
|
if (elf_check_phdr(tmp_phdr) != RT_EOK)
|
|
@@ -509,11 +650,16 @@ static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ub
|
|
|
|
|
|
load_addr = tmp_phdr->p_vaddr + *load_base;
|
|
|
LOG_D("%s : p_vaddr : 0x%x, load_addr : 0x%x", __func__, tmp_phdr->p_vaddr, load_addr);
|
|
|
+
|
|
|
+ /* When both the segment's virtual address and the load base are 0, the segment is loaded at any available
|
|
|
+ address rather than a fixed one. This behavior is particularly useful for Position-Independent Code (PIC)
|
|
|
+ or shared libraries. */
|
|
|
if ((tmp_phdr->p_vaddr == 0) && (*load_base == 0))
|
|
|
{
|
|
|
flags &= ~MAP_FIXED;
|
|
|
}
|
|
|
|
|
|
+ /* Map the segment into memory */
|
|
|
map_va = elf_map(load_info->lwp, tmp_phdr, fd, load_addr, prot, flags, map_size);
|
|
|
if (!map_va)
|
|
|
{
|
|
@@ -524,6 +670,8 @@ static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ub
|
|
|
map_size = 0;
|
|
|
|
|
|
elf_user_dump(load_info->lwp, (void *)load_addr, 64);
|
|
|
+
|
|
|
+ /* Handle BSS section (zero-initialized data) */
|
|
|
if ((tmp_phdr->p_memsz > tmp_phdr->p_filesz) && (tmp_phdr->p_flags & PF_W))
|
|
|
{
|
|
|
bss_start = load_addr + tmp_phdr->p_filesz;
|
|
@@ -552,6 +700,14 @@ static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ub
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load the ELF interpreter into memory.
|
|
|
+ *
|
|
|
+ * @param load_info Pointer to the ELF loading context.
|
|
|
+ * @param interp_base Pointer to store the interpreter's base address.
|
|
|
+ *
|
|
|
+ * @return RT_EOK on success, -RT_ERROR on failure.
|
|
|
+ */
|
|
|
static int load_elf_interp(elf_load_info_t *load_info, rt_ubase_t *interp_base)
|
|
|
{
|
|
|
int ret;
|
|
@@ -569,6 +725,21 @@ static int load_elf_interp(elf_load_info_t *load_info, rt_ubase_t *interp_base)
|
|
|
load_info->interp_info.map_size, &load_base);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Populate the auxiliary vector for an ELF-loaded process.
|
|
|
+ *
|
|
|
+ * This function sets up the auxiliary vector that provides essential information
|
|
|
+ * to the ELF executable about the runtime environment. It includes information
|
|
|
+ * about page size, program headers, entry point, and other system-specific details.
|
|
|
+ *
|
|
|
+ * @param load_info Pointer to the structure containing ELF loading information.
|
|
|
+ *
|
|
|
+ * @return 0 on success, -1 if the auxiliary structure is invalid, or -RT_ERROR
|
|
|
+ * if memory mapping fails.
|
|
|
+ *
|
|
|
+ * @note The auxiliary vector is crucial for proper initialization of the ELF
|
|
|
+ * executable and its interaction with the runtime environment.
|
|
|
+ */
|
|
|
static int elf_aux_fill(elf_load_info_t *load_info)
|
|
|
{
|
|
|
uint8_t *random;
|
|
@@ -625,13 +796,26 @@ static int elf_aux_fill(elf_load_info_t *load_info)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load the segments of an ELF file into memory.
|
|
|
+ *
|
|
|
+ * This function is responsible for loading the segments of an ELF file into memory,
|
|
|
+ * including handling dynamic libraries and setting up the entry point for execution.
|
|
|
+ *
|
|
|
+ * @param load_info Pointer to the structure containing ELF loading information.
|
|
|
+ * @return RT_EOK if the segments are successfully loaded and prepared for execution.
|
|
|
+ * @return -RT_ERROR if any error occurs during the loading process, including:
|
|
|
+ * - Memory allocation failure
|
|
|
+ * - File mapping errors
|
|
|
+ * - Interpreter loading errors
|
|
|
+ */
|
|
|
static int elf_load_segment(elf_load_info_t *load_info)
|
|
|
{
|
|
|
int ret;
|
|
|
- rt_ubase_t app_load_base = 0;
|
|
|
- load_info->load_addr = 0;
|
|
|
- load_info->interp_base = 0;
|
|
|
- load_info->exec_info.map_size = 0;
|
|
|
+ rt_ubase_t app_load_base = 0; /* Base address for loading the application. */
|
|
|
+ load_info->load_addr = 0; /* Load address for the ELF file. */
|
|
|
+ load_info->interp_base = 0; /* Base address for loading the interpreter. */
|
|
|
+ load_info->exec_info.map_size = 0; /* Total size of the mapped segments. */
|
|
|
|
|
|
if (load_info->exec_info.ehdr.e_type == ET_DYN)
|
|
|
{
|
|
@@ -642,9 +826,13 @@ static int elf_load_segment(elf_load_info_t *load_info)
|
|
|
return -RT_ERROR;
|
|
|
}
|
|
|
LOG_D("%s : map_size : 0x%x", __func__, load_info->exec_info.map_size);
|
|
|
+
|
|
|
+ /* Calculate the base address for loading the ELF file by adding a random offset to the default load address.
|
|
|
+ This randomization enhances security by making it harder for attackers to predict the memory layout. */
|
|
|
app_load_base = ELF_EXEC_LOAD_ADDR + elf_random_offset();
|
|
|
}
|
|
|
|
|
|
+ /* Map the segments of the ELF file into memory */
|
|
|
ret = elf_file_mmap(load_info, &load_info->exec_info, &load_info->load_addr,
|
|
|
load_info->exec_info.map_size, &app_load_base);
|
|
|
elf_file_close(load_info->exec_info.fd);
|
|
@@ -656,7 +844,7 @@ static int elf_load_segment(elf_load_info_t *load_info)
|
|
|
|
|
|
if (load_info->interp_info.fd != ELF_INVALID_FD)
|
|
|
{
|
|
|
- ret = load_elf_interp(load_info, &load_info->interp_base);
|
|
|
+ ret = load_elf_interp(load_info, &load_info->interp_base); /* load the interpreter */
|
|
|
if (ret)
|
|
|
{
|
|
|
LOG_E("%s : load_elf_interp failed, ret = %d", __func__, ret);
|
|
@@ -668,19 +856,24 @@ static int elf_load_segment(elf_load_info_t *load_info)
|
|
|
LOG_W("%s : elf_file_close interp failed, ret = %d", __func__, ret);
|
|
|
}
|
|
|
load_info->interp_info.fd = ELF_INVALID_FD;
|
|
|
+
|
|
|
+ /* if a interpreter exist, first jump to the interpreter's entry to handle dynamic libs' loading. */
|
|
|
load_info->e_entry = load_info->interp_info.ehdr.e_entry + load_info->interp_base;
|
|
|
- load_info->exec_info.ehdr.e_entry = load_info->exec_info.ehdr.e_entry + app_load_base;
|
|
|
+ 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. */
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
+ /* If there is no interpreter, use the ELF file's entry address directly. */
|
|
|
load_info->e_entry = load_info->exec_info.ehdr.e_entry;
|
|
|
}
|
|
|
|
|
|
load_info->lwp->text_entry = (void *)load_info->e_entry;
|
|
|
LOG_D("%s : lwp->text_entry : %p loadaddr : %p", __func__, load_info->lwp->text_entry, app_load_base);
|
|
|
|
|
|
+ /* Debug information: dump user space data. */
|
|
|
elf_user_dump(load_info->lwp, load_info->lwp->text_entry, 64);
|
|
|
|
|
|
+ /* Fill auxiliary information. */
|
|
|
ret = elf_aux_fill(load_info);
|
|
|
if (ret)
|
|
|
{
|
|
@@ -691,6 +884,15 @@ static int elf_load_segment(elf_load_info_t *load_info)
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Clean up resources allocated during ELF loading.
|
|
|
+ *
|
|
|
+ * This function releases all resources (file descriptors, memory, etc.) that were
|
|
|
+ * allocated during the ELF loading process. It ensures that no memory leaks occur
|
|
|
+ * and all file descriptors are properly closed.
|
|
|
+ *
|
|
|
+ * @param load_info Pointer to the structure containing ELF loading information.
|
|
|
+ */
|
|
|
static void elf_load_deinit(elf_load_info_t *load_info)
|
|
|
{
|
|
|
if (load_info->exec_info.fd != ELF_INVALID_FD)
|
|
@@ -724,16 +926,26 @@ static void elf_load_deinit(elf_load_info_t *load_info)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load the ELF header and program header information.
|
|
|
+ *
|
|
|
+ * @param exec_info Pointer to the elf_info_t structure containing elf file information.
|
|
|
+ *
|
|
|
+ * @return RT_EOK if the ELF header and program header information are successfully loaded.
|
|
|
+ * @return -RT_ERROR if any error occurs during the loading process.
|
|
|
+ */
|
|
|
static int elf_load_app(elf_info_t *exec_info)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
+ /* load elf header */
|
|
|
ret = elf_load_ehdr(exec_info);
|
|
|
if (ret != RT_EOK)
|
|
|
{
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ /* load the ELF program header */
|
|
|
ret = elf_load_phdr(exec_info);
|
|
|
if (ret != RT_EOK)
|
|
|
{
|
|
@@ -743,22 +955,33 @@ static int elf_load_app(elf_info_t *exec_info)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load an ELF file into memory.
|
|
|
+ *
|
|
|
+ * @param load_info Pointer to the elf_load_info_t structure containing information about the ELF file.
|
|
|
+ *
|
|
|
+ * @return RT_EOK if the ELF file is successfully loaded.
|
|
|
+ * @return -RT_ERROR if any error occurs during the loading process.
|
|
|
+ */
|
|
|
static int elf_file_load(elf_load_info_t *load_info)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
+ /* Load basic information of the ELF application (ELF header and program header) */
|
|
|
ret = elf_load_app(&load_info->exec_info);
|
|
|
if (ret != RT_EOK)
|
|
|
{
|
|
|
goto OUT;
|
|
|
}
|
|
|
|
|
|
+ /* Load the interpreter (if any) */
|
|
|
ret = elf_load_interp(load_info);
|
|
|
if (ret != RT_EOK)
|
|
|
{
|
|
|
goto OUT;
|
|
|
}
|
|
|
|
|
|
+ /* Load each segment of the ELF file into memory */
|
|
|
ret = elf_load_segment(load_info);
|
|
|
if (ret != RT_EOK)
|
|
|
{
|
|
@@ -766,10 +989,31 @@ static int elf_file_load(elf_load_info_t *load_info)
|
|
|
}
|
|
|
|
|
|
OUT:
|
|
|
+ /* Perform resource cleanup regardless of success or failure */
|
|
|
elf_load_deinit(load_info);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Load an ELF executable file into memory and prepare it for execution.
|
|
|
+ *
|
|
|
+ * This function is responsible for loading an ELF format executable file into memory,
|
|
|
+ * setting up the necessary process structures, and preparing it for execution.
|
|
|
+ *
|
|
|
+ * @param filename The path to the ELF file to be loaded.
|
|
|
+ * @param lwp Pointer to the Light Weight Process (LWP) structure that will execute the program.
|
|
|
+ * @param load_addr The memory address where the ELF should be loaded.
|
|
|
+ * @param addr_size The size of the memory area available for loading.
|
|
|
+ * @param aux_ua Pointer to the auxiliary information structure for process initialization.
|
|
|
+ *
|
|
|
+ * @return RT_EOK if the ELF file is successfully loaded and prepared for execution.
|
|
|
+ * @return -RT_ERROR if any error occurs during the loading process, including:
|
|
|
+ * - Invalid filename or path
|
|
|
+ * - Memory allocation failure
|
|
|
+ * - ELF file format errors
|
|
|
+ *
|
|
|
+ * @see dfs_normalize_path, elf_file_load
|
|
|
+ */
|
|
|
int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size,
|
|
|
struct process_aux *aux_ua)
|
|
|
{
|
|
@@ -777,12 +1021,14 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_
|
|
|
int len;
|
|
|
int ret;
|
|
|
|
|
|
+ /* Validate input filename */
|
|
|
if (filename == RT_NULL)
|
|
|
{
|
|
|
LOG_E("%s : file is NULL", __func__);
|
|
|
return -RT_ERROR;
|
|
|
}
|
|
|
|
|
|
+ /* Check filename length constraints */
|
|
|
len = rt_strlen(filename);
|
|
|
if (len < FLF_PATH_MIN || len > ELF_PATH_MAX)
|
|
|
{
|
|
@@ -790,6 +1036,7 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_
|
|
|
return -RT_ERROR;
|
|
|
}
|
|
|
|
|
|
+ /* Allocate memory for filename and copy it */
|
|
|
load_info.exec_info.filename = rt_malloc(len + 1);
|
|
|
if (!load_info.exec_info.filename)
|
|
|
{
|
|
@@ -802,6 +1049,7 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_
|
|
|
rt_strncpy(load_info.exec_info.filename, filename, len);
|
|
|
}
|
|
|
|
|
|
+ /* Initialize load information structure */
|
|
|
load_info.lwp = lwp;
|
|
|
load_info.aux = aux_ua;
|
|
|
|
|
@@ -811,8 +1059,9 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_
|
|
|
|
|
|
/* copy file name to process name */
|
|
|
rt_strncpy(lwp->cmd, filename, RT_NAME_MAX);
|
|
|
- lwp->exe_file = dfs_normalize_path(NULL, filename); // malloc
|
|
|
+ lwp->exe_file = dfs_normalize_path(NULL, filename); /* malloc */
|
|
|
|
|
|
+ /* Load and process the ELF file */
|
|
|
ret = elf_file_load(&load_info);
|
|
|
if (ret != RT_EOK)
|
|
|
{
|
|
@@ -823,4 +1072,4 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
|
|
|
-#endif
|
|
|
+#endif
|