Updated kernel (tl;dr: improved filesystem, tasking, loading files, etc..)

This commit is contained in:
Alex
2023-02-06 19:35:44 +02:00
parent 640f6a412a
commit a592b85ce5
46 changed files with 3503 additions and 2412 deletions

162
Execute/Elf/BaseLoad.cpp Normal file
View File

@ -0,0 +1,162 @@
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::NodeFlags;
namespace Execute
{
ELFBaseLoad ELFLoad(char *Path, const char **argv, const char **envp, Tasking::TaskCompatibility Compatibility)
{
/* We get the base name ("app.elf") */
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
shared_ptr<File> ExFile = vfs->Open(Path);
if (ExFile->Status != FileStatus::OK)
{
vfs->Close(ExFile);
error("Failed to open file: %s", Path);
return {};
}
else
{
if (ExFile->node->Flags != NodeFlags::FILE)
{
vfs->Close(ExFile);
error("Invalid file path: %s", Path);
return {};
}
else if (GetBinaryType(Path) != BinaryType::BinTypeELF)
{
vfs->Close(ExFile);
error("Invalid file type: %s", Path);
return {};
}
}
size_t ExFileSize = ExFile->node->Length;
/* Allocate elf in memory */
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(ExFileSize));
/* Copy the file to the allocated memory */
memcpy(ElfFile, (void *)ExFile->node->Address, ExFileSize);
debug("Image Size: %#lx - %#lx (length: %ld)", ElfFile, (uintptr_t)ElfFile + ExFileSize, ExFileSize);
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
switch (ELFHeader->e_machine)
{
case EM_386:
Arch = TaskArchitecture::x32;
break;
case EM_X86_64:
Arch = TaskArchitecture::x64;
break;
case EM_ARM:
Arch = TaskArchitecture::ARM32;
break;
case EM_AARCH64:
Arch = TaskArchitecture::ARM64;
break;
default:
break;
}
// TODO: This shouldn't be ignored
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS32)
{
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
fixme("ELF32 LSB");
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
fixme("ELF32 MSB");
else
fixme("ELF32 Unknown");
}
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
{
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
fixme("ELF64 LSB");
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
fixme("ELF64 MSB");
else
fixme("ELF64 Unknown");
}
else
fixme("Unknown ELF");
/* ------------------------------------------------------------------------------------------------------------------------------ */
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User, ElfFile);
Memory::Virtual pV = Memory::Virtual(Process->PageTable);
for (size_t i = 0; i < TO_PAGES(ExFileSize); i++)
pV.Remap((void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
// for (size_t i = 0; i < TO_PAGES(ElfLazyResolverSize); i++)
// pV.Remap((void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
/* We prepare the ELF for execution (allocate memory, etc...) */
ELFBaseLoad bl;
switch (ELFHeader->e_type)
{
case ET_REL:
bl = ELFLoadRel(ElfFile, ExFile.Get(), Process);
break;
case ET_EXEC:
bl = ELFLoadExec(ElfFile, ExFile.Get(), Process);
break;
case ET_DYN:
bl = ELFLoadDyn(ElfFile, ExFile.Get(), Process);
break;
case ET_CORE:
{
fixme("ET_CORE not implemented");
TaskManager->RevertProcessCreation(Process);
vfs->Close(ExFile);
return {};
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader->e_type);
vfs->Close(ExFile);
TaskManager->RevertProcessCreation(Process);
return {};
}
}
TCB *Thread = TaskManager->CreateThread(Process,
bl.InstructionPointer,
argv, envp, bl.auxv,
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this
Arch,
Compatibility);
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
Thread->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
}
delete bl.TmpMem;
bl.sd.Process = Process;
bl.sd.Thread = Thread;
bl.sd.Status = ExStatus::OK;
vfs->Close(ExFile);
return bl;
}
}

24
Execute/Elf/Dyn.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
namespace Execute
{
ELFBaseLoad ELFLoadDyn(void *BaseImage,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process)
{
fixme("Not implemented");
return {};
}
}

View File

@ -14,102 +14,62 @@ using namespace Tasking;
namespace Execute
{
void ELFLoadExec(void *BaseImage,
size_t Length,
Elf64_Ehdr *ELFHeader,
Memory::Virtual &pva,
SpawnData *ret,
char *Path,
Tasking::PCB *Process,
const char **argv,
const char **envp,
Tasking::TaskArchitecture Arch,
Tasking::TaskCompatibility Comp)
ELFBaseLoad ELFLoadExec(void *ElfFile,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process)
{
trace("Executable");
Elf64_Phdr *ProgramHeader = (Elf64_Phdr *)(((char *)BaseImage) + ELFHeader->e_phoff);
debug("p_paddr: %#lx | p_vaddr: %#lx | p_filesz: %#lx | p_memsz: %#lx | p_offset: %#lx", ProgramHeader->p_paddr, ProgramHeader->p_vaddr, ProgramHeader->p_filesz, ProgramHeader->p_memsz, ProgramHeader->p_offset);
debug("Executable");
ELFBaseLoad ELFBase = {};
/* This should be deleted inside BaseLoad.cpp */
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
Memory::Virtual pV(Process->PageTable);
uintptr_t BaseAddress = UINTPTR_MAX;
uint64_t ElfAppSize = 0;
uintptr_t EntryPoint = ELFHeader->e_entry;
Elf64_Phdr ItrProgramHeader;
Elf64_Phdr ItrPhdr;
/* Get base address */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
}
debug("BaseAddress %#lx", BaseAddress);
/* Get size */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
uintptr_t SegmentEnd;
SegmentEnd = ItrProgramHeader.p_vaddr - BaseAddress + ItrProgramHeader.p_memsz;
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
}
debug("ElfAppSize %ld", ElfAppSize);
uint8_t *MemoryImage = nullptr;
// check for TEXTREL
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
if (ItrProgramHeader.p_type == DT_TEXTREL)
{
warn("TEXTREL ELF is not fully tested yet!");
MemoryImage = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(ElfAppSize));
memset(MemoryImage, 0, ElfAppSize);
for (uint64_t i = 0; i < TO_PAGES(ElfAppSize); i++)
{
pva.Remap((void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Mapping: %#lx -> %#lx", (uintptr_t)MemoryImage + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
break;
}
}
if (!MemoryImage)
{
debug("Allocating %ld pages for image", TO_PAGES(ElfAppSize));
MemoryImage = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(ElfAppSize));
memset(MemoryImage, 0, ElfAppSize);
for (uint64_t i = 0; i < TO_PAGES(ElfAppSize); i++)
{
uintptr_t Address = (uintptr_t)ProgramHeader->p_vaddr;
Address &= 0xFFFFFFFFFFFFF000;
pva.Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Mapping: %#lx -> %#lx", (uintptr_t)Address + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
}
debug("BaseAddress: %#lx | ElfAppSize: %#lx (%ld, %ld KB)", BaseAddress, ElfAppSize, ElfAppSize, TO_KB(ElfAppSize));
debug("Solving symbols for address: %#llx", (uintptr_t)BaseImage);
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)BaseImage + ELFHeader->e_shoff);
Elf64_Shdr *Dynamic = nullptr;
Elf64_Shdr *DynamicSymbol = nullptr;
/* If required, MemoryImage will be at virtual address. (unless has PIE)
*
* tl;dr this is where the code is stored. */
void *MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, pV, ElfFile, ElfAppSize);
debug("Solving symbols for address: %#llx", (uintptr_t)ElfFile);
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)ElfFile + ELFHeader->e_shoff);
Elf64_Shdr *DynamicString = nullptr;
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf64_Shdr *RelaPlt = nullptr;
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++)
{
char *DynamicStringTable = (char *)((uintptr_t)BaseImage + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
char *DynamicStringTable = (char *)((uintptr_t)ElfFile + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
if (strcmp(DynamicStringTable, ".dynamic") == 0)
{
Dynamic = &ElfSections[i];
debug("Found .dynamic");
}
else if (strcmp(DynamicStringTable, ".dynsym") == 0)
{
DynamicSymbol = &ElfSections[i];
debug("Found .dynsym");
}
else if (strcmp(DynamicStringTable, ".dynstr") == 0)
if (strcmp(DynamicStringTable, ".dynstr") == 0)
{
DynamicString = &ElfSections[i];
debug("Found .dynstr");
@ -119,76 +79,57 @@ namespace Execute
StringTable = &ElfSections[i];
debug("Found .strtab");
}
else if (strcmp(DynamicStringTable, ".rela.plt") == 0)
{
RelaPlt = &ElfSections[i];
debug("Found .rela.plt");
}
else if (strcmp(DynamicStringTable, ".symtab") == 0)
{
SymbolTable = &ElfSections[i];
debug("Found .symtab");
}
else
{
debug("Unknown section: %s", DynamicStringTable);
}
}
UNUSED(Dynamic);
UNUSED(DynamicSymbol);
UNUSED(SymbolTable);
UNUSED(RelaPlt);
char *NeededLibraries[256];
uint64_t InitAddress = 0;
uint64_t FiniAddress = 0;
UNUSED(NeededLibraries);
UNUSED(InitAddress);
UNUSED(FiniAddress);
Vector<char *> NeededLibraries;
if (!DynamicString)
DynamicString = StringTable;
/* Calculate entry point */
memcpy(&ItrPhdr, (uint8_t *)ElfFile + ELFHeader->e_phoff, sizeof(Elf64_Phdr));
if (ItrPhdr.p_vaddr == 0)
EntryPoint += (uintptr_t)MemoryImage;
char InterpreterPath[256];
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
uintptr_t MAddr;
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
switch (ItrProgramHeader.p_type)
switch (ItrPhdr.p_type)
{
case PT_NULL:
fixme("PT_NULL");
break;
case PT_LOAD:
{
debug("PT_LOAD - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
MAddr = (ItrProgramHeader.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
debug("MAddr: %#lx", MAddr);
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
fixme("Address: %#lx %s%s%s", MAddr,
(ItrPhdr.p_flags & PF_R) ? "R" : "",
(ItrPhdr.p_flags & PF_W) ? "W" : "",
(ItrPhdr.p_flags & PF_X) ? "X" : "");
memcpy((void *)MAddr, (uint8_t *)BaseImage + ItrProgramHeader.p_offset, ItrProgramHeader.p_filesz);
debug("memcpy operation: %#lx to %#lx for length %ld", (uint8_t *)BaseImage + ItrProgramHeader.p_offset, MemoryImage + MAddr, ItrProgramHeader.p_filesz);
memcpy((void *)MAddr, (uint8_t *)ElfFile + ItrPhdr.p_offset, ItrPhdr.p_filesz);
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)ElfFile + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
break;
}
case PT_DYNAMIC:
{
debug("PT_DYNAMIC - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)BaseImage + ItrProgramHeader.p_offset);
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)ElfFile + ItrPhdr.p_offset);
for (uint64_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(Elf64_Dyn); i++)
for (size_t i = 0; i < ItrPhdr.p_filesz / sizeof(Elf64_Dyn); i++)
{
switch (Dynamic[i].d_tag)
{
case DT_NULL:
debug("DT_NULL");
break;
case DT_NEEDED:
if (Dynamic[i].d_tag == DT_NEEDED)
{
if (!DynamicString)
{
@ -196,240 +137,71 @@ namespace Execute
break;
}
debug("DT_NEEDED - Name[%ld]: %s", i, (uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr);
NeededLibraries[i] = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr);
break;
char *ReqLib = (char *)kmalloc(256);
strcpy(ReqLib, (char *)((uintptr_t)ElfFile + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr));
debug("DT_NEEDED - Name[%ld]: %s", i, ReqLib);
NeededLibraries.push_back(ReqLib);
}
case DT_PLTRELSZ:
{
fixme("DT_PLTRELSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_PLTGOT:
{
fixme("DT_PLTGOT - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_HASH:
{
fixme("DT_HASH - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_STRTAB:
{
fixme("DT_STRTAB - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_SYMTAB:
{
fixme("DT_SYMTAB - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RELA:
{
fixme("DT_RELA - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RELASZ:
{
fixme("DT_RELASZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_RELAENT:
{
fixme("DT_RELAENT - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_STRSZ:
{
fixme("DT_STRSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_SYMENT:
{
fixme("DT_SYMENT - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_INIT:
{
debug("DT_INIT - Address: %#lx", Dynamic[i].d_un.d_ptr);
InitAddress = Dynamic[i].d_un.d_ptr;
break;
}
case DT_FINI:
{
debug("DT_FINI - Address: %#lx", Dynamic[i].d_un.d_ptr);
FiniAddress = Dynamic[i].d_un.d_ptr;
break;
}
case DT_SONAME:
{
fixme("DT_SONAME - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RPATH:
{
fixme("DT_RPATH - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_SYMBOLIC:
{
fixme("DT_SYMBOLIC - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_REL:
{
fixme("DT_REL - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RELSZ:
{
fixme("DT_RELSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_RELENT:
{
fixme("DT_RELENT - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_PLTREL:
{
fixme("DT_PLTREL - Type: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_DEBUG:
{
fixme("DT_DEBUG - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_TEXTREL:
{
fixme("DT_TEXTREL - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_JMPREL:
{
fixme("DT_JMPREL - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_BIND_NOW:
{
fixme("DT_BIND_NOW - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_INIT_ARRAY:
{
fixme("DT_INIT_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_FINI_ARRAY:
{
fixme("DT_FINI_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_INIT_ARRAYSZ:
{
fixme("DT_INIT_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_FINI_ARRAYSZ:
{
fixme("DT_FINI_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_RUNPATH:
{
fixme("DT_RUNPATH - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_FLAGS:
{
fixme("DT_FLAGS - Flags: %#lx", Dynamic[i].d_un.d_val);
break;
}
case DT_PREINIT_ARRAY:
{
fixme("DT_PREINIT_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_PREINIT_ARRAYSZ:
{
fixme("DT_PREINIT_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
/* ... */
default:
fixme("DT: %ld", Dynamic[i].d_tag);
break;
}
if (Dynamic[i].d_tag == DT_NULL)
else if (Dynamic[i].d_tag == DT_NULL)
break;
}
break;
}
case PT_INTERP: // Do I have to do anything here?
case PT_INTERP:
{
debug("PT_INTERP - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
char InterpreterPath[256];
memcpy((void *)InterpreterPath, (uint8_t *)BaseImage + ItrProgramHeader.p_offset, 256);
fixme("Interpreter: %s", InterpreterPath);
FileSystem::FILE *InterpreterFile = vfs->Open(InterpreterPath);
if (InterpreterFile->Status != FileSystem::FileStatus::OK)
{
memcpy((void *)InterpreterPath, (uint8_t *)ElfFile + ItrPhdr.p_offset, 256);
debug("Interpreter: %s", InterpreterPath);
shared_ptr<VirtualFileSystem::File> InterpreterFile = vfs->Open(InterpreterPath);
if (InterpreterFile->Status != VirtualFileSystem::FileStatus::OK)
warn("Failed to open interpreter file: %s", InterpreterPath);
}
else
{
// TODO: Load interpreter file
fixme("Interpreter file loaded: %s", InterpreterPath);
}
vfs->Close(InterpreterFile);
vfs->Close(InterpreterFile);
break;
}
/* ... */
case PT_PHDR:
{
debug("PT_PHDR - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
break;
}
default:
{
warn("Unknown or unsupported program header type: %d", ItrProgramHeader.p_type);
warn("Unknown or unsupported program header type: %d", ItrPhdr.p_type);
break;
}
}
}
debug("Entry Point: %#lx", ELFHeader->e_entry);
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, pV, InterpreterPath);
Vector<AuxiliaryVector> auxv;
debug("Entry Point: %#lx", EntryPoint);
auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)Path}}});
auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t) "x86_64"}}});
auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)ELFHeader->e_entry}}});
auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage}}});
auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader->e_phnum}}});
auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader->e_phentsize}}});
auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader->e_phoff}}});
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true);
strcpy(aux_platform, "x86_64");
TCB *Thread = TaskManager->CreateThread(Process,
(IP)ELFHeader->e_entry,
argv, envp, auxv,
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this
Arch,
Comp);
ret->Process = Process;
ret->Thread = Thread;
ret->Status = ExStatus::OK;
ELFBase.auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)vfs->GetPathFromNode(ExFile->node).Get()}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader->e_phnum}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader->e_phentsize}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader->e_phoff}}});
ELFBase.InstructionPointer = EntryPoint;
foreach (auto var in NeededLibraries)
kfree(var);
ELFBase.Success = true;
return ELFBase;
}
}

284
Execute/Elf/Parse.cpp Normal file
View File

@ -0,0 +1,284 @@
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
{
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
{
return &GetELFSheader(Header)[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetELFStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
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 (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return (void *)Symbol->st_value;
}
return nullptr;
}
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
{
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
uint64_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;
Elf64_Sym *Symbol = &((Elf64_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 (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uintptr_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
}
}
Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag)
{
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
Elf64_Phdr ItrPhdr;
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr, (uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
if (ItrPhdr.p_type == PT_DYNAMIC)
{
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)ElfFile + ItrPhdr.p_offset);
for (size_t i = 0; i < ItrPhdr.p_filesz / sizeof(Elf64_Dyn); i++)
{
if (Dynamic[i].d_tag == Tag)
{
debug("Found dynamic tag %d at %#lx [d_val: %#lx].", Tag, &Dynamic[i], Dynamic[i].d_un.d_val);
return &Dynamic[i];
}
if (Dynamic[i].d_tag == DT_NULL)
{
debug("Reached end of dynamic tag list for tag %d.", Tag);
return nullptr;
}
}
}
}
debug("Dynamic tag %d not found.", Tag);
return nullptr;
}
void *ELFCreateMemoryImage(Memory::MemMgr *mem, Memory::Virtual &pV, void *ElfFile, size_t Length)
{
void *MemoryImage = nullptr;
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
/* TODO: Not sure what I am supposed to do with this.
* It is supposed to detect if it's PIC or not but I
* don't know if it's right. */
if (ELFGetDynamicTag(ElfFile, DT_TEXTREL))
{
fixme("Text relocation is not(?) tested yet!");
MemoryImage = (uint8_t *)mem->RequestPages(TO_PAGES(Length), true);
memset(MemoryImage, 0, Length);
return MemoryImage;
}
Elf64_Phdr ItrPhdr;
uintptr_t FirstProgramHeaderVirtualAddress = 0x0;
bool FirstProgramHeader = false;
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
if (ItrPhdr.p_type == PT_LOAD && !FirstProgramHeader)
{
FirstProgramHeaderVirtualAddress = ItrPhdr.p_vaddr;
FirstProgramHeader = true;
}
if (ItrPhdr.p_type == PT_LOAD && ItrPhdr.p_vaddr == 0)
{
debug("p_vaddr is 0, allocating %ld pages for image", TO_PAGES(Length));
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
memset(MemoryImage, 0, Length);
return MemoryImage;
}
}
debug("Allocating %ld pages for image", TO_PAGES(Length));
MemoryImage = mem->RequestPages(TO_PAGES(Length));
memset(MemoryImage, 0, Length);
if (FirstProgramHeaderVirtualAddress != 0)
FirstProgramHeaderVirtualAddress &= 0xFFFFFFFFFFFFF000;
else
FirstProgramHeaderVirtualAddress = (uintptr_t)MemoryImage;
for (size_t i = 0; i < TO_PAGES(Length); i++)
{
pV.Remap((void *)((uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Remapped: %#lx -> %#lx", (uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
return MemoryImage;
}
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &pV, const char *Interpreter)
{
if (GetBinaryType((char *)Interpreter) != BinaryType::BinTypeELF)
{
error("Interpreter \"%s\" is not an ELF file.", Interpreter);
return 0;
}
/* No need to check if it's valid, the GetBinaryType() call above does that. */
shared_ptr<VirtualFileSystem::File> File = vfs->Open(Interpreter);
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)File->node->Address;
#ifdef DEBUG
const char *InterpreterType[6] = {
"ET_NONE",
"ET_REL",
"ET_EXEC",
"ET_DYN",
"ET_CORE",
"ET_LOPROC - ET_HIPROC"};
Elf64_Half IntType = ELFHeader->e_type;
if (IntType > 5)
IntType = 5;
debug("Interpreter type: %s - %#x", InterpreterType[IntType], ELFHeader->e_type);
#endif
uintptr_t BaseAddress = UINTPTR_MAX;
uint64_t ElfAppSize = 0;
Elf64_Phdr ItrPhdr;
/* Get base address */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
}
/* Get size */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
uintptr_t SegmentEnd;
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
}
void *MemoryImage = ELFCreateMemoryImage(mem, pV, (void *)File->node->Address, ElfAppSize);
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
if (ItrPhdr.p_type == PT_LOAD)
{
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
fixme("Address: %#lx %s%s%s", MAddr,
(ItrPhdr.p_flags & PF_R) ? "R" : "",
(ItrPhdr.p_flags & PF_W) ? "W" : "",
(ItrPhdr.p_flags & PF_X) ? "X" : "");
memcpy((void *)MAddr, (uint8_t *)File->node->Address + ItrPhdr.p_offset, ItrPhdr.p_filesz);
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)File->node->Address + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
}
}
vfs->Close(File);
debug("Interpreter entry point: %#lx (%#lx + %#lx)", (uintptr_t)MemoryImage + ELFHeader->e_entry,
(uintptr_t)MemoryImage, ELFHeader->e_entry);
return (uintptr_t)MemoryImage + ELFHeader->e_entry;
}
}

93
Execute/Elf/Rel.cpp Normal file
View File

@ -0,0 +1,93 @@
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
ELFBaseLoad ELFLoadRel(void *BaseImage,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process)
{
debug("Relocatable");
/* TODO: I have to fully implement this, but for now I will leave it as it is now. */
warn("Relocatable ELF is not fully supported yet");
/* This should be deleted after with kfree */
ELFBaseLoad ELFBase = {};
/* This should be deleted inside BaseLoad.cpp */
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->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(Process->PageTable);
for (size_t i = 0; i < TO_PAGES(Section->sh_size); i++)
pva.Map((void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), (void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage;
debug("Section %ld", Section->sh_size);
}
}
}
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_REL)
{
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
{
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index];
Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info);
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset);
uint64_t SymbolValue = 0;
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
{
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead)
{
delete ELFBase.TmpMem;
return {};
}
}
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, (uintptr_t)RelAddress);
break;
default:
{
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
delete ELFBase.TmpMem;
return {};
}
}
debug("Symbol value: %#lx", SymbolValue);
}
}
}
return ELFBase;
}
}

View File

@ -26,7 +26,7 @@ namespace Execute
void StartExecuteService()
{
mem = new Memory::MemMgr;
return;
// return;
while (true)
{
@ -53,7 +53,7 @@ namespace Execute
}
}
SharedLibraries *AddLibrary(char *Identifier, void *LibraryImage, size_t Length)
SharedLibraries *AddLibrary(char *Identifier, void *ElfImage, size_t Length, const Memory::Virtual &pV)
{
SmartLock(ExecuteServiceLock);
SharedLibraries sl;
@ -62,12 +62,47 @@ namespace Execute
sl.Timeout = TimeManager->CalculateTarget(600000); /* 10 minutes */
sl.RefCount = 0;
void *BaseLibImage = mem->RequestPages(TO_PAGES(Length));
memcpy(BaseLibImage, (void *)LibraryImage, Length);
sl.Address = BaseLibImage;
void *LibFile = mem->RequestPages(TO_PAGES(Length), true);
memcpy(LibFile, (void *)ElfImage, Length);
Memory::Virtual ncpV = pV;
sl.MemoryImage = ELFCreateMemoryImage(mem, ncpV, LibFile, Length);
{
uintptr_t BaseAddress = UINTPTR_MAX;
Elf64_Phdr ItrProgramHeader;
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)LibFile)->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)LibFile + ((Elf64_Ehdr *)LibFile)->e_phoff + ((Elf64_Ehdr *)LibFile)->e_phentsize * i, sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
}
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)LibFile)->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)LibFile + ((Elf64_Ehdr *)LibFile)->e_phoff + ((Elf64_Ehdr *)LibFile)->e_phentsize * i, sizeof(Elf64_Phdr));
if (ItrProgramHeader.p_type != PT_LOAD)
continue;
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
uintptr_t MAddr = (ItrProgramHeader.p_vaddr - BaseAddress) + (uintptr_t)sl.MemoryImage;
fixme("Address: %#lx %s%s%s", MAddr,
(ItrProgramHeader.p_flags & PF_R) ? "R" : "",
(ItrProgramHeader.p_flags & PF_W) ? "W" : "",
(ItrProgramHeader.p_flags & PF_X) ? "X" : "");
memcpy((void *)MAddr, (uint8_t *)LibFile + ItrProgramHeader.p_offset, ItrProgramHeader.p_filesz);
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)LibFile + ItrProgramHeader.p_offset, (uintptr_t)MAddr, ItrProgramHeader.p_filesz);
break;
}
}
sl.Address = LibFile;
sl.Length = Length;
debug("Library %s loaded at %#lx", Identifier, BaseLibImage);
debug("Library %s loaded at %#lx (full file: %#lx)", Identifier, sl.MemoryImage, LibFile);
Libs.push_back(sl);
return &Libs[Libs.size() - 1];
@ -77,262 +112,4 @@ namespace Execute
{
SmartLock(ExecuteServiceLock);
}
void AttachLibrary(SharedLibraries *Lib, void *BaseImage)
{
SmartLock(ExecuteServiceLock);
BinaryType Type = GetBinaryType(BaseImage);
switch (Type)
{
case BinaryType::BinTypeFex:
{
fixme("Fex is not supported yet");
return;
}
case BinaryType::BinTypeELF:
{
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)BaseImage;
uintptr_t BaseAddress = UINTPTR_MAX;
size_t ElfAppSize = 0;
Elf64_Phdr ItrProgramHeader;
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)BaseImage + ELFHeader->e_shoff);
Elf64_Shdr *Dynamic = nullptr;
Elf64_Shdr *DynamicSymbol = nullptr;
Elf64_Shdr *DynamicString = nullptr;
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf64_Shdr *RelaPlt = nullptr;
Elf64_Shdr *GotPlt = nullptr;
size_t SymbolCount = 0;
size_t GOTSize = 0;
Elf64_Addr *GOTEntry = 0;
uintptr_t RelaOffset = 0;
uint64_t RelaEnt = 0;
size_t RelaSize = 0;
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
}
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
uintptr_t SegmentEnd;
SegmentEnd = ItrProgramHeader.p_vaddr - BaseAddress + ItrProgramHeader.p_memsz;
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++)
{
char *DynamicStringTable = (char *)((uintptr_t)BaseImage + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
if (strcmp(DynamicStringTable, ".dynamic") == 0)
{
Dynamic = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".dynsym") == 0)
{
DynamicSymbol = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".dynstr") == 0)
{
DynamicString = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".strtab") == 0)
{
StringTable = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".rela.plt") == 0)
{
RelaPlt = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".got.plt") == 0)
{
GotPlt = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".symtab") == 0)
{
SymbolTable = &ElfSections[i];
}
}
if (ItrProgramHeader.p_type == PT_DYNAMIC)
{
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)BaseImage + ItrProgramHeader.p_offset);
for (uint64_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(Elf64_Dyn); i++)
{
switch (Dynamic[i].d_tag)
{
case DT_PLTRELSZ:
{
GOTSize = Dynamic[i].d_un.d_val;
break;
}
case DT_PLTGOT:
{
GOTEntry = (Elf64_Addr *)Dynamic[i].d_un.d_ptr;
break;
}
case DT_RELA:
{
RelaOffset = Dynamic[i].d_un.d_ptr;
break;
}
case DT_RELASZ:
{
RelaSize = Dynamic[i].d_un.d_val;
break;
}
case DT_RELAENT:
{
RelaEnt = Dynamic[i].d_un.d_val;
break;
}
default:
break;
}
if (Dynamic[i].d_tag == DT_NULL)
break;
}
break;
}
}
debug("BaseAddress: %#lx Size: %ld", BaseAddress, ElfAppSize);
if (RelaOffset != 0)
{
if (RelaEnt != sizeof(Elf64_Rela))
{
error("RelaEnt != sizeof(Elf64_Rela)");
/* I should exit here I guess... */
}
else
{
for (size_t RelaOffsetItr = 0; RelaOffsetItr < RelaSize; RelaOffsetItr += RelaEnt)
{
Elf64_Rela *Rela = (Elf64_Rela *)(((char *)BaseImage) + RelaOffset + RelaOffsetItr);
switch (Rela->r_info)
{
case R_X86_64_RELATIVE:
{
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)BaseImage + Rela->r_offset);
*Ptr = (uintptr_t)Lib->Address + Rela->r_addend;
break;
}
default:
fixme("Rela: %ld", Rela->r_info);
break;
}
}
}
}
else
debug("No Rela");
if (DynamicSymbol != nullptr)
SymbolCount = DynamicSymbol->sh_size / sizeof(Elf64_Sym);
else if (SymbolTable != nullptr)
SymbolCount = SymbolTable->sh_size / sizeof(Elf64_Sym);
debug("GOT Address %#lx Size %#lx Entry %#lx",
GOTEntry, GOTSize, GOTEntry ? GOTEntry : 0);
#ifdef DEBUG
DumpData("Old GOT", (void *)GOTEntry, GOTSize);
if (DynamicSymbol && DynamicString)
for (size_t i = 0; i < SymbolCount; i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
if (GOTEntry)
if (GOTEntry[i])
{
uintptr_t SymbolAddress = GOTEntry[i];
debug("New GOTEntry[%d] - Symbol %s Address %#lx", i, SymbolName, SymbolAddress);
}
}
for (size_t i = 0; i < GOTSize; i++)
if (GOTEntry)
if (GOTEntry[i])
debug("GOTEntry[%d] = %#lx", i, GOTEntry[i]);
#endif
GOTEntry[1] = (uintptr_t)BaseImage;
GOTEntry[2] = (uintptr_t)ElfLazyResolver;
if (DynamicSymbol && DynamicString && GOTEntry)
for (size_t i = 0; i < SymbolCount; i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
switch (ELF64_ST_TYPE(Symbol->st_info))
{
case STT_OBJECT:
fixme("STT_OBJECT");
case STT_FUNC:
{
uintptr_t SymbolAddress = (uintptr_t)ELFLookupSymbol((Elf64_Ehdr *)Lib->Address, SymbolName);
if (SymbolAddress == 0)
{
error("Symbol %s not found", SymbolName);
continue;
}
GOTEntry[i] = (uintptr_t)Lib->Address + SymbolAddress;
debug("%d %#lx Symbol %s at %#lx (%#lx)", i, &GOTEntry[i], SymbolName, SymbolAddress, (uintptr_t)Lib->Address + SymbolAddress);
break;
}
case STT_NOTYPE:
break;
default:
error("Unsupported symbol type %d", ELF64_ST_TYPE(Symbol->st_info));
break;
}
}
#ifdef DEBUG
DumpData("New GOT", (void *)GOTEntry, GOTSize);
if (DynamicSymbol && DynamicString)
for (size_t i = 0; i < SymbolCount; i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
if (GOTEntry)
if (GOTEntry[i])
{
uintptr_t SymbolAddress = GOTEntry[i];
debug("New GOTEntry[%d] - Symbol %s Address %#lx", i, SymbolName, SymbolAddress);
}
}
for (size_t i = 0; i < GOTSize; i++)
if (GOTEntry)
if (GOTEntry[i])
debug("GOTEntry[%d] = %#lx", i, GOTEntry[i]);
#endif
break;
}
default:
{
fixme("Unsupported binary type %d", Type);
return;
}
}
Lib->RefCount++;
debug("Attached library %s", Lib->Identifier);
}
}