423 lines
14 KiB
C
423 lines
14 KiB
C
////////////////////////////////
|
|
// 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)){
|
|
good_headers = 1;
|
|
}
|
|
}
|
|
|
|
// 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){
|
|
default:break;
|
|
|
|
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;
|
|
{
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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){
|
|
default:break;
|
|
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;
|
|
}
|
|
}
|
|
}
|