[FL-3097] fbt, faploader: minimal app module implementation (#2420)
* fbt, faploader: minimal app module implementation * faploader, libs: moved API hashtable core to flipper_application * example: compound api * lib: flipper_application: naming fixes, doxygen comments * fbt: changed `requires` manifest field behavior for app extensions * examples: refactored plugin apps; faploader: changed new API naming; fbt: changed PLUGIN app type meaning * loader: dropped support for debug apps & plugin menus * moved applications/plugins -> applications/external * Restored x bit on chiplist_convert.py * git: fixed free-dap submodule path * pvs: updated submodule paths * examples: example_advanced_plugins.c: removed potential memory leak on errors * examples: example_plugins: refined requires * fbt: not deploying app modules for debug/sample apps; extra validation for .PLUGIN-type apps * apps: removed cdefines for external apps * fbt: moved ext app path definition * fbt: reworked fap_dist handling; f18: synced api_symbols.csv * fbt: removed resources_paths for extapps * scripts: reworked storage * scripts: reworked runfap.py & selfupdate.py to use new api * wip: fal runner * fbt: moved file packaging into separate module * scripts: storage: fixes * scripts: storage: minor fixes for new api * fbt: changed internal artifact storage details for external apps * scripts: storage: additional fixes and better error reporting; examples: using APP_DATA_PATH() * fbt, scripts: reworked launch_app to deploy plugins; moved old runfap.py to distfap.py * fbt: extra check for plugins descriptors * fbt: additional checks in emitter * fbt: better info message on SDK rebuild * scripts: removed requirements.txt * loader: removed remnants of plugins & debug menus * post-review fixes
This commit is contained in:
@@ -3,10 +3,14 @@
|
||||
#include <elf.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ELF_INVALID_ADDRESS 0xFFFFFFFF
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Interface for ELF loader to resolve symbols
|
||||
*/
|
||||
typedef struct ElfApiInterface {
|
||||
uint16_t api_version_major;
|
||||
uint16_t api_version_minor;
|
||||
bool (*resolver_callback)(const char* name, Elf32_Addr* address);
|
||||
bool (*resolver_callback)(
|
||||
const struct ElfApiInterface* interface,
|
||||
const char* name,
|
||||
Elf32_Addr* address);
|
||||
} ElfApiInterface;
|
||||
|
@@ -17,6 +17,8 @@
|
||||
#define FURI_LOG_D(...)
|
||||
#endif
|
||||
|
||||
#define ELF_INVALID_ADDRESS 0xFFFFFFFF
|
||||
|
||||
#define TRAMPOLINE_CODE_SIZE 6
|
||||
|
||||
/**
|
||||
@@ -166,7 +168,7 @@ static ELFSection* elf_section_of(ELFFile* elf, int index) {
|
||||
static Elf32_Addr elf_address_of(ELFFile* elf, Elf32_Sym* sym, const char* sName) {
|
||||
if(sym->st_shndx == SHN_UNDEF) {
|
||||
Elf32_Addr addr = 0;
|
||||
if(elf->api_interface->resolver_callback(sName, &addr)) {
|
||||
if(elf->api_interface->resolver_callback(elf->api_interface, sName, &addr)) {
|
||||
return addr;
|
||||
}
|
||||
} else {
|
||||
@@ -514,10 +516,13 @@ static SectionType elf_preload_section(
|
||||
section_p->sec_idx = section_idx;
|
||||
|
||||
if(section_header->sh_type == SHT_PREINIT_ARRAY) {
|
||||
furi_assert(elf->preinit_array == NULL);
|
||||
elf->preinit_array = section_p;
|
||||
} else if(section_header->sh_type == SHT_INIT_ARRAY) {
|
||||
furi_assert(elf->init_array == NULL);
|
||||
elf->init_array = section_p;
|
||||
} else if(section_header->sh_type == SHT_FINI_ARRAY) {
|
||||
furi_assert(elf->fini_array == NULL);
|
||||
elf->fini_array = section_p;
|
||||
}
|
||||
|
||||
@@ -605,10 +610,17 @@ ELFFile* elf_file_alloc(Storage* storage, const ElfApiInterface* api_interface)
|
||||
elf->api_interface = api_interface;
|
||||
ELFSectionDict_init(elf->sections);
|
||||
AddressCache_init(elf->trampoline_cache);
|
||||
elf->init_array_called = false;
|
||||
return elf;
|
||||
}
|
||||
|
||||
void elf_file_free(ELFFile* elf) {
|
||||
// furi_check(!elf->init_array_called);
|
||||
if(elf->init_array_called) {
|
||||
FURI_LOG_W(TAG, "Init array was called, but fini array wasn't");
|
||||
elf_file_call_section_list(elf->fini_array, true);
|
||||
}
|
||||
|
||||
// free sections data
|
||||
{
|
||||
ELFSectionDict_it_t it;
|
||||
@@ -774,19 +786,26 @@ ELFFileLoadStatus elf_file_load_sections(ELFFile* elf) {
|
||||
return status;
|
||||
}
|
||||
|
||||
void elf_file_pre_run(ELFFile* elf) {
|
||||
void elf_file_call_init(ELFFile* elf) {
|
||||
furi_check(!elf->init_array_called);
|
||||
elf_file_call_section_list(elf->preinit_array, false);
|
||||
elf_file_call_section_list(elf->init_array, false);
|
||||
elf->init_array_called = true;
|
||||
}
|
||||
|
||||
int32_t elf_file_run(ELFFile* elf, void* args) {
|
||||
int32_t result;
|
||||
result = ((int32_t(*)(void*))elf->entry)(args);
|
||||
return result;
|
||||
bool elf_file_is_init_complete(ELFFile* elf) {
|
||||
return elf->init_array_called;
|
||||
}
|
||||
|
||||
void elf_file_post_run(ELFFile* elf) {
|
||||
void* elf_file_get_entry_point(ELFFile* elf) {
|
||||
furi_check(elf->init_array_called);
|
||||
return (void*)elf->entry;
|
||||
}
|
||||
|
||||
void elf_file_call_fini(ELFFile* elf) {
|
||||
furi_check(elf->init_array_called);
|
||||
elf_file_call_section_list(elf->fini_array, true);
|
||||
elf->init_array_called = false;
|
||||
}
|
||||
|
||||
const ElfApiInterface* elf_file_get_api_interface(ELFFile* elf_file) {
|
||||
|
@@ -82,24 +82,34 @@ bool elf_file_load_section_table(ELFFile* elf_file);
|
||||
ELFFileLoadStatus elf_file_load_sections(ELFFile* elf_file);
|
||||
|
||||
/**
|
||||
* @brief Execute ELF file pre-run stage, call static constructors for example (load stage #3)
|
||||
* @brief Execute ELF file pre-run stage,
|
||||
* call static constructors for example (load stage #3)
|
||||
* Must be done before invoking any code from the ELF file
|
||||
* @param elf
|
||||
*/
|
||||
void elf_file_pre_run(ELFFile* elf);
|
||||
void elf_file_call_init(ELFFile* elf);
|
||||
|
||||
/**
|
||||
* @brief Run ELF file (load stage #4)
|
||||
* @brief Check if ELF file pre-run stage was executed and its code is runnable
|
||||
* @param elf
|
||||
*/
|
||||
bool elf_file_is_init_complete(ELFFile* elf);
|
||||
|
||||
/**
|
||||
* @brief Get actual entry point for ELF file
|
||||
* @param elf_file
|
||||
* @param args
|
||||
* @return int32_t
|
||||
*/
|
||||
int32_t elf_file_run(ELFFile* elf_file, void* args);
|
||||
void* elf_file_get_entry_point(ELFFile* elf_file);
|
||||
|
||||
/**
|
||||
* @brief Execute ELF file post-run stage, call static destructors for example (load stage #5)
|
||||
* @brief Execute ELF file post-run stage,
|
||||
* call static destructors for example (load stage #5)
|
||||
* Must be done if any code from the ELF file was executed
|
||||
* @param elf
|
||||
*/
|
||||
void elf_file_post_run(ELFFile* elf);
|
||||
void elf_file_call_fini(ELFFile* elf);
|
||||
|
||||
/**
|
||||
* @brief Get ELF file API interface
|
||||
|
@@ -45,6 +45,8 @@ struct ELFFile {
|
||||
ELFSection* preinit_array;
|
||||
ELFSection* init_array;
|
||||
ELFSection* fini_array;
|
||||
|
||||
bool init_array_called;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Reference in New Issue
Block a user