|
|
|
@@ -57,8 +57,23 @@ static ELFSection* elf_file_get_section(ELFFile* elf, const char* name) {
|
|
|
|
|
return ELFSectionDict_get(elf->sections, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void elf_file_put_section(ELFFile* elf, const char* name, ELFSection* section) {
|
|
|
|
|
ELFSectionDict_set_at(elf->sections, strdup(name), *section);
|
|
|
|
|
static ELFSection* elf_file_get_or_put_section(ELFFile* elf, const char* name) {
|
|
|
|
|
ELFSection* section_p = elf_file_get_section(elf, name);
|
|
|
|
|
if(!section_p) {
|
|
|
|
|
ELFSectionDict_set_at(
|
|
|
|
|
elf->sections,
|
|
|
|
|
strdup(name),
|
|
|
|
|
(ELFSection){
|
|
|
|
|
.data = NULL,
|
|
|
|
|
.sec_idx = 0,
|
|
|
|
|
.size = 0,
|
|
|
|
|
.rel_count = 0,
|
|
|
|
|
.rel_offset = 0,
|
|
|
|
|
});
|
|
|
|
|
section_p = elf_file_get_section(elf, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return section_p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool elf_read_string_from_offset(ELFFile* elf, off_t offset, FuriString* name) {
|
|
|
|
@@ -320,12 +335,12 @@ static bool elf_relocate_symbol(ELFFile* elf, Elf32_Addr relAddr, int type, Elf3
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool elf_relocate(ELFFile* elf, Elf32_Shdr* h, ELFSection* s) {
|
|
|
|
|
static bool elf_relocate(ELFFile* elf, ELFSection* s) {
|
|
|
|
|
if(s->data) {
|
|
|
|
|
Elf32_Rel rel;
|
|
|
|
|
size_t relEntries = h->sh_size / sizeof(rel);
|
|
|
|
|
size_t relEntries = s->rel_count;
|
|
|
|
|
size_t relCount;
|
|
|
|
|
(void)storage_file_seek(elf->fd, h->sh_offset, true);
|
|
|
|
|
(void)storage_file_seek(elf->fd, s->rel_offset, true);
|
|
|
|
|
FURI_LOG_D(TAG, " Offset Info Type Name");
|
|
|
|
|
|
|
|
|
|
int relocate_result = true;
|
|
|
|
@@ -395,14 +410,6 @@ static bool elf_relocate(ELFFile* elf, Elf32_Shdr* h, ELFSection* s) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************************************************/
|
|
|
|
|
/********************************************* MISC ***********************************************/
|
|
|
|
|
/**************************************************************************************************/
|
|
|
|
|
|
|
|
|
|
static bool cstr_prefix(const char* prefix, const char* string) {
|
|
|
|
|
return strncmp(prefix, string, strlen(prefix)) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************************************************/
|
|
|
|
|
/************************************ Internal FAP interfaces *************************************/
|
|
|
|
|
/**************************************************************************************************/
|
|
|
|
@@ -445,6 +452,31 @@ static bool elf_load_debug_link(ELFFile* elf, Elf32_Shdr* section_header) {
|
|
|
|
|
section_header->sh_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* section_header) {
|
|
|
|
|
if(section_header->sh_size == 0) {
|
|
|
|
|
FURI_LOG_D(TAG, "No data for section");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
section->data = aligned_malloc(section_header->sh_size, section_header->sh_addralign);
|
|
|
|
|
section->size = section_header->sh_size;
|
|
|
|
|
|
|
|
|
|
if(section_header->sh_type == SHT_NOBITS) {
|
|
|
|
|
// BSS section, no data to load
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((!storage_file_seek(elf->fd, section_header->sh_offset, true)) ||
|
|
|
|
|
(storage_file_read(elf->fd, section->data, section_header->sh_size) !=
|
|
|
|
|
section_header->sh_size)) {
|
|
|
|
|
FURI_LOG_E(TAG, " seek/read fail");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FURI_LOG_D(TAG, "0x%X", section->data);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static SectionType elf_preload_section(
|
|
|
|
|
ELFFile* elf,
|
|
|
|
|
size_t section_idx,
|
|
|
|
@@ -453,73 +485,63 @@ static SectionType elf_preload_section(
|
|
|
|
|
FlipperApplicationManifest* manifest) {
|
|
|
|
|
const char* name = furi_string_get_cstr(name_string);
|
|
|
|
|
|
|
|
|
|
const struct {
|
|
|
|
|
const char* prefix;
|
|
|
|
|
SectionType type;
|
|
|
|
|
} lookup_sections[] = {
|
|
|
|
|
{".text", SectionTypeData},
|
|
|
|
|
{".rodata", SectionTypeData},
|
|
|
|
|
{".data", SectionTypeData},
|
|
|
|
|
{".bss", SectionTypeData},
|
|
|
|
|
{".preinit_array", SectionTypeData},
|
|
|
|
|
{".init_array", SectionTypeData},
|
|
|
|
|
{".fini_array", SectionTypeData},
|
|
|
|
|
{".rel.text", SectionTypeRelData},
|
|
|
|
|
{".rel.rodata", SectionTypeRelData},
|
|
|
|
|
{".rel.data", SectionTypeRelData},
|
|
|
|
|
{".rel.preinit_array", SectionTypeRelData},
|
|
|
|
|
{".rel.init_array", SectionTypeRelData},
|
|
|
|
|
{".rel.fini_array", SectionTypeRelData},
|
|
|
|
|
};
|
|
|
|
|
// Load allocable section
|
|
|
|
|
if(section_header->sh_flags & SHF_ALLOC) {
|
|
|
|
|
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
|
|
|
|
section_p->sec_idx = section_idx;
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0; i < COUNT_OF(lookup_sections); i++) {
|
|
|
|
|
if(cstr_prefix(lookup_sections[i].prefix, name)) {
|
|
|
|
|
FURI_LOG_D(TAG, "Found section %s", lookup_sections[i].prefix);
|
|
|
|
|
if(section_header->sh_type == SHT_PREINIT_ARRAY) {
|
|
|
|
|
elf->preinit_array = section_p;
|
|
|
|
|
} else if(section_header->sh_type == SHT_INIT_ARRAY) {
|
|
|
|
|
elf->init_array = section_p;
|
|
|
|
|
} else if(section_header->sh_type == SHT_FINI_ARRAY) {
|
|
|
|
|
elf->fini_array = section_p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(lookup_sections[i].type == SectionTypeRelData) {
|
|
|
|
|
name = name + strlen(".rel");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ELFSection* section_p = elf_file_get_section(elf, name);
|
|
|
|
|
if(!section_p) {
|
|
|
|
|
ELFSection section = {
|
|
|
|
|
.data = NULL,
|
|
|
|
|
.sec_idx = 0,
|
|
|
|
|
.rel_sec_idx = 0,
|
|
|
|
|
.size = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
elf_file_put_section(elf, name, §ion);
|
|
|
|
|
section_p = elf_file_get_section(elf, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(lookup_sections[i].type == SectionTypeRelData) {
|
|
|
|
|
section_p->rel_sec_idx = section_idx;
|
|
|
|
|
} else {
|
|
|
|
|
section_p->sec_idx = section_idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lookup_sections[i].type;
|
|
|
|
|
if(!elf_load_section_data(elf, section_p, section_header)) {
|
|
|
|
|
FURI_LOG_E(TAG, "Error loading section '%s'", name);
|
|
|
|
|
return SectionTypeERROR;
|
|
|
|
|
} else {
|
|
|
|
|
return SectionTypeData;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load link info section
|
|
|
|
|
if(section_header->sh_flags & SHF_INFO_LINK) {
|
|
|
|
|
name = name + strlen(".rel");
|
|
|
|
|
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
|
|
|
|
section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel);
|
|
|
|
|
section_p->rel_offset = section_header->sh_offset;
|
|
|
|
|
return SectionTypeRelData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load symbol table
|
|
|
|
|
if(strcmp(name, ".symtab") == 0) {
|
|
|
|
|
FURI_LOG_D(TAG, "Found .symtab section");
|
|
|
|
|
elf->symbol_table = section_header->sh_offset;
|
|
|
|
|
elf->symbol_count = section_header->sh_size / sizeof(Elf32_Sym);
|
|
|
|
|
return SectionTypeSymTab;
|
|
|
|
|
} else if(strcmp(name, ".strtab") == 0) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load string table
|
|
|
|
|
if(strcmp(name, ".strtab") == 0) {
|
|
|
|
|
FURI_LOG_D(TAG, "Found .strtab section");
|
|
|
|
|
elf->symbol_table_strings = section_header->sh_offset;
|
|
|
|
|
return SectionTypeStrTab;
|
|
|
|
|
} else if(strcmp(name, ".fapmeta") == 0) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load manifest section
|
|
|
|
|
if(strcmp(name, ".fapmeta") == 0) {
|
|
|
|
|
FURI_LOG_D(TAG, "Found .fapmeta section");
|
|
|
|
|
if(elf_load_metadata(elf, section_header, manifest)) {
|
|
|
|
|
return SectionTypeManifest;
|
|
|
|
|
} else {
|
|
|
|
|
return SectionTypeERROR;
|
|
|
|
|
}
|
|
|
|
|
} else if(strcmp(name, ".gnu_debuglink") == 0) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load debug link section
|
|
|
|
|
if(strcmp(name, ".gnu_debuglink") == 0) {
|
|
|
|
|
FURI_LOG_D(TAG, "Found .gnu_debuglink section");
|
|
|
|
|
if(elf_load_debug_link(elf, section_header)) {
|
|
|
|
|
return SectionTypeDebugLink;
|
|
|
|
@@ -531,61 +553,17 @@ static SectionType elf_preload_section(
|
|
|
|
|
return SectionTypeUnused;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool elf_load_section_data(ELFFile* elf, ELFSection* section) {
|
|
|
|
|
Elf32_Shdr section_header;
|
|
|
|
|
if(section->sec_idx == 0) {
|
|
|
|
|
FURI_LOG_D(TAG, "Section is not present");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!elf_read_section_header(elf, section->sec_idx, §ion_header)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(section_header.sh_size == 0) {
|
|
|
|
|
FURI_LOG_D(TAG, "No data for section");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
section->data = aligned_malloc(section_header.sh_size, section_header.sh_addralign);
|
|
|
|
|
section->size = section_header.sh_size;
|
|
|
|
|
|
|
|
|
|
if(section_header.sh_type == SHT_NOBITS) {
|
|
|
|
|
/* section is empty (.bss?) */
|
|
|
|
|
/* no need to memset - allocator already did that */
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((!storage_file_seek(elf->fd, section_header.sh_offset, true)) ||
|
|
|
|
|
(storage_file_read(elf->fd, section->data, section_header.sh_size) !=
|
|
|
|
|
section_header.sh_size)) {
|
|
|
|
|
FURI_LOG_E(TAG, " seek/read fail");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FURI_LOG_D(TAG, "0x%X", section->data);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool elf_relocate_section(ELFFile* elf, ELFSection* section) {
|
|
|
|
|
Elf32_Shdr section_header;
|
|
|
|
|
if(section->rel_sec_idx) {
|
|
|
|
|
if(section->rel_count) {
|
|
|
|
|
FURI_LOG_D(TAG, "Relocating section");
|
|
|
|
|
if(elf_read_section_header(elf, section->rel_sec_idx, §ion_header))
|
|
|
|
|
return elf_relocate(elf, §ion_header, section);
|
|
|
|
|
else {
|
|
|
|
|
FURI_LOG_E(TAG, "Error reading section header");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return elf_relocate(elf, section);
|
|
|
|
|
} else {
|
|
|
|
|
FURI_LOG_D(TAG, "No relocation index"); /* Not an error */
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void elf_file_call_section_list(ELFFile* elf, const char* name, bool reverse_order) {
|
|
|
|
|
ELFSection* section = elf_file_get_section(elf, name);
|
|
|
|
|
|
|
|
|
|
static void elf_file_call_section_list(ELFSection* section, bool reverse_order) {
|
|
|
|
|
if(section && section->size) {
|
|
|
|
|
const uint32_t* start = section->data;
|
|
|
|
|
const uint32_t* end = section->data + section->size;
|
|
|
|
@@ -729,7 +707,6 @@ bool elf_file_load_section_table(ELFFile* elf, FlipperApplicationManifest* manif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
furi_string_free(name);
|
|
|
|
|
FURI_LOG_D(TAG, "Load symbols done");
|
|
|
|
|
|
|
|
|
|
return IS_FLAGS_SET(loaded_sections, SectionTypeValid);
|
|
|
|
|
}
|
|
|
|
@@ -739,16 +716,6 @@ ELFFileLoadStatus elf_file_load_sections(ELFFile* elf) {
|
|
|
|
|
ELFSectionDict_it_t it;
|
|
|
|
|
|
|
|
|
|
AddressCache_init(elf->relocation_cache);
|
|
|
|
|
size_t start = furi_get_tick();
|
|
|
|
|
|
|
|
|
|
for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); ELFSectionDict_next(it)) {
|
|
|
|
|
ELFSectionDict_itref_t* itref = ELFSectionDict_ref(it);
|
|
|
|
|
FURI_LOG_D(TAG, "Loading section '%s'", itref->key);
|
|
|
|
|
if(!elf_load_section_data(elf, &itref->value)) {
|
|
|
|
|
FURI_LOG_E(TAG, "Error loading section '%s'", itref->key);
|
|
|
|
|
status = ELFFileLoadStatusUnspecifiedError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(status == ELFFileLoadStatusSuccess) {
|
|
|
|
|
for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it);
|
|
|
|
@@ -777,14 +744,13 @@ ELFFileLoadStatus elf_file_load_sections(ELFFile* elf) {
|
|
|
|
|
FURI_LOG_D(TAG, "Relocation cache size: %u", AddressCache_size(elf->relocation_cache));
|
|
|
|
|
FURI_LOG_D(TAG, "Trampoline cache size: %u", AddressCache_size(elf->trampoline_cache));
|
|
|
|
|
AddressCache_clear(elf->relocation_cache);
|
|
|
|
|
FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start));
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void elf_file_pre_run(ELFFile* elf) {
|
|
|
|
|
elf_file_call_section_list(elf, ".preinit_array", false);
|
|
|
|
|
elf_file_call_section_list(elf, ".init_array", false);
|
|
|
|
|
elf_file_call_section_list(elf->preinit_array, false);
|
|
|
|
|
elf_file_call_section_list(elf->init_array, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t elf_file_run(ELFFile* elf, void* args) {
|
|
|
|
@@ -794,7 +760,7 @@ int32_t elf_file_run(ELFFile* elf, void* args) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void elf_file_post_run(ELFFile* elf) {
|
|
|
|
|
elf_file_call_section_list(elf, ".fini_array", true);
|
|
|
|
|
elf_file_call_section_list(elf->fini_array, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ElfApiInterface* elf_file_get_api_interface(ELFFile* elf_file) {
|
|
|
|
|