Kernel/Execute/Parse.cpp
2022-11-07 08:34:22 +02:00

234 lines
8.8 KiB
C++

#include <exec.hpp>
#include <msexec.h>
#include "../kernel.h"
#include "../Fex.hpp"
namespace Execute
{
BinaryType GetBinaryType(char *Path)
{
BinaryType Type = BinaryType::BinTypeInvalid;
FileSystem::FILE *ExFile = vfs->Open(Path);
if (ExFile->Status == FileSystem::FileStatus::OK)
{
if (ExFile->Node->Flags == FileSystem::NodeFlags::FS_FILE)
{
Fex *FexHdr = (Fex *)ExFile->Node->Address;
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ExFile->Node->Address;
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)ExFile->Node->Address;
if (FexHdr->Magic[0] == 'F' && FexHdr->Magic[1] == 'E' && FexHdr->Magic[2] == 'X' && FexHdr->Magic[3] == '\0')
{
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
trace("%s - Fex", Path);
Type = BinaryType::BinTypeFex;
goto Exit;
}
}
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
trace("%s - ELF", Path);
Type = BinaryType::BinTypeELF;
goto Exit;
}
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
trace("%s - NE", Path);
Type = BinaryType::BinTypeNE;
}
else if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
trace("%s - PE", Path);
Type = BinaryType::BinTypePE;
}
else
{
trace("%s - MZ", Path);
Type = BinaryType::BinTypeMZ;
}
goto Exit;
}
/* ... */
Type = BinaryType::BinTypeUnknown;
}
}
Exit:
vfs->Close(ExFile);
return Type;
}
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
static inline Elf64_Shdr *GetElfSheader(Elf64_Ehdr *Header) { return (Elf64_Shdr *)((uint64_t)Header + Header->e_shoff); }
static inline Elf64_Shdr *GetElfSection(Elf64_Ehdr *Header, uint64_t Index) { return &GetElfSheader(Header)[Index]; }
static inline char *GetElfStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetElfSection(Header, Header->e_shstrndx)->sh_offset;
}
static inline char *elf_lookup_string(Elf64_Ehdr *Header, uint64_t Offset)
{
char *StringTable = GetElfStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
static void *ElfLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf64_Sym *Symbol = nullptr;
char *String = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetElfSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetElfSection(Header, shdr->sh_link);
break;
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
return nullptr;
for (uint64_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Symbol = (Elf64_Sym *)((uint64_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
String = (char *)((uint64_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return (void *)Symbol->st_value;
}
return nullptr;
}
static uint64_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint32_t Index)
{
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetElfSection(Header, Table);
uint32_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf32_Sym *Symbol = &((Elf32_Sym *)SymbolAddress)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetElfSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
void *Target = ElfLookupSymbol(Header, Name);
if (Target == nullptr)
{
if (ELF32_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uint64_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetElfSection(Header, Symbol->st_shndx);
return (uint64_t)Header + Symbol->st_value + Target->sh_offset;
}
}
void *ELFLoadRel(Elf64_Ehdr *Header)
{
Elf64_Shdr *shdr = GetElfSheader(Header);
for (uint64_t i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_NOBITS)
{
if (!Section->sh_size)
continue;
if (Section->sh_flags & SHF_ALLOC)
{
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size));
memset(Buffer, 0, Section->sh_size);
Memory::Virtual pva = Memory::Virtual(/* TODO TODO TODO TODO TODO TODO */);
for (uint64_t i = 0; i < TO_PAGES(Section->sh_size); i++)
pva.Map((void *)((uint64_t)Buffer + (i * PAGE_SIZE)), (void *)((uint64_t)Buffer + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
Section->sh_offset = (uint64_t)Buffer - (uint64_t)Header;
debug("Section %ld", Section->sh_size);
}
}
}
for (uint64_t i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_REL)
{
for (uint64_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
{
Elf64_Rel *RelTable = &((Elf64_Rel *)((uint64_t)Header + Section->sh_offset))[Index];
Elf64_Shdr *Target = GetElfSection(Header, Section->sh_info);
uint64_t *RelAddress = (uint64_t *)(((uint64_t)Header + Target->sh_offset) + RelTable->r_offset);
uint64_t SymbolValue = 0;
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
{
SymbolValue = ELFGetSymbolValue(Header, Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead)
return (void *)0xdeadbeef;
}
switch (ELF64_R_TYPE(RelTable->r_info))
{
case R_386_NONE:
break;
case R_386_32:
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
break;
case R_386_PC32:
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uint64_t)RelAddress);
break;
default:
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
return (void *)0xdeadbeef;
}
debug("Symbol value: %#lx", SymbolValue);
}
}
}
return (void *)Header->e_entry;
}
}