## 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, ESP32-S3, ESP32-C6, ESP32-C61 and ESP32-P4 are supported

### Hardware Required

* A development board based on espressif ESP32/ESP32-S2/ESP32-S3/ESP32-C6/ESP32-C61/ESP32-P4 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.

### Generate the ELF File

The `test_xtensa.elf` or `test_riscv.elf` used for testing is corresponding ELF file generated by [build_elf_file_example](https://github.com/espressif/esp-iot-solution/tree/master/examples/elf_loader/build_elf_file_example), corresponding to the `xtensa` and `risc-v` processor architectures respectively.

In `build_elf_file_example` example, `hello_world.app.elf` will be generated, and you can copy this ELF file to the `elf_loader_example/main`, e.g.
```
    cp build/hello_world.app.elf ../elf_loader_example/main/test_xtensa.elf
```

You can refer to [build_elf_file_example](https://github.com/espressif/esp-iot-solution/tree/master/examples/elf_loader/build_elf_file_example) to generate the ELF file you need.

### Generate functions or variables that can be used by ELF applications

The functions or variables in symbols table can be used by the ELF application, according to your needs, you can use `symbol.py` to generate the following types of symbols table:
1. Generate symbols table based on ELF files.
2. Generate symbols table based on static libraries.

#### Generate symbols table based on ELF files

The `components/elf_loader/src/esp_all_symbol.c` contains functions and variables used by the ELF application, this file is generated by `components/elf_loader/tool/symbols.py`.
This script will generate functions or variables for the current project that can be used by ELF applications.

You can use the ELF file of the current project to generate `components/elf_loader/src/esp_all_symbol.c`. e.g.

1. Enter the `elf_loader_example` directory:

    ```linux
    cd ./esp-iot-solution/examples/elf_loader/elf_loader_example
    ```

2. Use the `idf.py` tool to set the compiler chip, and then compile it, the instructions are:

    ```linux
    # Set compiler chip
    idf.py set-target esp32p4

    # Compile
    idf.py build
    ```

3. Use the `symbols.py` to generate `esp_all_symbol.c`:

    ```linux
    # Generate esp_all_symbol.c based on ELF application
    python ../../../components/elf_loader/tool/symbols.py -u -i main/test_riscv.elf -t e
    ```
    Note: the symbols table are unlinked functions or variables in the ELF application.

    ```linux
    # Generate esp_all_symbol.c based on the ELF of the current project
    python ../../../components/elf_loader/tool/symbols.py -i build/elf-loader.elf -t e
    ```
    Note: the symbols table are functions or variables that have been linked to the project ELF.

#### Generate symbols table based on static libraries

The `components/elf_loader/src/xxx_symbol.c(xxx is the component name, such as esp_wifi ...)` contains functions and variables used by the ELF application, this file is generated by `components/elf_loader/tool/symbols.py`.
This script will generate functions or variables for the current project that can be used by ELF applications.

You can use the ELF file of the current project to generate `components/elf_loader/src/xxx_symbol.c`. e.g.

1. Enter the `elf_loader_example` directory:

    ```linux
    cd ./esp-iot-solution/examples/elf_loader/elf_loader_example
    ```

2. Use the `idf.py` tool to set the compiler chip, and then compile it, the instructions are:

    ```linux
    # Set compiler chip
    idf.py set-target esp32p4

    # Compile
    idf.py build
    ```

3. Use the `symbols.py` to generate `xxx_symbol.c(e.g. esp_wifi_symbol.c)`:

    ```linux
    # generate esp_all_symbol.c
    python ../../../components/elf_loader/tool/symbols.py -i build/esp-idf/esp_wifi/libesp_wifi.a -t l
    ```

4. Add `g_xxx_elfsyms` in `xxx_symbol.c` to `components/elf_loader/src/esp_elf_symbol.c`. e.g: `esp_wifi_symbol.c`

   ```c
   ...
   uintptr_t elf_find_sym(const char *sym_name)
   {
        ...
        extern const struct esp_elfsym g_esp_wifi_elfsyms[];

        syms = g_esp_wifi_elfsyms;
        while (syms->name) {
            if (!strcmp(syms->name, sym_name)) {
                return (uintptr_t)syms->sym;
            }

            syms++;
        }
        ...
    }
   ```

5. Add `xxx_symbol.c` to `components/elf_loader/CMakeLists.txt`. e.g: `esp_wifi_symbol.c`

    ```cmake
    if(CONFIG_ELF_LOADER)
        ...
        list(APPEND srcs "src/esp_wifi_symbol.c")
        ...
    endif()
    ```

### 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
```
