c-scripting/symbol_set.ld_meta/mr4th/exefmt/elf/mr4th_elf.parse.c

413 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)){
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;
}
}
}