Support for building and running external apps (#112)
This commit is contained in:
committed by
GitHub
parent
42e843b463
commit
415442e410
@@ -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