## ELF console Example

This example shows how to dynamically load shared objects (.so) or ELF applications (.elf) from the file-system and execute them.

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

### Generate the ELF File

The `main/fs_image/xtensa/test_app.elf` or `main/fs_image/xtensa/test_so.elf` (for xtensa architecture) and `main/fs_image/riscv/test_app.elf` or `main/fs_image/riscv/test_so.elf` (for risc-v architecture) used for testing are corresponding ELF files generated by [build_elf_file_example](https://github.com/espressif/esp-iot-solution/tree/master/examples/elf_loader/build_elf_file_example).

In the `build_elf_file_example` example, `hello_world.app.elf` will be generated. **Note:** Xtensa and RISC-V architectures require separate builds and distinct ELF files. You must build the ELF file for the correct architecture before copying.

To build for Xtensa architecture (ESP32/ESP32-S2/ESP32-S3):
1. Set the target to an Xtensa-based chip: `idf.py -G 'Unix Makefiles' set-target esp32` (or esp32s2/esp32s3)
2. Build the project: `idf.py elf`
3. Copy the generated ELF file:
```
    cp build/hello_world.app.elf ../elf_console_example/main/fs_image/xtensa/test_app.elf
```

To build for RISC-V architecture (ESP32-C6/ESP32-C61/ESP32-P4):
1. Set the target to a RISC-V-based chip: `idf.py -G 'Unix Makefiles' set-target esp32c6` (or esp32c61/esp32p4)
2. Build the project: `idf.py elf`
3. Copy the generated ELF file:
```
    cp build/hello_world.app.elf ../elf_console_example/main/fs_image/riscv/test_app.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 the shared library

The `main/fs_image/xtensa/lib.so` (for xtensa architecture) and `main/fs_image/riscv/lib.so` (for risc-v architecture) used for testing are corresponding shared library files generated by [build_shared_library_example](https://github.com/espressif/esp-iot-solution/tree/master/examples/elf_loader/build_shared_library_example).

In the `build_shared_library_example` example, `lib.so` will be generated. **Note:** Xtensa and RISC-V architectures require separate builds and distinct shared library files. You must build the shared library file for the correct architecture before copying.

To build for Xtensa architecture (ESP32/ESP32-S2/ESP32-S3):
1. Set the target to an Xtensa-based chip: `idf.py -G 'Unix Makefiles' set-target esp32` (or esp32s2/esp32s3)
2. Build the project: `idf.py so`
3. Copy the generated shared library:
```
    cp build/lib.so ../elf_console_example/main/fs_image/xtensa/lib.so
```

To build for RISC-V architecture (ESP32-C6/ESP32-C61/ESP32-P4):
1. Set the target to a RISC-V-based chip: `idf.py -G 'Unix Makefiles' set-target esp32c6` (or esp32c61/esp32p4)
2. Build the project: `idf.py so`
3. Copy the generated shared library:
```
    cp build/lib.so ../elf_console_example/main/fs_image/riscv/lib.so
```

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

### Configure the Project

Use the `idf.py` tool to set the target chip:

```sh
idf.py set-target esp32
```

Open the project configuration menu (`idf.py menuconfig`).

In the `Example Configuration` menu:

* Enable the ELF shell command option, then compile the project

```sh
idf.py build
```

### Burn File-System

The LittleFS file system will be mounted by default, so LittleFS image should be burned in advance. Otherwise, the system will fail to start. The reference command is as follows:

```
idf.py storage-flash
```

The burning image is generated by `main/fs_image`, so it will contain the subdirectories and files under the `main/fs_image` directory. You can put the required files into the directory and burn them.

At runtime:

- LittleFS is mounted at `/storage` by default, or the value of `CONFIG_ELF_FILE_SYSTEM_BASE_PATH` if configured.
- The console's working directory starts at `/storage` (the console root maps to the mounted filesystem). Use relative paths from this root when executing ELF apps.

Example mapping: `main/fs_image/xtensa/test_app.elf` is available under the console root as `xtensa/test_app.elf`.

- **Note:** After the file system image is burned again, you will lose the data stored in the previous file system in flash.

### Compile and Download

Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.

(To exit the serial monitor, type `Ctrl-]`.)

### Command Line Tool

The supported commands are as follows:

#### ls

Display the files in the target directory by running the following command:

```
ls <file_or_directory>

    file_or_directory: directory name relative to the console root (/storage)
```

#### free

Display memory heap information, including total, used, and remaining heap size. When PSRAM is enabled, it also can show DRAM and PSRAM memory heap information respectively. The reference command is as follows:

```
free
```

#### mod_load

Dynamically load shared objects from the file system into memory:

```
mod_load <file>

    file: shared objects file name relative to the console root (/storage)
```

#### mod_unload

Unload the shared objects from memory:

```
mod_unload <file>

    file: shared objects file name relative to the console root (/storage)
```

#### list

List dynamically loaded shared objects:

```
list [Configuration parameters]
```

The relevant configuration parameters are described as follows:

```
     -m, --mod  List loaded shared object modules
     -s, --sym  List symbols table in shared object
```

#### exec

Dynamically load ELF applications from the file-system and execute them:

```
exec <file>

    file: ELF application file name relative to the console root (/storage)
```

## Example Output

#### Execute an ELF application

The reference command is as follows. The ELF application corresponds to `main/fs_image/xtensa/test_app.elf` in the project tree and is available under the console root as `xtensa/test_app.elf`:

```sh
ELF> exec xtensa/test_app.elf
```
You will see the following log:

```
Open file:xtensa/test_app.elf, len=1220
I (2952006) ELF: ELF loader version: 1.3.0
Start to relocate ELF file
I (2952006) ELF: elf->entry=0x4008e1cc
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
Success to exit from ELF file
```

#### Execute an ELF application (the ELF application depends on shared libraries)

The reference command is as follows:

```sh
ELF> mod_load xtensa/lib.so
```

You will see the following log:

```
I (3343606) ELF: ELF loader version: 1.3.0
I (3343606) ELF: elf->entry=0x4008df48
I (3343606) ELF: elf->symtab[0], func: fibonacci
I (3343626) ELF: elf->symtab[1], func: try_test
```

```sh
ELF> exec xtensa/test_so.elf
```

You will see the following log:

```
Open file:xtensa/test_so.elf, len=1336
I (3567126) ELF: ELF loader version: 1.3.0
Start to relocate ELF file
I (3567136) ELF: elf->entry=0x4008e2b8
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
fibonacci(10) test
Success to exit from ELF file
```