Support for building and running external apps (#112)
This commit is contained in:
committed by
GitHub
parent
42e843b463
commit
415442e410
@@ -0,0 +1 @@
|
||||
ec9b5b8881cf5c38113ed7eab28a71ed7bfc9f477d6faef851f7f59f7a07b536
|
||||
@@ -0,0 +1,5 @@
|
||||
# ChangeLog
|
||||
|
||||
## v0.1.0 - 2023-08-14
|
||||
|
||||
* Add basic ELF loader component
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
if(CONFIG_ELF_LOADER)
|
||||
set(srcs "src/esp_elf_symbol.c"
|
||||
"src/esp_elf.c"
|
||||
"src/esp_elf_adapter.c")
|
||||
|
||||
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||
list(APPEND srcs "src/arch/esp_elf_xtensa.c")
|
||||
|
||||
# ESP32-S2 need to set MMU to run ELF
|
||||
if(CONFIG_IDF_TARGET_ESP32S2 AND (CONFIG_ELF_LOADER_LOAD_PSRAM))
|
||||
list(APPEND srcs "src/soc/esp_elf_esp32s2.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(include_dirs "include")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${include_dirs}
|
||||
PRIV_REQUIRES spi_flash)
|
||||
|
||||
include(package_manager)
|
||||
if(CONFIG_ELF_LOADER)
|
||||
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
|
||||
endif()
|
||||
@@ -0,0 +1,48 @@
|
||||
menu "Espressif ELF Loader Configuration"
|
||||
visible if (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3)
|
||||
|
||||
config ELF_LOADER
|
||||
bool "Enable Espressif ELF Loader"
|
||||
default y
|
||||
depends on (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3)
|
||||
help
|
||||
Select this option to enable ELF Loader and show the submenu with ELF Loader configuration choices.
|
||||
|
||||
if ELF_LOADER
|
||||
config ELF_LOADER_CACHE_OFFSET
|
||||
bool
|
||||
default n
|
||||
help
|
||||
Select this option if D-cache and I-cache has different offset to access the same physical address.
|
||||
|
||||
config ELF_LOADER_SET_MMU
|
||||
bool
|
||||
default n
|
||||
help
|
||||
Select this option if D-cache and I-cache is not symmetry。
|
||||
|
||||
config ELF_LOADER_LOAD_PSRAM
|
||||
bool "Load ELF to PSRAM"
|
||||
default y
|
||||
depends on (IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3) && SPIRAM
|
||||
select ELF_LOADER_CACHE_OFFSET if (IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3)
|
||||
select ELF_LOADER_SET_MMU if IDF_TARGET_ESP32S2
|
||||
help
|
||||
Load ELF file into PSRAM instead of internal SRAM.
|
||||
|
||||
menu "ELF Symbols Table"
|
||||
|
||||
config ELF_LOADER_LIBC_SYMBOLS
|
||||
bool "Libc Symbols Table"
|
||||
default y
|
||||
|
||||
config ELF_LOADER_ESPIDF_SYMBOLS
|
||||
bool "ESP-IDF Symbols Table"
|
||||
default y
|
||||
|
||||
config ELF_LOADER_CUSTOMER_SYMBOLS
|
||||
bool "Customer Symbols Table"
|
||||
default n
|
||||
endmenu
|
||||
endif
|
||||
endmenu
|
||||
@@ -0,0 +1,83 @@
|
||||
## Description
|
||||
|
||||
[](https://components.espressif.com/components/espressif/elf_loader)
|
||||
|
||||
Espressif ELF(Executable and Linkable Format) loader is a software development kit that is developed based on the ESP-IDF, mainly used to load ELF file compiled based on ESP32 series SoCs to the executable memory area, then link and execute it.
|
||||
|
||||
In this way, the application does not need compile into the whole firmware in advance. It is like running the compiled program through terminal input `./main.o` on the Ubuntu platform automatically, which realizes the separation of application and kernel.
|
||||
|
||||
This ELF loader supports following SoCs:
|
||||
|
||||
- ESP32
|
||||
- ESP32-S2, support running ELF in PSRAM
|
||||
- ESP32-S3, support running ELF in PSRAM
|
||||
|
||||
### Usage
|
||||
|
||||
#### Firmware
|
||||
|
||||
Add a dependency on this component in your component or project's idf_component.yml file.
|
||||
|
||||
```yml
|
||||
dependencies:
|
||||
espressif/elf_loader: "0.*"
|
||||
```
|
||||
|
||||
Enable ELF loader in the menuconfig:
|
||||
|
||||
```
|
||||
Component config --->
|
||||
ESP-ELFLoader Configuration --->
|
||||
[*] Enable Espressif ELF Loader
|
||||
```
|
||||
|
||||
Add API calls in your project as follows:
|
||||
|
||||
```c
|
||||
#include "esp_elf.h"
|
||||
|
||||
esp_elf_t elf;
|
||||
|
||||
// Your Code
|
||||
|
||||
esp_elf_init(&elf);
|
||||
esp_elf_relocate(&elf, elf_file_data_bytes);
|
||||
esp_elf_request(&elf, 0, argc, argv);
|
||||
esp_elf_deinit(&elf);
|
||||
```
|
||||
|
||||
#### ELF APP
|
||||
|
||||
To use this feature to compile ELF file, including the required CMake file in your project's CMakeLists.txt file after the line project(XXXX).
|
||||
|
||||
```cmake
|
||||
project(XXXX)
|
||||
|
||||
# Add
|
||||
include(elf_loader)
|
||||
project_elf(XXXX)
|
||||
```
|
||||
|
||||
Build the project as an ordinary ESP-IDF project, and then the ELF file named `XXXX.app.elf` is in the build directory.
|
||||
|
||||
### Adding the Component to Your Project
|
||||
|
||||
Please use the component manager command add-dependency to add the elf_loader component as a dependency in your project. During the CMake step, the component will be downloaded automatically.
|
||||
|
||||
```
|
||||
idf.py add-dependency "espressif/elf_loader=*"
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Please use the component manager command create-project-from-example to create a project from the example template.
|
||||
|
||||
```
|
||||
idf.py create-project-from-example "espressif/elf_loader=*:elf_loader_example"
|
||||
```
|
||||
|
||||
This command will download the example elf_loader_example into the current folder. You can navigate into it to build and flash the example.
|
||||
|
||||
Alternatively, you can download examples from the esp-iot-solution repository:
|
||||
1. [build_elf_file_example](https://github.com/espressif/esp-iot-solution/tree/master/examples/elf_loader/build_elf_file_example)
|
||||
2. [elf_loader_example](https://github.com/espressif/esp-iot-solution/tree/master/examples/elf_loader/elf_loader_example)
|
||||
@@ -0,0 +1,62 @@
|
||||
# The script is to generate ELF for application
|
||||
|
||||
# Trick to temporarily redefine project(). When functions are overriden in CMake, the originals can still be accessed
|
||||
# using an underscore prefixed function of the same name. The following lines make sure that project calls
|
||||
# the original project(). See https://cmake.org/pipermail/cmake/2015-October/061751.html.
|
||||
function(project_elf)
|
||||
endfunction()
|
||||
|
||||
function(_project_elf)
|
||||
endfunction()
|
||||
|
||||
macro(project_elf project_name)
|
||||
# Enable these options to remove unused symbols and reduce linked objects
|
||||
set(cflags -nostartfiles
|
||||
-nostdlib
|
||||
-fPIC
|
||||
-shared
|
||||
-e app_main
|
||||
-fdata-sections
|
||||
-ffunction-sections
|
||||
-Wl,--gc-sections
|
||||
-fvisibility=hidden)
|
||||
|
||||
# Enable this options to remove unnecessary sections in
|
||||
list(APPEND cflags -Wl,--strip-all
|
||||
-Wl,--strip-debug
|
||||
-Wl,--strip-discarded)
|
||||
|
||||
list(APPEND cflags -Dmain=app_main)
|
||||
|
||||
idf_build_set_property(COMPILE_OPTIONS "${cflags}" APPEND)
|
||||
|
||||
set(elf_app "${CMAKE_PROJECT_NAME}.app.elf")
|
||||
|
||||
# Remove more unused sections
|
||||
string(REPLACE "-elf-gcc" "-elf-strip" ${CMAKE_STRIP} ${CMAKE_C_COMPILER})
|
||||
set(strip_flags --strip-unneeded
|
||||
--remove-section=.xt.lit
|
||||
--remove-section=.xt.prop
|
||||
--remove-section=.comment
|
||||
--remove-section=.xtensa.info
|
||||
--remove-section=.got.loc
|
||||
--remove-section=.got)
|
||||
|
||||
# Link input list of libraries to ELF
|
||||
if(ELF_COMPONENTS)
|
||||
foreach(c "${ELF_COMPONENTS}")
|
||||
set(elf_libs "${elf_libs}" "esp-idf/${c}/lib${c}.a")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(elf_libs ${elf_libs} "${ELF_LIBS}" "esp-idf/main/libmain.a")
|
||||
spaces2list(elf_libs)
|
||||
|
||||
add_custom_command(OUTPUT elf_app
|
||||
COMMAND ${CMAKE_C_COMPILER} ${cflags} ${elf_libs} -o ${elf_app}
|
||||
COMMAND ${CMAKE_STRIP} ${strip_flags} ${elf_app}
|
||||
DEPENDS idf::main
|
||||
COMMENT "Build ELF: ${elf_app}"
|
||||
)
|
||||
add_custom_target(elf ALL DEPENDS elf_app)
|
||||
endmacro()
|
||||
@@ -0,0 +1,11 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(hello_world)
|
||||
|
||||
include(elf_loader)
|
||||
project_elf(hello_world)
|
||||
@@ -0,0 +1,13 @@
|
||||
## Build ELF file Example
|
||||
|
||||
This example shows how to build ELF file.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
|
||||
|
||||
* Note: Only ESP32, ESP32-S2 and ESP32-S3 are supported
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py build` to build project, and when compiling is done you can see `hello_world.app.elf` in `build` directory.
|
||||
@@ -0,0 +1 @@
|
||||
idf_component_register(SRCS "main.c")
|
||||
@@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
elf_loader:
|
||||
version: "0.*"
|
||||
override_path: "../../../../components/elf_loader"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
char buffer[] = "hello world %d\n";
|
||||
static int s_cnt;
|
||||
|
||||
int try_test(void)
|
||||
{
|
||||
for (int i = 0; i < 10; i++) {
|
||||
printf(buffer, s_cnt++);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
try_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=n
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(elf-loader)
|
||||
@@ -0,0 +1,50 @@
|
||||
## ELF Loader Example
|
||||
|
||||
This example shows how to use ELF loader to run ELF file.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
|
||||
|
||||
* Note: Only ESP32, ESP32-S2 and ESP32-S3 are supported
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board based on espressif ESP32/ESP32-S2/ESP32-S3 SoC
|
||||
* A USB cable for power supply and programming
|
||||
|
||||
### Configure the Project
|
||||
|
||||
Open the project configuration menu (`idf.py menuconfig`).
|
||||
|
||||
In the `Example Configuration` menu:
|
||||
|
||||
* Enable ELF input arguments in the `Support arguments for ELF main` option if necessary.
|
||||
* Set the arguments in the `Arguments of ELF main` option.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
## Example Output
|
||||
|
||||
As you run the example, you will see the following log:
|
||||
|
||||
```
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (382) elf_loader: Start to relocate ELF
|
||||
I (392) elf_loader: Start to run ELF
|
||||
hello world 0
|
||||
hello world 1
|
||||
hello world 2
|
||||
hello world 3
|
||||
hello world 4
|
||||
hello world 5
|
||||
hello world 6
|
||||
hello world 7
|
||||
hello world 8
|
||||
hello world 9
|
||||
I (10392) elf_loader: Success to exit from APP of ELF
|
||||
```
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "elf_loader_example_main.c"
|
||||
INCLUDE_DIRS ""
|
||||
EMBED_TXTFILES "test.elf")
|
||||
@@ -0,0 +1,12 @@
|
||||
menu "ELF Loader Example Configuration"
|
||||
|
||||
config ELF_LOADER_MAIN_ARGS
|
||||
bool "Support arguments for ELF main"
|
||||
default n
|
||||
|
||||
config ELF_LOADER_MAIN_ARGS_STRING
|
||||
string "Arguments of ELF main"
|
||||
default "main"
|
||||
depends on ELF_LOADER_MAIN_ARGS
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_elf.h"
|
||||
|
||||
static const char *TAG = "elf_loader";
|
||||
|
||||
extern const uint8_t test_elf_start[] asm("_binary_test_elf_start");
|
||||
extern const uint8_t test_elf_end[] asm("_binary_test_elf_end");
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_MAIN_ARGS
|
||||
static int elf_args_decode(const char *str, int *argc, char ***argv)
|
||||
{
|
||||
int n;
|
||||
char **argv_buf;
|
||||
char *s;
|
||||
char *pbuf;
|
||||
int len;
|
||||
|
||||
s = (char *)str;
|
||||
n = 1;
|
||||
len = 1;
|
||||
while (*s) {
|
||||
if (*s++ == ' ') {
|
||||
n++;
|
||||
}
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
pbuf = malloc(n * sizeof(char *) + len);
|
||||
if (!pbuf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
argv_buf = (char **)pbuf;
|
||||
s = pbuf + n * sizeof(char *);
|
||||
memcpy(s, str, len);
|
||||
for (int i = 0; i < n; i++) {
|
||||
argv_buf[i] = s;
|
||||
|
||||
while (*s != ' ' || *s == 0) {
|
||||
s++;
|
||||
}
|
||||
|
||||
*s++ = 0;
|
||||
}
|
||||
|
||||
*argc = n;
|
||||
*argv = argv_buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int app_main(void)
|
||||
{
|
||||
int ret;
|
||||
int argc;
|
||||
char **argv;
|
||||
esp_elf_t elf;
|
||||
const uint8_t *buffer = test_elf_start;
|
||||
|
||||
ESP_LOGI(TAG, "Start to relocate ELF file");
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_MAIN_ARGS
|
||||
if (strlen(CONFIG_ELF_LOADER_MAIN_ARGS_STRING) <= 0) {
|
||||
ESP_LOGE(TAG, "Failed to check arguments %s",
|
||||
CONFIG_ELF_LOADER_MAIN_ARGS_STRING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = elf_args_decode(CONFIG_ELF_LOADER_MAIN_ARGS_STRING, &argc, &argv);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "Failed to decode arguments %s errno=%d",
|
||||
CONFIG_ELF_LOADER_MAIN_ARGS_STRING, ret);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
#endif
|
||||
|
||||
ret = esp_elf_init(&elf);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "Failed to initialize ELF file errno=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_elf_relocate(&elf, buffer);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "Failed to relocate ELF file errno=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Start to run ELF file");
|
||||
|
||||
esp_elf_request(&elf, 0, argc, argv);
|
||||
|
||||
ESP_LOGI(TAG, "Success to exit from ELF file");
|
||||
|
||||
esp_elf_deinit(&elf);
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_MAIN_ARGS
|
||||
if (argv) {
|
||||
free(argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
elf_loader:
|
||||
version: "0.*"
|
||||
override_path: "../../../../components/elf_loader"
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_ELF_LOADER_LOAD_PSRAM=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
|
||||
@@ -0,0 +1,8 @@
|
||||
dependencies:
|
||||
espressif/cmake_utilities:
|
||||
version: 0.*
|
||||
idf:
|
||||
version: '>=4.4.3'
|
||||
description: Espressif ELF(Executable and Linkable Format) Loader
|
||||
url: https://github.com/espressif/esp-iot-solution/tree/master/components/elf_loader
|
||||
version: 0.1.0
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "private/elf_types.h"
|
||||
#include "elf_symbol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_ELFSYM_EXPORT(_sym) { #_sym, (void*)&_sym }
|
||||
#define ESP_ELFSYM_END { NULL, NULL }
|
||||
|
||||
/** @brief Function symbol description */
|
||||
|
||||
struct esp_elfsym {
|
||||
const char *name; /*!< Function name */
|
||||
const void *sym; /*!< Function pointer */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Find symbol address by name.
|
||||
*
|
||||
* @param sym_name - Symbol name
|
||||
*
|
||||
* @return Symbol address if success or 0 if failed.
|
||||
*/
|
||||
uintptr_t elf_find_sym(const char *sym_name);
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS
|
||||
void elf_set_custom_symbols(const struct esp_elfsym* symbols);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "private/elf_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Map symbol's address of ELF to physic space.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param sym - ELF symbol address
|
||||
*
|
||||
* @return Mapped physic address.
|
||||
*/
|
||||
uintptr_t esp_elf_map_sym(esp_elf_t *elf, uintptr_t sym);
|
||||
|
||||
/**
|
||||
* @brief Initialize ELF object.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_init(esp_elf_t *elf);
|
||||
|
||||
/**
|
||||
* @brief Decode and relocate ELF data.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_relocate(esp_elf_t *elf, const uint8_t *pbuf);
|
||||
|
||||
/**
|
||||
* @brief Request running relocated ELF function.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param opt - Request options
|
||||
* @param argc - Arguments number
|
||||
* @param argv - Arguments value array
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_request(esp_elf_t *elf, int opt, int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize ELF object.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_deinit(esp_elf_t *elf);
|
||||
|
||||
/**
|
||||
* @brief Print header description information of ELF.
|
||||
*
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_print_hdr(const uint8_t *pbuf);
|
||||
|
||||
/**
|
||||
* @brief Print section header description information of ELF.
|
||||
*
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_print_shdr(const uint8_t *pbuf);
|
||||
|
||||
/**
|
||||
* @brief Print section information of ELF.
|
||||
*
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_print_sec(esp_elf_t *elf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "private/elf_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ELF_ALIGN_SIZE
|
||||
#define ELF_ALIGN_SIZE 4
|
||||
#endif
|
||||
|
||||
#define ELF_ALIGN(_a) (((_a) + (ELF_ALIGN_SIZE - 1)) & \
|
||||
(~(ELF_ALIGN_SIZE - 1)))
|
||||
|
||||
/**
|
||||
* @brief Allocate block of memory.
|
||||
*
|
||||
* @param n - Memory size in byte
|
||||
* @param exec - True: memory can run executable code; False: memory can R/W data
|
||||
*
|
||||
* @return Memory pointer if success or NULL if failed.
|
||||
*/
|
||||
void *esp_elf_malloc(uint32_t n, bool exec);
|
||||
|
||||
/**
|
||||
* @brief Free block of memory.
|
||||
*
|
||||
* @param ptr - memory block pointer allocated by "esp_elf_malloc"
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_free(void *ptr);
|
||||
|
||||
/**
|
||||
* @brief Relocates target architecture symbol of ELF
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param rela - Relocated symbol data
|
||||
* @param sym - ELF symbol table
|
||||
* @param addr - Jumping target address
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_arch_relocate(esp_elf_t *elf, const elf32_rela_t *rela,
|
||||
const elf32_sym_t *sym, uint32_t addr);
|
||||
|
||||
/**
|
||||
* @brief Remap symbol from ".data" to ".text" section.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param sym - ELF symbol table
|
||||
*
|
||||
* @return Remapped symbol value
|
||||
*/
|
||||
#ifdef CONFIG_ELF_LOADER_CACHE_OFFSET
|
||||
uintptr_t elf_remap_text(esp_elf_t *elf, uintptr_t sym);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Flush data from cache to external RAM.
|
||||
*
|
||||
* @param None
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
#ifdef CONFIG_ELF_LOADER_LOAD_PSRAM
|
||||
void esp_elf_arch_flush(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize MMU hardware remapping function.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return 0 if success or a negative value if failed.
|
||||
*/
|
||||
#ifdef CONFIG_ELF_LOADER_SET_MMU
|
||||
int esp_elf_arch_init_mmu(esp_elf_t *elf);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief De-initialize MMU hardware remapping function.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
#ifdef CONFIG_ELF_LOADER_SET_MMU
|
||||
void esp_elf_arch_deinit_mmu(esp_elf_t *elf);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define EI_NIDENT 16 /*!< Magic number and other information length */
|
||||
|
||||
/** @brief Section Type */
|
||||
|
||||
#define SHT_NULL 0 /*!< invalid section header */
|
||||
#define SHT_PROGBITS 1 /*!< some useful section like .text, .data .got, .plt .rodata .interp and so on */
|
||||
#define SHT_SYMTAB 2 /*!< symbol table */
|
||||
#define SHT_STRTAB 3 /*!< string table */
|
||||
#define SHT_RELA 4 /*!< relocation table */
|
||||
#define SHT_HASH 5 /*!< HASH table */
|
||||
#define SHT_SYNAMIC 6 /*!< dynamic symbol table */
|
||||
#define SHT_NOTE 7 /*!< note information */
|
||||
#define SHT_NOBITS 8 /*!< .bss */
|
||||
#define SHT_REL 9 /*!< relocation table */
|
||||
#define SHT_SHKIB 10 /*!< reserved but has unspecified semantics. */
|
||||
#define SHT_SYNSYM 11 /*!< dynamic symbol */
|
||||
#define SHT_LOPROC 0x70000000 /*!< reserved for processor-specific semantics */
|
||||
#define SHT_LOUSER 0x7fffffff /*!< lower bound of the range of indexes reserved for application programs */
|
||||
#define SHT_HIUSER 0xffffffff /*!< upper bound of the range of indexes reserved for application programs. */
|
||||
|
||||
/** @brief Section Attribute Flags */
|
||||
|
||||
#define SHF_WRITE 1 /*!< writable when task runs */
|
||||
#define SHF_ALLOC 2 /*!< allocated when task runs */
|
||||
#define SHF_EXECINSTR 4 /*!< machine code */
|
||||
#define SHF_MASKPROG 0xf0000000 /*!< reserved for processor-specific semantics */
|
||||
|
||||
/** @brief Symbol Types */
|
||||
|
||||
#define STT_NOTYPE 0 /*!< symbol type is unspecified */
|
||||
#define STT_OBJECT 1 /*!< data object */
|
||||
#define STT_FUNC 2 /*!< code object */
|
||||
#define STT_SECTION 3 /*!< symbol identifies an ELF section */
|
||||
#define STT_FILE 4 /*!< symbol's name is file name */
|
||||
#define STT_COMMON 5 /*!< common data object */
|
||||
#define STT_TLS 6 /*!< thread-local data object */
|
||||
#define STT_NUM 7 /*!< defined types in generic range */
|
||||
#define STT_LOOS 10 /*!< Low OS specific range */
|
||||
#define STT_HIOS 12 /*!< High OS specific range */
|
||||
#define STT_LOPROC 13 /*!< processor specific range */
|
||||
#define STT_HIPROC 15 /*!< processor specific link range */
|
||||
|
||||
/** @brief Section names */
|
||||
|
||||
#define ELF_BSS ".bss" /*!< uninitialized data */
|
||||
#define ELF_DATA ".data" /*!< initialized data */
|
||||
#define ELF_DEBUG ".debug" /*!< debug */
|
||||
#define ELF_DYNAMIC ".dynamic" /*!< dynamic linking information */
|
||||
#define ELF_DYNSTR ".dynstr" /*!< dynamic string table */
|
||||
#define ELF_DYNSYM ".dynsym" /*!< dynamic symbol table */
|
||||
#define ELF_FINI ".fini" /*!< termination code */
|
||||
#define ELF_GOT ".got" /*!< global offset table */
|
||||
#define ELF_HASH ".hash" /*!< symbol hash table */
|
||||
#define ELF_INIT ".init" /*!< initialization code */
|
||||
#define ELF_REL_DATA ".rel.data" /*!< relocation data */
|
||||
#define ELF_REL_FINI ".rel.fini" /*!< relocation termination code */
|
||||
#define ELF_REL_INIT ".rel.init" /*!< relocation initialization code */
|
||||
#define ELF_REL_DYN ".rel.dyn" /*!< relocaltion dynamic link info */
|
||||
#define ELF_REL_RODATA ".rel.rodata" /*!< relocation read-only data */
|
||||
#define ELF_REL_TEXT ".rel.text" /*!< relocation code */
|
||||
#define ELF_RODATA ".rodata" /*!< read-only data */
|
||||
#define ELF_SHSTRTAB ".shstrtab" /*!< section header string table */
|
||||
#define ELF_STRTAB ".strtab" /*!< string table */
|
||||
#define ELF_SYMTAB ".symtab" /*!< symbol table */
|
||||
#define ELF_TEXT ".text" /*!< code */
|
||||
#define ELF_DATA_REL_RO ".data.rel.ro" /*!< dynamic read-only data */
|
||||
|
||||
/** @brief ELF section and symbol operation */
|
||||
|
||||
#define ELF_SEC_TEXT 0
|
||||
#define ELF_SEC_BSS 1
|
||||
#define ELF_SEC_DATA 2
|
||||
#define ELF_SEC_RODATA 3
|
||||
#define ELF_SEC_DRLRO 4
|
||||
#define ELF_SECS 5
|
||||
|
||||
#define ELF_ST_BIND(_i) ((_i) >> 4)
|
||||
#define ELF_ST_TYPE(_i) ((_i) & 0xf)
|
||||
#define ELF_ST_INFO(_b, _t) (((_b)<<4) + ((_t) & 0xf))
|
||||
|
||||
#define ELF_R_SYM(_i) ((_i) >> 8)
|
||||
#define ELF_R_TYPE(_i) ((unsigned char)(_i))
|
||||
#define ELF_R_INFO(_s, _t) (((_s) << 8) + (unsigned char)(_t))
|
||||
|
||||
#define ELF_SEC_MAP(_elf, _sec, _addr) \
|
||||
((_elf)->sec[(_sec)].addr - \
|
||||
(_elf)->sec[(_sec)].v_addr + \
|
||||
(_addr))
|
||||
|
||||
typedef unsigned int Elf32_Addr;
|
||||
typedef unsigned int Elf32_Off;
|
||||
typedef unsigned int Elf32_Word;
|
||||
typedef unsigned short Elf32_Half;
|
||||
typedef int Elf32_Sword;
|
||||
|
||||
/** @brief ELF Header */
|
||||
|
||||
typedef struct elf32_hdr {
|
||||
unsigned char ident[EI_NIDENT]; /*!< ELF Identification */
|
||||
Elf32_Half type; /*!< object file type */
|
||||
Elf32_Half machine; /*!< machine */
|
||||
Elf32_Word version; /*!< object file version */
|
||||
Elf32_Addr entry; /*!< virtual entry point */
|
||||
Elf32_Off phoff; /*!< program header table offset */
|
||||
Elf32_Off shoff; /*!< section header table offset */
|
||||
Elf32_Word flags; /*!< processor-specific flags */
|
||||
Elf32_Half ehsize; /*!< ELF header size */
|
||||
Elf32_Half phentsize; /*!< program header entry size */
|
||||
Elf32_Half phnum; /*!< number of program header entries */
|
||||
Elf32_Half shentsize; /*!< section header entry size */
|
||||
Elf32_Half shnum; /*!< number of section header entries */
|
||||
Elf32_Half shstrndx; /*!< section header table's "section header string table" entry offset */
|
||||
} elf32_hdr_t;
|
||||
|
||||
/** @brief Section Header */
|
||||
|
||||
typedef struct elf32_shdr {
|
||||
Elf32_Word name; /*!< section index and it is offset in section .shstrtab */
|
||||
Elf32_Word type; /*!< type */
|
||||
Elf32_Word flags; /*!< flags */
|
||||
Elf32_Addr addr; /*!< start address when map to task space */
|
||||
Elf32_Off offset; /*!< offset address from file start address */
|
||||
Elf32_Word size; /*!< size */
|
||||
Elf32_Word link; /*!< link to another section */
|
||||
Elf32_Word info; /*!< additional section information */
|
||||
Elf32_Word addralign; /*!< address align */
|
||||
Elf32_Word entsize; /*!< index table size */
|
||||
} elf32_shdr_t;
|
||||
|
||||
/** @brief Symbol Table Entry */
|
||||
|
||||
typedef struct elf32_sym {
|
||||
Elf32_Word name; /*!< name - index into string table */
|
||||
Elf32_Addr value; /*!< symbol value */
|
||||
Elf32_Word size; /*!< symbol size */
|
||||
unsigned char info; /*!< type and binding */
|
||||
unsigned char other; /*!< 0 - no defined meaning */
|
||||
Elf32_Half shndx; /*!< section header index */
|
||||
} elf32_sym_t;
|
||||
|
||||
/** @brief Relocation entry with implicit addend */
|
||||
|
||||
typedef struct elf32_rel {
|
||||
Elf32_Addr offset; /*!< offset of relocation */
|
||||
Elf32_Word info; /*!< symbol table index and type */
|
||||
} elf32_rel_t;
|
||||
|
||||
/** @brief Relocation entry with explicit addend */
|
||||
|
||||
typedef struct elf32_rela {
|
||||
Elf32_Addr offset; /*!< offset of relocation */
|
||||
Elf32_Word info; /*!< symbol table index and type */
|
||||
Elf32_Sword addend; /*!< Added information */
|
||||
} elf32_rela_t;
|
||||
|
||||
/** @brief ELF section object */
|
||||
|
||||
typedef struct esp_elf_sec {
|
||||
uintptr_t v_addr; /*!< symbol virtual address */
|
||||
off_t offset; /*!< offset in ELF */
|
||||
|
||||
uintptr_t addr; /*!< section physic address in memory */
|
||||
size_t size; /*!< section size */
|
||||
} esp_elf_sec_t;
|
||||
|
||||
/** @brief ELF object */
|
||||
|
||||
typedef struct esp_elf {
|
||||
unsigned char *ptext; /*!< instruction buffer pointer */
|
||||
|
||||
unsigned char *pdata; /*!< data buffer pointer */
|
||||
|
||||
esp_elf_sec_t sec[ELF_SECS]; /*!< ".bss", "data", "rodata", ".text" */
|
||||
|
||||
int (*entry)(int argc, char *argv[]); /*!< Entry pointer of ELF */
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_SET_MMU
|
||||
uint32_t text_off; /* .text symbol offset */
|
||||
|
||||
uint32_t mmu_off; /* MMU unit offset */
|
||||
uint32_t mmu_num; /* MMU unit total number */
|
||||
#endif
|
||||
} esp_elf_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1 @@
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH})
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/errno.h>
|
||||
#include "esp_elf.h"
|
||||
#include "esp_log.h"
|
||||
#include "private/elf_platform.h"
|
||||
|
||||
/** @brief Xtensa relocations defined by the ABIs */
|
||||
|
||||
#define R_XTENSA_NONE 0
|
||||
#define R_XTENSA_32 1
|
||||
#define R_XTENSA_RTLD 2
|
||||
#define R_XTENSA_GLOB_DAT 3
|
||||
#define R_XTENSA_JMP_SLOT 4
|
||||
#define R_XTENSA_RELATIVE 5
|
||||
#define R_XTENSA_PLT 6
|
||||
#define R_XTENSA_OP0 8
|
||||
#define R_XTENSA_OP1 9
|
||||
#define R_XTENSA_OP2 10
|
||||
#define R_XTENSA_ASM_EXPAND 11
|
||||
#define R_XTENSA_ASM_SIMPLIFY 12
|
||||
#define R_XTENSA_GNU_VTINHERIT 15
|
||||
#define R_XTENSA_GNU_VTENTRY 16
|
||||
#define R_XTENSA_DIFF8 17
|
||||
#define R_XTENSA_DIFF16 18
|
||||
#define R_XTENSA_DIFF32 19
|
||||
#define R_XTENSA_SLOT0_OP 20
|
||||
#define R_XTENSA_SLOT1_OP 21
|
||||
#define R_XTENSA_SLOT2_OP 22
|
||||
#define R_XTENSA_SLOT3_OP 23
|
||||
#define R_XTENSA_SLOT4_OP 24
|
||||
#define R_XTENSA_SLOT5_OP 25
|
||||
#define R_XTENSA_SLOT6_OP 26
|
||||
#define R_XTENSA_SLOT7_OP 27
|
||||
#define R_XTENSA_SLOT8_OP 28
|
||||
#define R_XTENSA_SLOT9_OP 29
|
||||
#define R_XTENSA_SLOT10_OP 30
|
||||
#define R_XTENSA_SLOT11_OP 31
|
||||
#define R_XTENSA_SLOT12_OP 32
|
||||
#define R_XTENSA_SLOT13_OP 33
|
||||
#define R_XTENSA_SLOT14_OP 34
|
||||
#define R_XTENSA_SLOT0_ALT 35
|
||||
#define R_XTENSA_SLOT1_ALT 36
|
||||
#define R_XTENSA_SLOT2_ALT 37
|
||||
#define R_XTENSA_SLOT3_ALT 38
|
||||
#define R_XTENSA_SLOT4_ALT 39
|
||||
#define R_XTENSA_SLOT5_ALT 40
|
||||
#define R_XTENSA_SLOT6_ALT 41
|
||||
#define R_XTENSA_SLOT7_ALT 42
|
||||
#define R_XTENSA_SLOT8_ALT 43
|
||||
#define R_XTENSA_SLOT9_ALT 44
|
||||
#define R_XTENSA_SLOT10_ALT 45
|
||||
#define R_XTENSA_SLOT11_ALT 46
|
||||
#define R_XTENSA_SLOT12_ALT 47
|
||||
#define R_XTENSA_SLOT13_ALT 48
|
||||
#define R_XTENSA_SLOT14_ALT 49
|
||||
|
||||
static const char *TAG = "elf_arch";
|
||||
|
||||
/**
|
||||
* @brief Relocates target architecture symbol of ELF
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param rela - Relocated symbol data
|
||||
* @param sym - ELF symbol table
|
||||
* @param addr - Jumping target address
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_arch_relocate(esp_elf_t *elf, const elf32_rela_t *rela,
|
||||
const elf32_sym_t *sym, uint32_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t *where;
|
||||
|
||||
assert(elf && rela);
|
||||
|
||||
where = (uint32_t *)esp_elf_map_sym(elf, rela->offset);
|
||||
|
||||
ESP_LOGD(TAG, "where=%p addr=%x offset=%x\n", where, (int)addr, (int)rela->offset);
|
||||
|
||||
switch (ELF_R_TYPE(rela->info)) {
|
||||
case R_XTENSA_RELATIVE:
|
||||
val = esp_elf_map_sym(elf, *where);
|
||||
#ifdef CONFIG_ELF_LOADER_CACHE_OFFSET
|
||||
*where = elf_remap_text(elf, val);
|
||||
#else
|
||||
*where = val;
|
||||
#endif
|
||||
break;
|
||||
case R_XTENSA_RTLD:
|
||||
break;
|
||||
case R_XTENSA_GLOB_DAT:
|
||||
case R_XTENSA_JMP_SLOT:
|
||||
#ifdef CONFIG_ELF_LOADER_CACHE_OFFSET
|
||||
*where = elf_remap_text(elf, addr);
|
||||
#else
|
||||
*where = addr;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "info=%d is not supported", ELF_R_TYPE(rela->info));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "elf_symbol.h"
|
||||
#include "private/elf_platform.h"
|
||||
|
||||
#define stype(_s, _t) ((_s)->type == (_t))
|
||||
#define sflags(_s, _f) (((_s)->flags & (_f)) == (_f))
|
||||
|
||||
static const char *TAG = "ELF";
|
||||
|
||||
/**
|
||||
* @brief Map symbol's address of ELF to physic space.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param sym - ELF symbol address
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
uintptr_t esp_elf_map_sym(esp_elf_t *elf, uintptr_t sym)
|
||||
{
|
||||
for (int i = 0; i < ELF_SECS; i++) {
|
||||
if ((sym >= elf->sec[i].v_addr) &&
|
||||
(sym < (elf->sec[i].v_addr + elf->sec[i].size))) {
|
||||
return sym - elf->sec[i].v_addr + elf->sec[i].addr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize ELF object.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_init(esp_elf_t *elf)
|
||||
{
|
||||
ESP_LOGI(TAG, "ELF loader version: %d.%d.%d", ELF_LOADER_VER_MAJOR, ELF_LOADER_VER_MINOR, ELF_LOADER_VER_PATCH);
|
||||
|
||||
if (!elf) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(elf, 0, sizeof(esp_elf_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode and relocate ELF data.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_relocate(esp_elf_t *elf, const uint8_t *pbuf)
|
||||
{
|
||||
uint32_t entry;
|
||||
uint32_t size;
|
||||
|
||||
const elf32_hdr_t *phdr;
|
||||
const elf32_shdr_t *pshdr;
|
||||
const char *shstrab;
|
||||
|
||||
if (!elf || !pbuf) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
phdr = (const elf32_hdr_t *)pbuf;
|
||||
pshdr = (const elf32_shdr_t *)(pbuf + phdr->shoff);
|
||||
shstrab = (const char *)pbuf + pshdr[phdr->shstrndx].offset;
|
||||
|
||||
/* Calculate ELF image size */
|
||||
|
||||
for (uint32_t i = 0; i < phdr->shnum; i++) {
|
||||
const char *name = shstrab + pshdr[i].name;
|
||||
|
||||
if (stype(&pshdr[i], SHT_PROGBITS) && sflags(&pshdr[i], SHF_ALLOC)) {
|
||||
if (sflags(&pshdr[i], SHF_EXECINSTR) && !strcmp(ELF_TEXT, name)) {
|
||||
ESP_LOGD(TAG, ".text sec addr=0x%08x size=0x%08x offset=0x%08x",
|
||||
pshdr[i].addr, pshdr[i].size, pshdr[i].offset);
|
||||
|
||||
elf->sec[ELF_SEC_TEXT].v_addr = pshdr[i].addr;
|
||||
elf->sec[ELF_SEC_TEXT].size = ELF_ALIGN(pshdr[i].size);
|
||||
elf->sec[ELF_SEC_TEXT].offset = pshdr[i].offset;
|
||||
|
||||
ESP_LOGD(TAG, ".text offset is 0x%lx size is 0x%x",
|
||||
elf->sec[ELF_SEC_TEXT].offset,
|
||||
elf->sec[ELF_SEC_TEXT].size);
|
||||
} else if (sflags(&pshdr[i], SHF_WRITE) && !strcmp(ELF_DATA, name)) {
|
||||
ESP_LOGD(TAG, ".data sec addr=0x%08x size=0x%08x offset=0x%08x",
|
||||
pshdr[i].addr, pshdr[i].size, pshdr[i].offset);
|
||||
|
||||
elf->sec[ELF_SEC_DATA].v_addr = pshdr[i].addr;
|
||||
elf->sec[ELF_SEC_DATA].size = pshdr[i].size;
|
||||
elf->sec[ELF_SEC_DATA].offset = pshdr[i].offset;
|
||||
|
||||
ESP_LOGD(TAG, ".data offset is 0x%lx size is 0x%x",
|
||||
elf->sec[ELF_SEC_DATA].offset,
|
||||
elf->sec[ELF_SEC_DATA].size);
|
||||
} else if (!strcmp(ELF_RODATA, name)) {
|
||||
ESP_LOGD(TAG, ".rodata sec addr=0x%08x size=0x%08x offset=0x%08x",
|
||||
pshdr[i].addr, pshdr[i].size, pshdr[i].offset);
|
||||
|
||||
elf->sec[ELF_SEC_RODATA].v_addr = pshdr[i].addr;
|
||||
elf->sec[ELF_SEC_RODATA].size = pshdr[i].size;
|
||||
elf->sec[ELF_SEC_RODATA].offset = pshdr[i].offset;
|
||||
|
||||
ESP_LOGD(TAG, ".rodata offset is 0x%lx size is 0x%x",
|
||||
elf->sec[ELF_SEC_RODATA].offset,
|
||||
elf->sec[ELF_SEC_RODATA].size);
|
||||
} else if (!strcmp(ELF_DATA_REL_RO, name)) {
|
||||
ESP_LOGD(TAG, ".data.rel.ro sec addr=0x%08x size=0x%08x offset=0x%08x",
|
||||
pshdr[i].addr, pshdr[i].size, pshdr[i].offset);
|
||||
|
||||
elf->sec[ELF_SEC_DRLRO].v_addr = pshdr[i].addr;
|
||||
elf->sec[ELF_SEC_DRLRO].size = pshdr[i].size;
|
||||
elf->sec[ELF_SEC_DRLRO].offset = pshdr[i].offset;
|
||||
|
||||
ESP_LOGD(TAG, ".data.rel.ro offset is 0x%lx size is 0x%x",
|
||||
elf->sec[ELF_SEC_DRLRO].offset,
|
||||
elf->sec[ELF_SEC_DRLRO].size);
|
||||
}
|
||||
} else if (stype(&pshdr[i], SHT_NOBITS) &&
|
||||
sflags(&pshdr[i], SHF_ALLOC | SHF_WRITE) &&
|
||||
!strcmp(ELF_BSS, name)) {
|
||||
ESP_LOGD(TAG, ".bss sec addr=0x%08x size=0x%08x offset=0x%08x",
|
||||
pshdr[i].addr, pshdr[i].size, pshdr[i].offset);
|
||||
|
||||
elf->sec[ELF_SEC_BSS].v_addr = pshdr[i].addr;
|
||||
elf->sec[ELF_SEC_BSS].size = pshdr[i].size;
|
||||
elf->sec[ELF_SEC_BSS].offset = pshdr[i].offset;
|
||||
|
||||
ESP_LOGD(TAG, ".bss offset is 0x%lx size is 0x%x",
|
||||
elf->sec[ELF_SEC_BSS].offset,
|
||||
elf->sec[ELF_SEC_BSS].size);
|
||||
}
|
||||
}
|
||||
|
||||
/* No .text on image */
|
||||
|
||||
if (!elf->sec[ELF_SEC_TEXT].size) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
elf->ptext = esp_elf_malloc(elf->sec[ELF_SEC_TEXT].size, true);
|
||||
if (!elf->ptext) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
size = elf->sec[ELF_SEC_DATA].size +
|
||||
elf->sec[ELF_SEC_RODATA].size +
|
||||
elf->sec[ELF_SEC_BSS].size +
|
||||
elf->sec[ELF_SEC_DRLRO].size;
|
||||
if (size) {
|
||||
elf->pdata = esp_elf_malloc(size, false);
|
||||
if (!elf->pdata) {
|
||||
esp_elf_free(elf->ptext);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump ".text" from ELF to excutable space memory */
|
||||
|
||||
elf->sec[ELF_SEC_TEXT].addr = (Elf32_Addr)elf->ptext;
|
||||
memcpy(elf->ptext, pbuf + elf->sec[ELF_SEC_TEXT].offset,
|
||||
elf->sec[ELF_SEC_TEXT].size);
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_SET_MMU
|
||||
if (esp_elf_arch_init_mmu(elf)) {
|
||||
esp_elf_free(elf->ptext);
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Dump ".data", ".rodata" and ".bss" from ELF to R/W space memory.
|
||||
*
|
||||
* Todo: Dump ".rodata" to rodata section by MMU/MPU.
|
||||
*/
|
||||
|
||||
if (size) {
|
||||
uint8_t *pdata = elf->pdata;
|
||||
|
||||
if (elf->sec[ELF_SEC_DATA].size) {
|
||||
elf->sec[ELF_SEC_DATA].addr = (uint32_t)pdata;
|
||||
|
||||
memcpy(pdata, pbuf + elf->sec[ELF_SEC_DATA].offset,
|
||||
elf->sec[ELF_SEC_DATA].size);
|
||||
|
||||
pdata += elf->sec[ELF_SEC_DATA].size;
|
||||
}
|
||||
|
||||
if (elf->sec[ELF_SEC_RODATA].size) {
|
||||
elf->sec[ELF_SEC_RODATA].addr = (uint32_t)pdata;
|
||||
|
||||
memcpy(pdata, pbuf + elf->sec[ELF_SEC_RODATA].offset,
|
||||
elf->sec[ELF_SEC_RODATA].size);
|
||||
|
||||
pdata += elf->sec[ELF_SEC_RODATA].size;
|
||||
}
|
||||
|
||||
if (elf->sec[ELF_SEC_DRLRO].size) {
|
||||
elf->sec[ELF_SEC_DRLRO].addr = (uint32_t)pdata;
|
||||
|
||||
memcpy(pdata, pbuf + elf->sec[ELF_SEC_DRLRO].offset,
|
||||
elf->sec[ELF_SEC_DRLRO].size);
|
||||
|
||||
pdata += elf->sec[ELF_SEC_DRLRO].size;
|
||||
}
|
||||
|
||||
if (elf->sec[ELF_SEC_BSS].size) {
|
||||
elf->sec[ELF_SEC_BSS].addr = (uint32_t)pdata;
|
||||
memset(pdata, 0, elf->sec[ELF_SEC_BSS].size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set ELF entry */
|
||||
|
||||
entry = phdr->entry + elf->sec[ELF_SEC_TEXT].addr -
|
||||
elf->sec[ELF_SEC_TEXT].v_addr;
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_CACHE_OFFSET
|
||||
elf->entry = (void *)elf_remap_text(elf, (uintptr_t)entry);
|
||||
#else
|
||||
elf->entry = (void *)entry;
|
||||
#endif
|
||||
|
||||
/* Relocation section data */
|
||||
|
||||
for (uint32_t i = 0; i < phdr->shnum; i++) {
|
||||
if (stype(&pshdr[i], SHT_RELA)) {
|
||||
uint32_t nr_reloc;
|
||||
const elf32_rela_t *rela;
|
||||
const elf32_sym_t *symtab;
|
||||
const char *strtab;
|
||||
|
||||
nr_reloc = pshdr[i].size / sizeof(elf32_rela_t);
|
||||
rela = (const elf32_rela_t *)(pbuf + pshdr[i].offset);
|
||||
symtab = (const elf32_sym_t *)(pbuf + pshdr[pshdr[i].link].offset);
|
||||
strtab = (const char *)(pbuf + pshdr[pshdr[pshdr[i].link].link].offset);
|
||||
|
||||
ESP_LOGD(TAG, "Section %s has %d symbol tables", shstrab + pshdr[i].name, (int)nr_reloc);
|
||||
|
||||
for (int i = 0; i < nr_reloc; i++) {
|
||||
int type;
|
||||
uintptr_t addr = 0;
|
||||
elf32_rela_t rela_buf;
|
||||
|
||||
memcpy(&rela_buf, &rela[i], sizeof(elf32_rela_t));
|
||||
|
||||
const elf32_sym_t *sym = &symtab[ELF_R_SYM(rela_buf.info)];
|
||||
|
||||
type = ELF_R_TYPE(rela->info);
|
||||
if (type == STT_COMMON) {
|
||||
const char *comm_name = strtab + sym->name;
|
||||
|
||||
if (comm_name[0]) {
|
||||
addr = elf_find_sym(comm_name);
|
||||
|
||||
if (!addr) {
|
||||
ESP_LOGE(TAG, "Can't find common %s", strtab + sym->name);
|
||||
esp_elf_free(elf->pdata);
|
||||
esp_elf_free(elf->ptext);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Find common %s addr=%x", comm_name, addr);
|
||||
}
|
||||
} else if (type == STT_FILE) {
|
||||
const char *func_name = strtab + sym->name;
|
||||
|
||||
if (sym->value) {
|
||||
addr = esp_elf_map_sym(elf, sym->value);
|
||||
} else {
|
||||
addr = elf_find_sym(func_name);
|
||||
}
|
||||
|
||||
if (!addr) {
|
||||
ESP_LOGE(TAG, "Can't find symbol %s", func_name);
|
||||
esp_elf_free(elf->pdata);
|
||||
esp_elf_free(elf->ptext);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Find function %s addr=%x", func_name, addr);
|
||||
}
|
||||
|
||||
esp_elf_arch_relocate(elf, &rela_buf, sym, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_LOAD_PSRAM
|
||||
esp_elf_arch_flush();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request running relocated ELF function.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param opt - Request options
|
||||
* @param argc - Arguments number
|
||||
* @param argv - Arguments value array
|
||||
*
|
||||
* @return ESP_OK if sucess or other if failed.
|
||||
*/
|
||||
int esp_elf_request(esp_elf_t *elf, int opt, int argc, char *argv[])
|
||||
{
|
||||
elf->entry(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deinitialize ELF object.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_deinit(esp_elf_t *elf)
|
||||
{
|
||||
if (elf->pdata) {
|
||||
esp_elf_free(elf->pdata);
|
||||
elf->pdata = NULL;
|
||||
}
|
||||
|
||||
if (elf->ptext) {
|
||||
esp_elf_free(elf->ptext);
|
||||
elf->ptext = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_SET_MMU
|
||||
esp_elf_arch_deinit_mmu(elf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print header description information of ELF.
|
||||
*
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_print_hdr(const uint8_t *pbuf)
|
||||
{
|
||||
const char *s_bits, *s_endian;
|
||||
const elf32_hdr_t *hdr = (const elf32_hdr_t *)pbuf;
|
||||
|
||||
switch (hdr->ident[4]) {
|
||||
case 1:
|
||||
s_bits = "32-bit";
|
||||
break;
|
||||
case 2:
|
||||
s_bits = "64-bit";
|
||||
break;
|
||||
default:
|
||||
s_bits = "invalid bits";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (hdr->ident[5]) {
|
||||
case 1:
|
||||
s_endian = "little-endian";
|
||||
break;
|
||||
case 2:
|
||||
s_endian = "big-endian";
|
||||
break;
|
||||
default:
|
||||
s_endian = "invalid endian";
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdr->ident[0] == 0x7f) {
|
||||
ESP_LOGI(TAG, "%-40s %c%c%c", "Class:", hdr->ident[1], hdr->ident[2], hdr->ident[3]);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%-40s %s, %s", "Format:", s_bits, s_endian);
|
||||
ESP_LOGI(TAG, "%-40s %x", "Version(current):", hdr->ident[6]);
|
||||
|
||||
ESP_LOGI(TAG, "%-40s %d", "Type:", hdr->type);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Machine:", hdr->machine);
|
||||
ESP_LOGI(TAG, "%-40s %x", "Version:", hdr->version);
|
||||
ESP_LOGI(TAG, "%-40s %x", "Entry point address:", hdr->entry);
|
||||
ESP_LOGI(TAG, "%-40s %x", "Start of program headers:", hdr->phoff);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Start of section headers:", hdr->shoff);
|
||||
ESP_LOGI(TAG, "%-40s 0x%x", "Flags:", hdr->flags);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Size of this header(bytes):", hdr->ehsize);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Size of program headers(bytes):", hdr->phentsize);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Number of program headers:", hdr->phnum);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Size of section headers(bytes):", hdr->shentsize);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Number of section headers:", hdr->shnum);
|
||||
ESP_LOGI(TAG, "%-40s %d", "Section header string table i:", hdr->shstrndx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print section header description information of ELF.
|
||||
*
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_print_shdr(const uint8_t *pbuf)
|
||||
{
|
||||
const elf32_hdr_t *phdr = (const elf32_hdr_t *)pbuf;
|
||||
const elf32_shdr_t *pshdr = (const elf32_shdr_t *)((size_t)pbuf + phdr->shoff);
|
||||
|
||||
for (int i = 0; i < phdr->shnum; i++) {
|
||||
ESP_LOGI(TAG, "%-40s %d", "name:", pshdr->name);
|
||||
ESP_LOGI(TAG, "%-40s %d", "type:", pshdr->type);
|
||||
ESP_LOGI(TAG, "%-40s 0x%x", "flags:", pshdr->flags);
|
||||
ESP_LOGI(TAG, "%-40s %x", "addr", pshdr->addr);
|
||||
ESP_LOGI(TAG, "%-40s %x", "offset:", pshdr->offset);
|
||||
ESP_LOGI(TAG, "%-40s %d", "size", pshdr->size);
|
||||
ESP_LOGI(TAG, "%-40s 0x%x", "link", pshdr->link);
|
||||
ESP_LOGI(TAG, "%-40s %d", "addralign", pshdr->addralign);
|
||||
ESP_LOGI(TAG, "%-40s %d", "entsize", pshdr->entsize);
|
||||
|
||||
pshdr = (const elf32_shdr_t *)((size_t)pshdr + sizeof(elf32_shdr_t));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print section information of ELF.
|
||||
*
|
||||
* @param pbuf - ELF data buffer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_print_sec(esp_elf_t *elf)
|
||||
{
|
||||
const char *sec_names[ELF_SECS] = {
|
||||
"text", "bss", "data", "rodata"
|
||||
};
|
||||
|
||||
for (int i = 0; i < ELF_SECS; i++) {
|
||||
ESP_LOGI(TAG, "%s: 0x%08x size 0x%08x", sec_names[i], elf->sec[i].addr, elf->sec[i].size);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "entry: %p", elf->entry);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/errno.h>
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "soc/soc.h"
|
||||
#include "private/elf_platform.h"
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_LOAD_PSRAM
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||
#define OFFSET_TEXT_VALUE (SOC_IROM_LOW - SOC_DROM_LOW)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Allocate block of memory.
|
||||
*
|
||||
* @param n - Memory size in byte
|
||||
* @param exec - True: memory can run executable code; False: memory can R/W data
|
||||
*
|
||||
* @return Memory pointer if success or NULL if failed.
|
||||
*/
|
||||
void *esp_elf_malloc(uint32_t n, bool exec)
|
||||
{
|
||||
#ifdef CONFIG_ELF_LOADER_LOAD_PSRAM
|
||||
uint32_t caps = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
|
||||
#else
|
||||
uint32_t caps = exec ? MALLOC_CAP_EXEC : MALLOC_CAP_8BIT;
|
||||
#endif
|
||||
|
||||
return heap_caps_malloc(n, caps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free block of memory.
|
||||
*
|
||||
* @param ptr - memory block pointer allocated by "esp_elf_malloc"
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void esp_elf_free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remap symbol from ".data" to ".text" section.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
* @param sym - ELF symbol table
|
||||
*
|
||||
* @return Remapped symbol value
|
||||
*/
|
||||
#ifdef CONFIG_ELF_LOADER_CACHE_OFFSET
|
||||
uintptr_t elf_remap_text(esp_elf_t *elf, uintptr_t sym)
|
||||
{
|
||||
uintptr_t mapped_sym;
|
||||
esp_elf_sec_t *sec = &elf->sec[ELF_SEC_TEXT];
|
||||
|
||||
if ((sym >= sec->addr) &&
|
||||
(sym < (sec->addr + sec->size))) {
|
||||
#ifdef CONFIG_ELF_LOADER_SET_MMU
|
||||
mapped_sym = sym + elf->text_off;
|
||||
#else
|
||||
mapped_sym = sym + OFFSET_TEXT_VALUE;
|
||||
#endif
|
||||
} else {
|
||||
mapped_sym = sym;
|
||||
}
|
||||
|
||||
return mapped_sym;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Flush data from cache to external RAM.
|
||||
*
|
||||
* @param None
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
#ifdef CONFIG_ELF_LOADER_LOAD_PSRAM
|
||||
void IRAM_ATTR esp_elf_arch_flush(void)
|
||||
{
|
||||
extern void spi_flash_disable_interrupts_caches_and_other_cpu(void);
|
||||
extern void spi_flash_enable_interrupts_caches_and_other_cpu(void);
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
extern void Cache_WriteBack_All(void);
|
||||
|
||||
Cache_WriteBack_All();
|
||||
#else
|
||||
void esp_spiram_writeback_cache(void);
|
||||
|
||||
esp_spiram_writeback_cache();
|
||||
#endif
|
||||
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <reent.h>
|
||||
#include <pthread.h>
|
||||
#include <setjmp.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "elf_symbol.h"
|
||||
|
||||
|
||||
extern int __ltdf2 (double a, double b);
|
||||
extern unsigned int __fixunsdfsi (double a);
|
||||
extern int __gtdf2 (double a, double b);
|
||||
extern double __floatunsidf (unsigned int i);
|
||||
extern double __divdf3 (double a, double b);
|
||||
|
||||
/** @brief Libc public functions symbols look-up table */
|
||||
|
||||
static const struct esp_elfsym g_esp_libc_elfsyms[] = {
|
||||
|
||||
/* string.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(strerror),
|
||||
ESP_ELFSYM_EXPORT(memset),
|
||||
ESP_ELFSYM_EXPORT(memcpy),
|
||||
ESP_ELFSYM_EXPORT(strlen),
|
||||
ESP_ELFSYM_EXPORT(strtod),
|
||||
ESP_ELFSYM_EXPORT(strrchr),
|
||||
ESP_ELFSYM_EXPORT(strchr),
|
||||
ESP_ELFSYM_EXPORT(strcmp),
|
||||
ESP_ELFSYM_EXPORT(strtol),
|
||||
ESP_ELFSYM_EXPORT(strcspn),
|
||||
ESP_ELFSYM_EXPORT(strncat),
|
||||
|
||||
/* stdio.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(puts),
|
||||
ESP_ELFSYM_EXPORT(putchar),
|
||||
ESP_ELFSYM_EXPORT(fputc),
|
||||
ESP_ELFSYM_EXPORT(fputs),
|
||||
ESP_ELFSYM_EXPORT(printf),
|
||||
ESP_ELFSYM_EXPORT(vfprintf),
|
||||
ESP_ELFSYM_EXPORT(fprintf),
|
||||
ESP_ELFSYM_EXPORT(fwrite),
|
||||
|
||||
/* unistd.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(usleep),
|
||||
ESP_ELFSYM_EXPORT(sleep),
|
||||
ESP_ELFSYM_EXPORT(exit),
|
||||
ESP_ELFSYM_EXPORT(close),
|
||||
|
||||
/* stdlib.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(malloc),
|
||||
ESP_ELFSYM_EXPORT(calloc),
|
||||
ESP_ELFSYM_EXPORT(realloc),
|
||||
ESP_ELFSYM_EXPORT(free),
|
||||
|
||||
/* time.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(clock_gettime),
|
||||
ESP_ELFSYM_EXPORT(strftime),
|
||||
|
||||
/* pthread.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(pthread_create),
|
||||
ESP_ELFSYM_EXPORT(pthread_attr_init),
|
||||
ESP_ELFSYM_EXPORT(pthread_attr_setstacksize),
|
||||
ESP_ELFSYM_EXPORT(pthread_detach),
|
||||
ESP_ELFSYM_EXPORT(pthread_join),
|
||||
ESP_ELFSYM_EXPORT(pthread_exit),
|
||||
|
||||
/* newlib */
|
||||
|
||||
ESP_ELFSYM_EXPORT(__errno),
|
||||
ESP_ELFSYM_EXPORT(__getreent),
|
||||
#ifdef __HAVE_LOCALE_INFO__
|
||||
ESP_ELFSYM_EXPORT(__locale_ctype_ptr),
|
||||
#else
|
||||
ESP_ELFSYM_EXPORT(_ctype_),
|
||||
#endif
|
||||
|
||||
/* math */
|
||||
|
||||
ESP_ELFSYM_EXPORT(__ltdf2),
|
||||
ESP_ELFSYM_EXPORT(__fixunsdfsi),
|
||||
ESP_ELFSYM_EXPORT(__gtdf2),
|
||||
ESP_ELFSYM_EXPORT(__floatunsidf),
|
||||
ESP_ELFSYM_EXPORT(__divdf3),
|
||||
|
||||
/* getopt.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(getopt_long),
|
||||
ESP_ELFSYM_EXPORT(optind),
|
||||
ESP_ELFSYM_EXPORT(opterr),
|
||||
ESP_ELFSYM_EXPORT(optarg),
|
||||
ESP_ELFSYM_EXPORT(optopt),
|
||||
|
||||
/* setjmp.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(longjmp),
|
||||
ESP_ELFSYM_EXPORT(setjmp),
|
||||
|
||||
ESP_ELFSYM_END
|
||||
};
|
||||
|
||||
/** @brief ESP-IDF public functions symbols look-up table */
|
||||
|
||||
static const struct esp_elfsym g_esp_espidf_elfsyms[] = {
|
||||
|
||||
/* sys/socket.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(lwip_bind),
|
||||
ESP_ELFSYM_EXPORT(lwip_setsockopt),
|
||||
ESP_ELFSYM_EXPORT(lwip_socket),
|
||||
ESP_ELFSYM_EXPORT(lwip_listen),
|
||||
ESP_ELFSYM_EXPORT(lwip_accept),
|
||||
ESP_ELFSYM_EXPORT(lwip_recv),
|
||||
ESP_ELFSYM_EXPORT(lwip_recvfrom),
|
||||
ESP_ELFSYM_EXPORT(lwip_send),
|
||||
ESP_ELFSYM_EXPORT(lwip_sendto),
|
||||
ESP_ELFSYM_EXPORT(lwip_connect),
|
||||
|
||||
/* arpa/inet.h */
|
||||
|
||||
ESP_ELFSYM_EXPORT(ipaddr_addr),
|
||||
ESP_ELFSYM_EXPORT(lwip_htons),
|
||||
ESP_ELFSYM_EXPORT(lwip_htonl),
|
||||
ESP_ELFSYM_EXPORT(ip4addr_ntoa),
|
||||
|
||||
/* ROM functions */
|
||||
|
||||
ESP_ELFSYM_EXPORT(ets_printf),
|
||||
|
||||
ESP_ELFSYM_END
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS
|
||||
static const struct esp_elfsym* custom_symbols = NULL;
|
||||
void elf_set_custom_symbols(const struct esp_elfsym* symbols) {
|
||||
custom_symbols = symbols;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Find symbol address by name.
|
||||
*
|
||||
* @param sym_name - Symbol name
|
||||
*
|
||||
* @return Symbol address if success or 0 if failed.
|
||||
*/
|
||||
uintptr_t elf_find_sym(const char *sym_name)
|
||||
{
|
||||
const struct esp_elfsym *syms;
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_LIBC_SYMBOLS
|
||||
syms = g_esp_libc_elfsyms;
|
||||
while (syms->name) {
|
||||
if (!strcmp(syms->name, sym_name)) {
|
||||
return (uintptr_t)syms->sym;
|
||||
}
|
||||
|
||||
syms++;
|
||||
}
|
||||
#else
|
||||
syms = g_esp_libc_elfsyms;
|
||||
(void)syms;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_ESPIDF_SYMBOLS
|
||||
syms = g_esp_espidf_elfsyms;
|
||||
while (syms->name) {
|
||||
if (!strcmp(syms->name, sym_name)) {
|
||||
return (uintptr_t)syms->sym;
|
||||
}
|
||||
|
||||
syms++;
|
||||
}
|
||||
#else
|
||||
syms = g_esp_espidf_elfsyms;
|
||||
(void)syms;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS
|
||||
syms = custom_symbols;
|
||||
if (syms != NULL) {
|
||||
while (syms->name) {
|
||||
if (!strcmp(syms->name, sym_name)) {
|
||||
return (uintptr_t)syms->sym;
|
||||
}
|
||||
|
||||
syms++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/errno.h>
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp32s2/rom/cache.h"
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
#include "esp32s2/spiram.h"
|
||||
#endif
|
||||
#include "soc/mmu.h"
|
||||
#include "private/elf_platform.h"
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
#define PSRAM_VADDR_START 0x3f800000
|
||||
#else
|
||||
#define PSRAM_VADDR_START (DRAM0_CACHE_ADDRESS_HIGH - esp_spiram_get_size())
|
||||
#endif
|
||||
|
||||
#define MMU_INVALID BIT(14)
|
||||
#define MMU_UNIT_SIZE 0x10000
|
||||
#define MMU_REG ((volatile uint32_t *)DR_REG_MMU_TABLE)
|
||||
|
||||
#define ESP_MMU_IBUS_BASE IRAM0_ADDRESS_LOW
|
||||
#define ESP_MMU_IBUS_MAX ((IRAM0_ADDRESS_HIGH - IRAM0_ADDRESS_LOW) / \
|
||||
MMU_UNIT_SIZE)
|
||||
#define ESP_MMU_IBUS_OFF (8)
|
||||
|
||||
#define DADDR_2_SECS(v) ((v) / MMU_UNIT_SIZE)
|
||||
#define IADDR_2_SECS(v) ((v) / MMU_UNIT_SIZE)
|
||||
|
||||
#define PSRAM_OFF(v) ((v) - PSRAM_VADDR_START)
|
||||
#define PSRAM_SECS(v) DADDR_2_SECS(PSRAM_OFF((uintptr_t)(v)))
|
||||
#define PSRAM_ALIGN(v) ((uintptr_t)(v) & (~(MMU_UNIT_SIZE - 1)))
|
||||
|
||||
#define ICACHE_ADDR(s) (ESP_MMU_IBUS_BASE + (s) * MMU_UNIT_SIZE)
|
||||
|
||||
extern void spi_flash_disable_interrupts_caches_and_other_cpu(void);
|
||||
extern void spi_flash_enable_interrupts_caches_and_other_cpu(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize MMU hardware remapping function.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return 0 if success or a negative value if failed.
|
||||
*/
|
||||
int IRAM_ATTR esp_elf_arch_init_mmu(esp_elf_t *elf)
|
||||
{
|
||||
int ret;
|
||||
int off;
|
||||
uint32_t ibus_secs;
|
||||
volatile uint32_t dbus_secs;
|
||||
esp_elf_sec_t *sec = &elf->sec[ELF_SEC_TEXT];
|
||||
volatile uint32_t *p = MMU_REG;
|
||||
|
||||
if (sec->size % MMU_UNIT_SIZE) {
|
||||
ibus_secs = IADDR_2_SECS(sec->size) + 1;
|
||||
} else {
|
||||
ibus_secs = IADDR_2_SECS(sec->size);
|
||||
}
|
||||
|
||||
dbus_secs = PSRAM_SECS(elf->ptext);
|
||||
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
|
||||
for (off = ESP_MMU_IBUS_OFF; off < ESP_MMU_IBUS_MAX; off++) {
|
||||
if (p[off] == MMU_INVALID) {
|
||||
int j;
|
||||
|
||||
for (j = 1; j < ibus_secs; j++) {
|
||||
if (p[off + j] != MMU_INVALID) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j >= ibus_secs) {
|
||||
for (int k = 0; k < ibus_secs; k++) {
|
||||
p [off + k] = MMU_ACCESS_SPIRAM | (dbus_secs + k);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
|
||||
if (off >= ESP_MMU_IBUS_MAX) {
|
||||
ret = -EIO;
|
||||
} else {
|
||||
elf->mmu_off = off;
|
||||
elf->mmu_num = ibus_secs;
|
||||
elf->text_off = ICACHE_ADDR(off) - PSRAM_ALIGN(elf->ptext);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief De-initialize MMU hardware remapping function.
|
||||
*
|
||||
* @param elf - ELF object pointer
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void IRAM_ATTR esp_elf_arch_deinit_mmu(esp_elf_t *elf)
|
||||
{
|
||||
volatile int num = elf->mmu_num;
|
||||
volatile int off = elf->mmu_off;
|
||||
volatile uint32_t *p = MMU_REG;
|
||||
|
||||
spi_flash_disable_interrupts_caches_and_other_cpu();
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
p [off + i] = MMU_INVALID;
|
||||
}
|
||||
|
||||
spi_flash_enable_interrupts_caches_and_other_cpu();
|
||||
}
|
||||
Reference in New Issue
Block a user