//////////////////////////////// // Elf Parse Functions MR4TH_SYMBOL ELF_Parse* elfp_begin(Arena *arena, String8 data){ // magic check B32 elf_magic = 0; ELF_Class elf_class = ELF_Class_NONE; ELF_Encoding elf_encoding = ELF_Encoding_NONE; U32 elf_version = 0; ELF_OsAbiExtension elf_ext = ELF_OsAbiExtension_NONE; B32 good_headers = 0; if (data.size >= ELF_NUM_IDENT){ elf_class = data.str[ELF_IdentificationIdx_CLASS]; elf_encoding = data.str[ELF_IdentificationIdx_DATA]; elf_version = data.str[ELF_IdentificationIdx_VERSION]; elf_ext = data.str[ELF_IdentificationIdx_OSABI]; if (data.str[0] == ELF_Magic_Byte0 && data.str[1] == ELF_Magic_Byte1 && data.str[2] == ELF_Magic_Byte2 && data.str[3] == ELF_Magic_Byte3 && elf_version == 1 && (elf_class == ELF_Class_32 || elf_class == ELF_Class_64) && (elf_encoding == ELF_Encoding_2LSB || elf_encoding == ELF_Encoding_2MSB)){ switch (elf_class){ case ELF_Class_32: { if (data.size >= sizeof(ELF_Header32)){ good_headers = 1; } }break; case ELF_Class_64: { if (data.size >= sizeof(ELF_Header64)){ good_headers = 1; } }break; } } } // header void *header = 0; U64 section_table_foff = 0; U16 section_count = 0; U16 section_size = 0; U64 segment_table_foff = 0; U16 segment_count = 0; U16 segment_size = 0; U16 string_section_index = 0; if (good_headers){ switch (elf_class){ case ELF_Class_32: { if (sizeof(ELF_Header32) <= data.size){ header = data.str; ELF_Header32 *h = (ELF_Header32*)header; section_table_foff = h->section_table_foff; section_count = h->section_count; section_size = h->section_size; segment_table_foff = h->segment_table_foff; segment_count = h->segment_count; segment_size = h->segment_size; string_section_index = h->string_section_index; } }break; case ELF_Class_64: { if (sizeof(ELF_Header64) <= data.size){ header = data.str; ELF_Header64 *h = (ELF_Header64*)header; section_table_foff = h->section_table_foff; section_count = h->section_count; section_size = h->section_size; segment_table_foff = h->segment_table_foff; segment_count = h->segment_count; segment_size = h->segment_size; string_section_index = h->string_section_index; } }break; } } // sections void *sections = 0; if (section_count > 0 && section_table_foff + section_count*section_size <= data.size){ sections = data.str + section_table_foff; } // segments void *segments = 0; if (segment_count > 0 && segment_table_foff + segment_count*segment_size <= data.size){ segments = data.str + segment_table_foff; } // string table U8 *section_strtable_first = 0; U8 *section_strtable_opl = 0; if (sections != 0){ U32 index = 0; if (string_section_index != ELF_SectionIndex_UNDEF && string_section_index != ELF_SectionIndex_XINDEX){ index = string_section_index; } else if (string_section_index == ELF_SectionIndex_XINDEX){ switch (elf_class){ case ELF_Class_32: index = ((ELF_Section32*)sections)->link; break; case ELF_Class_64: index = ((ELF_Section64*)sections)->link; break; } } if (index > 0){ U64 offset = 0; U64 size = 0; switch (elf_class){ case ELF_Class_32: { offset = ((ELF_Section32*)sections)[index].offset; size = ((ELF_Section32*)sections)[index].size; }break; case ELF_Class_64: { offset = ((ELF_Section64*)sections)[index].offset; size = ((ELF_Section64*)sections)[index].size; }break; } if (offset < data.size && offset + size < data.size){ section_strtable_first = data.str + offset; section_strtable_opl = data.str + offset + size; } } } // find symtab & dynsym sections void *symbols[ELFP_SYMBOL_TABLE_COUNT] = {0}; U32 symbol_count[ELFP_SYMBOL_TABLE_COUNT] = {0}; U8 *symbol_strtable_first[ELFP_SYMBOL_TABLE_COUNT] = {0}; U8 *symbol_strtable_opl[ELFP_SYMBOL_TABLE_COUNT] = {0}; if (sections != 0){ for (U32 i = 0; i < section_count; i += 1){ ELF_SectionType type = 0; U64 foff = 0; U64 opl = 0; switch (elf_class){ case ELF_Class_32: { ELF_Section32 *sec32 = (ELF_Section32*)sections + i; type = sec32->type; foff = sec32->offset; opl = foff + sec32->size; }break; case ELF_Class_64: { ELF_Section64 *sec64 = (ELF_Section64*)sections + i; type = sec64->type; foff = sec64->offset; opl = foff + sec64->size; }break; } U32 idx = ELFP_SYMBOL_TABLE_COUNT; switch (type){ case ELF_SectionType_SYMTAB: idx = ELFP_SYMBOL_TABLE_symtab; break; case ELF_SectionType_DYNSYM: idx = ELFP_SYMBOL_TABLE_dynsym; break; } if (idx < ELFP_SYMBOL_TABLE_COUNT && foff < data.size && opl < data.size){ U32 link = 0; //U32 info = 0; U32 count = 0; switch (elf_class){ case ELF_Class_32: { ELF_Section32 *sec32 = (ELF_Section32*)sections + i; link = sec32->link; //info = sec32->info; count = sec32->size/sizeof(ELF_Symbol32); }break; case ELF_Class_64: { ELF_Section64 *sec64 = (ELF_Section64*)sections + i; link = sec64->link; //info = sec64->info; count = sec64->size/sizeof(ELF_Symbol64); }break; } symbols[idx] = data.str + foff; symbol_count[idx] = count; if (link < section_count){ U64 strtable_off = 0; U64 strtable_size = 0; switch (elf_class){ case ELF_Class_32: { ELF_Section32 *sec32 = (ELF_Section32*)sections + link; strtable_off = sec32->offset; strtable_size = sec32->size; }break; case ELF_Class_64: { ELF_Section64 *sec64 = (ELF_Section64*)sections + link; strtable_off = sec64->offset; strtable_size = sec64->size; }break; } if (strtable_off < data.size && strtable_off + strtable_size < data.size){ symbol_strtable_first[idx] = data.str + strtable_off; symbol_strtable_opl[idx] = data.str + strtable_off + strtable_size; } } } } } // fill result ELF_Parse *elf = 0; if (header != 0){ elf = push_array(arena, ELF_Parse, 1); elf->elf_class = elf_class; elf->encoding = elf_encoding; elf->section_count = section_count; elf->segment_count = segment_count; elf->header = header; elf->size = data.size; elf->sections = sections; elf->segments = segments; elf->section_strtable_first = section_strtable_first; elf->section_strtable_opl = section_strtable_opl; MemoryCopyArray(elf->symbols, symbols); MemoryCopyArray(elf->symbol_count, symbol_count); MemoryCopyArray(elf->symbol_strtable_first, symbol_strtable_first); MemoryCopyArray(elf->symbol_strtable_opl, symbol_strtable_opl); } return(elf); } MR4TH_SYMBOL void elfp_header_read(ELF_Parse *elf, ELF_Header64 *out){ if (elf->header != 0){ switch (elf->elf_class){ case ELF_Class_32: { elf_header64_from_header32(out, (ELF_Header32*)elf->header, elf->encoding); }break; case ELF_Class_64: { elf_header64_from_header64(out, (ELF_Header64*)elf->header, elf->encoding); }break; } } } MR4TH_SYMBOL U32 elfp_section_count(ELF_Parse *elf){ U32 result = elf->section_count; return(result); } MR4TH_SYMBOL void elfp_section_read(ELF_Parse *elf, U32 idx, ELF_Section64 *out){ if (elf->sections != 0 && idx < elf->section_count){ switch (elf->elf_class){ case ELF_Class_32: { elf_section64_from_section32(out, (ELF_Section32*)elf->sections + idx, elf->encoding); }break; case ELF_Class_64: { elf_section64_from_section64(out, (ELF_Section64*)elf->sections + idx, elf->encoding); }break; } } } MR4TH_SYMBOL String8 elfp_section_name(ELF_Parse *elf, U32 idx){ String8 result = {0}; if (elf->sections != 0 && idx < elf->section_count){ U32 name = 0; switch (elf->elf_class){ case ELF_Class_32: name = ((ELF_Section32*)elf->sections)[idx].name; break; case ELF_Class_64: name = ((ELF_Section64*)elf->sections)[idx].name; break; } result = str8_cstring_capped(elf->section_strtable_first + name, elf->section_strtable_opl); } return(result); } MR4TH_SYMBOL U32 elfp_segment_count(ELF_Parse *elf){ U32 result = elf->segment_count; return(result); } MR4TH_SYMBOL void elfp_segment_read(ELF_Parse *elf, U32 idx, ELF_Segment64 *out){ if (elf->segments != 0 && idx < elf->segment_count){ switch (elf->elf_class){ case ELF_Class_32: { elf_segment64_from_segment32(out, (ELF_Segment32*)elf->segments + idx, elf->encoding); }break; case ELF_Class_64: { elf_segment64_from_segment64(out, (ELF_Segment64*)elf->segments + idx, elf->encoding); }break; } } } MR4TH_SYMBOL U32 elfp_symbol_count(ELF_Parse *elf, U32 table){ U32 result = 0; if (table < ELFP_SYMBOL_TABLE_COUNT){ result = elf->symbol_count[table]; } return(result); } MR4TH_SYMBOL void elfp_symbol_read(ELF_Parse *elf, U32 table, U32 idx, ELF_Symbol64 *out){ if (table < ELFP_SYMBOL_TABLE_COUNT){ void *symbols = elf->symbols[table]; switch (elf->elf_class){ case ELF_Class_32: { elf_symbol64_from_symbol32(out, (ELF_Symbol32*)symbols + idx, elf->encoding); }break; case ELF_Class_64: { elf_symbol64_from_symbol64(out, (ELF_Symbol64*)symbols + idx, elf->encoding); }break; } } } MR4TH_SYMBOL String8 elfp_symbol_name(ELF_Parse *elf, U32 table, U32 idx){ String8 result = {0}; if (table < ELFP_SYMBOL_TABLE_COUNT){ void *s = elf->symbols[table]; U8 *string_table_first = elf->symbol_strtable_first[table]; U8 *string_table_opl = elf->symbol_strtable_opl[table]; U32 name = 0; switch (elf->elf_class){ case ELF_Class_32: name = ((ELF_Symbol32*)s)[idx].name; break; case ELF_Class_64: name = ((ELF_Symbol64*)s)[idx].name; break; } if (string_table_first != 0){ result = str8_cstring_capped(string_table_first + name, string_table_opl); } } return(result); } MR4TH_SYMBOL U32 elfp_relocs_count(ELF_Parse *elf, U32 secidx){ U32 result = 0; if (elf->sections != 0 && secidx < elf->section_count){ switch (elf->elf_class){ case ELF_Class_32: { ELF_Section32 *sec32 = ((ELF_Section32*)elf->sections) + secidx; switch (sec32->type){ case ELF_SectionType_REL: result = sec32->size/sizeof(ELF_Relocation32); break; case ELF_SectionType_RELA: result = sec32->size/sizeof(ELF_RelocationAdd32); break; } }break; case ELF_Class_64: { ELF_Section64 *sec64 = ((ELF_Section64*)elf->sections) + secidx; switch (sec64->type){ case ELF_SectionType_REL: result = sec64->size/sizeof(ELF_Relocation64); break; case ELF_SectionType_RELA: result = sec64->size/sizeof(ELF_RelocationAdd64); break; } }break; } } return(result); } MR4TH_SYMBOL void elfp_relocs_read(ELF_Parse *elf, U32 secidx, U32 relocidx, ELF_RelocationAdd64 *out){ if (elf->sections != 0 && secidx < elf->section_count){ switch (elf->elf_class){ case ELF_Class_32: { ELF_Section32 *sec32 = ((ELF_Section32*)elf->sections) + secidx; U64 opl = ClampTop(sec32->offset + sec32->size, elf->size); U64 size = opl - sec32->offset; switch (sec32->type){ case ELF_SectionType_REL: { ELF_Relocation32 *relocs = (ELF_Relocation32*)((U8*)elf->header + sec32->offset); U32 count = sec32->size/sizeof(*relocs); if (relocidx < count){ elf_reloca64_from_reloc32(out, relocs + relocidx, elf->encoding); } }break; case ELF_SectionType_RELA: { ELF_RelocationAdd32 *relocs = (ELF_RelocationAdd32*)((U8*)elf->header + sec32->offset); U32 count = sec32->size/sizeof(*relocs); if (relocidx < count){ elf_reloca64_from_reloca32(out, relocs + relocidx, elf->encoding); } }break; } }break; case ELF_Class_64: { ELF_Section64 *sec64 = ((ELF_Section64*)elf->sections) + secidx; U64 opl = ClampTop(sec64->offset + sec64->size, elf->size); U64 size = opl - sec64->offset; switch (sec64->type){ case ELF_SectionType_REL: { ELF_Relocation64 *relocs = (ELF_Relocation64*)((U8*)elf->header + sec64->offset); U32 count = sec64->size/sizeof(*relocs); if (relocidx < count){ elf_reloca64_from_reloc64(out, relocs + relocidx, elf->encoding); } }break; case ELF_SectionType_RELA: { ELF_RelocationAdd64 *relocs = (ELF_RelocationAdd64*)((U8*)elf->header + sec64->offset); U32 count = sec64->size/sizeof(*relocs); if (relocidx < count){ elf_reloca64_from_reloca64(out, relocs + relocidx, elf->encoding); } }break; } }break; } } }