private static uint GetSymValue(Elf_Header *aHeader, int aTableIdx, int aSymIdx) { uint BaseAddress = (uint)aHeader; Elf_Shdr * SymSection = (Elf_Shdr *)(BaseAddress + aHeader->e_shoff) + aTableIdx; Elf32_Sym *SymTab = (Elf32_Sym *)(SymSection->sh_addr) + aSymIdx; switch (SymTab->st_shndx) { case SHN_UNDEF: { var StrTabAdd = ((Elf_Shdr *)(BaseAddress + aHeader->e_shoff) + SymSection->sh_link)->sh_addr; string SymName = new string((sbyte *)(StrTabAdd + SymTab->st_name)); Debug.Write("Undefined Symbol: %s\n", SymName); Heap.Free(SymName); throw new Exception("[ELF]: Extern Symbol not supported"); } case SHN_ABS: return(SymTab->st_value); default: Elf_Shdr *TargetSection = (Elf_Shdr *)(BaseAddress + aHeader->e_shoff) + SymTab->st_shndx; return(TargetSection->sh_addr + SymTab->st_value); } }
private static void RegisterSymbol(Elf_Header *aHeader, Elf_Shdr *aShdr, string aPath) { uint BaseAddress = (uint)aHeader; Elf32_Sym *SymTab = (Elf32_Sym *)aShdr->sh_addr; var StrTabAdd = ((Elf_Shdr *)(BaseAddress + aHeader->e_shoff) + aShdr->sh_link)->sh_addr; uint count = aShdr->sh_size / aShdr->sh_entsize; uint Address; for (uint i = 0; i < count; i++, SymTab++) { uint flag = (uint)(SymTab->st_info >> 4); if (flag == STB_GLOBAL) { switch (SymTab->st_shndx) { case SHN_UNDEF: continue; // for now ignore UNDEF Symbols case SHN_ABS: Address = SymTab->st_value; break; default: var TargetSection = (Elf_Shdr *)(BaseAddress + aHeader->e_shoff) + SymTab->st_shndx; Address = TargetSection->sh_addr + SymTab->st_value; break; } string SymName = new string((sbyte *)(StrTabAdd + SymTab->st_name)); Debug.Write("Symbol: %s\n", SymName); } } }
const uint STB_WEAK = 2; /* Weak, (ie. __attribute__((weak))) */ internal static uint Load(string aPath) { Stream xStream = VirtualFileSystem.GetFile(aPath); if (xStream == null) { throw new Exception("[ELF]: File not found!"); } var xData = new byte[xStream.FileSize]; xStream.Read(xData, xData.Length); uint BaseAddress = xData.GetDataOffset(); Elf_Header *Header = (Elf_Header *)BaseAddress; /* verify ELF header and if this code support this type of elf */ CheckHeader(Header); /* prepare sections and allocate memory (if required) */ Elf_Shdr *Shdr = (Elf_Shdr *)(BaseAddress + Header->e_shoff); for (int i = 0; i < Header->e_shnum; i++, Shdr++) { Shdr->sh_addr = BaseAddress + Shdr->sh_offset; if ((Shdr->sh_flags & SHF_ALLOC) != 0) { LoadSection(BaseAddress, Shdr); } } /* Iterate over all sections and perform relocations */ Shdr = (Elf_Shdr *)(BaseAddress + Header->e_shoff); for (int i = 0; i < Header->e_shnum; i++, Shdr++) { switch (Shdr->sh_type) { case SHT_SYMTAB: { RegisterSymbol(Header, Shdr, aPath); } break; case SHT_REL: { Shdr->sh_addr = BaseAddress + Shdr->sh_offset; Relocate(Header, Shdr); } break; } } uint LoadAddress = Header->e_entry; Heap.Free(xData); return(LoadAddress); }
private static void Relocate(Elf_Header *aHeader, Elf_Shdr *aShdr) { uint BaseAddress = (uint)aHeader; Elf32_Rel *Reloc = (Elf32_Rel *)aShdr->sh_addr; Elf_Shdr * TargetSection = (Elf_Shdr *)(BaseAddress + aHeader->e_shoff) + aShdr->sh_info; uint RelocCount = aShdr->sh_size / aShdr->sh_entsize; byte SymIdx; uint SymVal, RelocType; for (uint i = 0; i < RelocCount; i++, Reloc++) { SymVal = 0; SymIdx = (byte)(Reloc->r_info >> 8); RelocType = Reloc->r_info & 0xFF; if (SymIdx != SHN_UNDEF) { if (RelocType == R_386_PLT32) { SymVal = 0; } else { SymVal = GetSymValue(aHeader, TargetSection->sh_link, SymIdx); } } uint *add_ref = (uint *)(TargetSection->sh_addr + Reloc->r_offset); switch (RelocType) { case R_386_32: *add_ref = SymVal + *add_ref; // S + A break; case R_386_PLT32: // L + A - P case R_386_PC32: // S + A - P default: throw new Exception("[ELF]: Unsupported Relocation type"); } } }
private static void CheckHeader(Elf_Header *aHeader) { /* Check if we are supporting this standard */ var ident = aHeader->e_ident; if ((ident[EI_MAG0] != ELFMAG0) || (ident[EI_MAG1] != ELFMAG1) || (ident[EI_MAG2] != ELFMAG2) || (ident[EI_MAG3] != ELFMAG3)) { throw new Exception("[ELF]: Invalid File format"); } if (ident[EI_CLASS] != ELFCLASS32) { throw new Exception("[ELF]: Unsupported EI_CLASS"); } if (ident[EI_DATA] != ELFDATA2LSB) { throw new Exception("[ELF]: Unsupported EI_DATA"); } if (aHeader->e_machine != EM_386) { throw new Exception("[ELF]: Unsupported Machine Type"); } if (aHeader->e_type != ET_REL) { throw new Exception("[ELF]: Unsupported ELF Type"); } if (aHeader->e_version != EV_CURRENT) { throw new Exception("[ELF]: Unsupported ELF Version"); } }