mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-13 16:29:21 +00:00
Update kernel
This commit is contained in:
171
Execute/BinaryParse.cpp
Normal file
171
Execute/BinaryParse.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <msexec.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
#include "../Fex.hpp"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
BinaryType GetBinaryType(void *Image)
|
||||
{
|
||||
Fex *FexHdr = (Fex *)Image;
|
||||
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Image;
|
||||
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Image;
|
||||
|
||||
/* Check Fex magic */
|
||||
if (FexHdr->Magic[0] == 'F' &&
|
||||
FexHdr->Magic[1] == 'E' &&
|
||||
FexHdr->Magic[2] == 'X' &&
|
||||
FexHdr->Magic[3] == '\0')
|
||||
{
|
||||
/* If the fex type is driver, we shouldn't return as Fex. */
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
debug("Image - Fex");
|
||||
return BinaryType::BinTypeFex;
|
||||
}
|
||||
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
|
||||
{
|
||||
debug("Fex Driver is not supposed to be executed.");
|
||||
}
|
||||
}
|
||||
/* Check ELF magic. */
|
||||
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)
|
||||
{
|
||||
debug("Image - ELF");
|
||||
return BinaryType::BinTypeELF;
|
||||
}
|
||||
/* Every Windows executable starts with MZ header. */
|
||||
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Image) + MZHeader->e_lfanew);
|
||||
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Image) + MZHeader->e_lfanew);
|
||||
|
||||
/* TODO: LE, EDOS */
|
||||
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
debug("Image - PE");
|
||||
return BinaryType::BinTypePE;
|
||||
}
|
||||
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
|
||||
{
|
||||
debug("Image - NE");
|
||||
return BinaryType::BinTypeNE;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Image - MZ");
|
||||
return BinaryType::BinTypeMZ;
|
||||
}
|
||||
}
|
||||
|
||||
/* ... */
|
||||
return BinaryType::BinTypeUnknown;
|
||||
}
|
||||
|
||||
BinaryType GetBinaryType(char *Path)
|
||||
{
|
||||
BinaryType Type = BinaryType::BinTypeInvalid;
|
||||
VirtualFileSystem::File ExFile = vfs->Open(Path);
|
||||
|
||||
if (!ExFile.IsOK())
|
||||
{
|
||||
vfs->Close(ExFile);
|
||||
return Type;
|
||||
}
|
||||
|
||||
debug("File opened: %s", Path);
|
||||
uint8_t *Buffer = new uint8_t[1024];
|
||||
vfs->Read(ExFile, Buffer, 128);
|
||||
|
||||
Fex *FexHdr = (Fex *)Buffer;
|
||||
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Buffer;
|
||||
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Buffer;
|
||||
|
||||
/* Check Fex header. */
|
||||
if (FexHdr->Magic[0] == 'F' &&
|
||||
FexHdr->Magic[1] == 'E' &&
|
||||
FexHdr->Magic[2] == 'X' &&
|
||||
FexHdr->Magic[3] == '\0')
|
||||
{
|
||||
/* If the fex type is driver, we shouldn't return as Fex. */
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
debug("Image - Fex");
|
||||
Type = BinaryType::BinTypeFex;
|
||||
goto Success;
|
||||
}
|
||||
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
|
||||
{
|
||||
fixme("Fex Driver is not supposed to be executed.");
|
||||
/* TODO: Driver installation pop-up. */
|
||||
}
|
||||
}
|
||||
/* Check ELF header. */
|
||||
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)
|
||||
{
|
||||
debug("Image - ELF");
|
||||
Type = BinaryType::BinTypeELF;
|
||||
goto Success;
|
||||
}
|
||||
/* Check MZ header. */
|
||||
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
vfs->Seek(ExFile, MZHeader->e_lfanew, SEEK_SET);
|
||||
vfs->Read(ExFile, Buffer, 512);
|
||||
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Buffer) + MZHeader->e_lfanew);
|
||||
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Buffer) + MZHeader->e_lfanew);
|
||||
|
||||
/* TODO: LE, EDOS */
|
||||
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
debug("Image - PE");
|
||||
Type = BinaryType::BinTypePE;
|
||||
goto Success;
|
||||
}
|
||||
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
|
||||
{
|
||||
debug("Image - NE");
|
||||
Type = BinaryType::BinTypeNE;
|
||||
goto Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Image - MZ");
|
||||
Type = BinaryType::BinTypeMZ;
|
||||
goto Success;
|
||||
}
|
||||
}
|
||||
|
||||
/* ... */
|
||||
Type = BinaryType::BinTypeUnknown;
|
||||
Success:
|
||||
delete[] Buffer;
|
||||
vfs->Close(ExFile);
|
||||
return Type;
|
||||
}
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
{
|
||||
struct InterpreterIPCDataLibrary
|
||||
{
|
||||
char Name[128];
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char Path[256];
|
||||
void *ElfFile;
|
||||
void *MemoryImage;
|
||||
struct InterpreterIPCDataLibrary Libraries[64];
|
||||
} InterpreterIPCData;
|
||||
|
||||
/* Passing arguments as a sanity check and debugging. */
|
||||
void ELFInterpreterIPCThread(PCB *Process, char *Path, void *MemoryImage, void *ElfFile, std::vector<const char *> NeededLibraries)
|
||||
{
|
||||
debug("Interpreter thread started for %s", Path);
|
||||
// Interpreter will create an IPC with token "LOAD".
|
||||
char UniqueToken[16] = {'L', 'O', 'A', 'D', '\0'};
|
||||
InterProcessCommunication::IPCHandle *Handle = nullptr;
|
||||
while (Handle == nullptr)
|
||||
{
|
||||
debug("Searching for IPC with token %s", UniqueToken);
|
||||
Handle = Process->IPC->SearchByToken(UniqueToken);
|
||||
if (Handle == nullptr)
|
||||
{
|
||||
debug("Failed");
|
||||
}
|
||||
|
||||
TaskManager->Sleep(200);
|
||||
if (Handle == nullptr)
|
||||
{
|
||||
debug("Retrying...");
|
||||
}
|
||||
}
|
||||
debug("IPC found, sending data...");
|
||||
InterpreterIPCData *TmpBuffer = new InterpreterIPCData;
|
||||
strcpy(TmpBuffer->Path, Path);
|
||||
TmpBuffer->ElfFile = ElfFile;
|
||||
TmpBuffer->MemoryImage = MemoryImage;
|
||||
if (NeededLibraries.size() > 256)
|
||||
warn("Too many libraries! (max 256)");
|
||||
for (size_t i = 0; i < NeededLibraries.size(); i++)
|
||||
{
|
||||
strcpy(TmpBuffer->Libraries[i].Name, NeededLibraries[i]);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
debug("OUTSIDE DATA");
|
||||
debug("Path: %s", Path);
|
||||
debug("ElfFile: %p", ElfFile);
|
||||
debug("MemoryImage: %p", MemoryImage);
|
||||
for (size_t i = 0; i < NeededLibraries.size(); i++)
|
||||
{
|
||||
debug("Library: %s", NeededLibraries[i]);
|
||||
}
|
||||
debug("INSIDE DATA");
|
||||
debug("Path: %s", TmpBuffer->Path);
|
||||
debug("ElfFile: %p", TmpBuffer->ElfFile);
|
||||
debug("MemoryImage: %p", TmpBuffer->MemoryImage);
|
||||
for (size_t i = 0; i < NeededLibraries.size(); i++)
|
||||
{
|
||||
debug("Library: %s", TmpBuffer->Libraries[i].Name);
|
||||
}
|
||||
#endif
|
||||
|
||||
RetryIPCWrite:
|
||||
InterProcessCommunication::IPCErrorCode ret = Process->IPC->Write(Handle->ID, TmpBuffer, sizeof(InterpreterIPCData));
|
||||
debug("Write returned %d", ret);
|
||||
if (ret == InterProcessCommunication::IPCErrorCode::IPCNotListening)
|
||||
{
|
||||
debug("IPC not listening, retrying...");
|
||||
TaskManager->Sleep(100);
|
||||
goto RetryIPCWrite;
|
||||
}
|
||||
delete TmpBuffer;
|
||||
/* Prevent race condition, maybe a
|
||||
better idea is to watch when the
|
||||
IPC is destroyed. */
|
||||
TaskManager->Sleep(5000);
|
||||
TEXIT(0);
|
||||
}
|
||||
|
||||
PCB *InterpreterTargetProcess;
|
||||
std::string *InterpreterTargetPath; /* We can't have String as a constructor :( */
|
||||
void *InterpreterMemoryImage;
|
||||
void *InterpreterElfFile;
|
||||
std::vector<const char *> InterpreterNeededLibraries;
|
||||
void ELFInterpreterThreadWrapper()
|
||||
{
|
||||
ELFInterpreterIPCThread(InterpreterTargetProcess, (char *)InterpreterTargetPath->c_str(), InterpreterMemoryImage, InterpreterElfFile, InterpreterNeededLibraries);
|
||||
delete InterpreterTargetPath, InterpreterTargetPath = nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 + 1));
|
||||
/* Copy the file to the allocated memory */
|
||||
memcpy(ElfFile, (void *)ExFile.node->Address, ExFileSize);
|
||||
debug("Elf file: %#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);
|
||||
Process->SetWorkingDirectory(vfs->GetNodeFromPath(Path)->Parent);
|
||||
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);
|
||||
|
||||
ELFBaseLoad bl;
|
||||
|
||||
switch (ELFHeader->e_type)
|
||||
{
|
||||
case ET_REL:
|
||||
bl = ELFLoadRel(ElfFile, ExFile, Process);
|
||||
break;
|
||||
case ET_EXEC:
|
||||
bl = ELFLoadExec(ElfFile, ExFile, Process);
|
||||
break;
|
||||
case ET_DYN:
|
||||
bl = ELFLoadDyn(ElfFile, ExFile, 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 {};
|
||||
}
|
||||
}
|
||||
|
||||
if (bl.Interpreter)
|
||||
{
|
||||
debug("ElfFile: %p ELFHeader: %p", ElfFile, ELFHeader);
|
||||
|
||||
InterpreterTargetProcess = Process;
|
||||
InterpreterTargetPath = new std::string(Path); /* We store in a String because Path may get changed while outside ELFLoad(). */
|
||||
InterpreterMemoryImage = bl.VirtualMemoryImage;
|
||||
InterpreterElfFile = ElfFile;
|
||||
InterpreterNeededLibraries = bl.NeededLibraries;
|
||||
__sync;
|
||||
TCB *InterpreterIPCThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)ELFInterpreterThreadWrapper);
|
||||
InterpreterIPCThread->Rename("ELF Interpreter IPC Thread");
|
||||
InterpreterIPCThread->SetPriority(TaskPriority::Low);
|
||||
}
|
||||
|
||||
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.TmpMem = nullptr;
|
||||
|
||||
bl.sd.Process = Process;
|
||||
bl.sd.Thread = Thread;
|
||||
bl.sd.Status = ExStatus::OK;
|
||||
vfs->Close(ExFile);
|
||||
return bl;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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)
|
||||
{
|
||||
UNUSED(BaseImage);
|
||||
UNUSED(ExFile);
|
||||
UNUSED(Process);
|
||||
fixme("Not implemented");
|
||||
return {};
|
||||
}
|
||||
}
|
187
Execute/Elf/ElfBaseLoad.cpp
Normal file
187
Execute/Elf/ElfBaseLoad.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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,
|
||||
TaskCompatibility Compatibility)
|
||||
{
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
|
||||
|
||||
File ExFile = vfs->Open(Path);
|
||||
|
||||
if (ExFile.Status != FileStatus::OK)
|
||||
{
|
||||
vfs->Close(ExFile);
|
||||
error("Failed to open file: %s", Path);
|
||||
return {};
|
||||
}
|
||||
else if (ExFile.GetFlags() != 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.GetLength();
|
||||
|
||||
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(ExFileSize + 1));
|
||||
vfs->Read(ExFile, (uint8_t *)ElfFile, ExFileSize);
|
||||
debug("Loaded elf %s at %#lx with the length of %ld",
|
||||
Path, ElfFile, ExFileSize);
|
||||
|
||||
Elf32_Ehdr *ELFHeader = (Elf32_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)
|
||||
fixme("32-bit ELF");
|
||||
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
fixme("64-bit ELF");
|
||||
else
|
||||
fixme("Unknown class %d", ELFHeader->e_ident[EI_CLASS]);
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
if (ELFHeader->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
{
|
||||
fixme("ELF32 LSB expected, got %d", ELFHeader->e_ident[EI_DATA]);
|
||||
}
|
||||
#else
|
||||
if (ELFHeader->e_ident[EI_DATA] != ELFDATA2MSB)
|
||||
{
|
||||
fixme("ELF32 MSB expected, got %d", ELFHeader->e_ident[EI_DATA]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(),
|
||||
BaseName, TaskTrustLevel::User, ElfFile);
|
||||
Process->SetWorkingDirectory(vfs->GetNodeFromPath(Path)->Parent);
|
||||
Process->Info.Compatibility = TaskCompatibility::Native;
|
||||
Process->Info.Architecture = TaskArchitecture::x64;
|
||||
|
||||
ELFBaseLoad bl;
|
||||
|
||||
ELFObject *obj = new ELFObject(Path, Process);
|
||||
if (!obj->IsValid())
|
||||
{
|
||||
error("Failed to load ELF object");
|
||||
vfs->Close(ExFile);
|
||||
TaskManager->RevertProcessCreation(Process);
|
||||
return {};
|
||||
}
|
||||
|
||||
bl = obj->GetBaseLoadInfo();
|
||||
|
||||
/* TODO: Keep only the necessary headers */
|
||||
Memory::Virtual vmm = Memory::Virtual(Process->PageTable);
|
||||
for (size_t i = 0; i < TO_PAGES(ExFileSize); i++)
|
||||
{
|
||||
void *AddressToMap = (void *)((uintptr_t)ElfFile + (i * PAGE_SIZE));
|
||||
vmm.Remap(AddressToMap, AddressToMap, Memory::RW | Memory::US);
|
||||
}
|
||||
|
||||
if (bl.Interpreter)
|
||||
{
|
||||
debug("Keeping ElfFile at %p", ElfFile);
|
||||
|
||||
TCB *InterIPCThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(),
|
||||
(IP)ELFInterpreterIPCThread,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::vector<AuxiliaryVector>(),
|
||||
TaskArchitecture::x64,
|
||||
TaskCompatibility::Native,
|
||||
true);
|
||||
|
||||
std::vector<const char *> *tmp_needed_libs =
|
||||
new std::vector<const char *>(bl.NeededLibraries);
|
||||
|
||||
InterIPCThread->SYSV_ABI_Call((uintptr_t)Process,
|
||||
(uintptr_t) new std::string(Path),
|
||||
(uintptr_t)bl.VirtualMemoryImage,
|
||||
(uintptr_t)tmp_needed_libs);
|
||||
|
||||
InterIPCThread->Rename("ELF Interpreter IPC Thread");
|
||||
InterIPCThread->SetPriority(TaskPriority::Low);
|
||||
InterIPCThread->Status = TaskStatus::Ready;
|
||||
}
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
bl.InstructionPointer,
|
||||
argv, envp, bl.auxv,
|
||||
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.TmpMem = nullptr;
|
||||
|
||||
bl.sd.Process = Process;
|
||||
bl.sd.Thread = Thread;
|
||||
bl.sd.Status = ExStatus::OK;
|
||||
vfs->Close(ExFile);
|
||||
return bl;
|
||||
}
|
||||
}
|
155
Execute/Elf/ElfInterpreter.cpp
Normal file
155
Execute/Elf/ElfInterpreter.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace Tasking;
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
struct InterpreterIPCDataLibrary
|
||||
{
|
||||
char Name[64];
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char Path[256];
|
||||
void *MemoryImage;
|
||||
struct InterpreterIPCDataLibrary Libraries[64];
|
||||
} InterpreterIPCData;
|
||||
|
||||
void ELFInterpreterIPCThread(PCB *TargetProcess,
|
||||
std::string *TargetPath,
|
||||
void *MemoryImage,
|
||||
std::vector<const char *> *_NeededLibraries)
|
||||
{
|
||||
std::vector<const char *> NeededLibraries = *_NeededLibraries;
|
||||
delete _NeededLibraries;
|
||||
|
||||
debug("Interpreter thread started for %s", TargetPath->c_str());
|
||||
// Interpreter will create an IPC with token "LOAD".
|
||||
char UniqueToken[16] = {'L', 'O', 'A', 'D', '\0'};
|
||||
InterProcessCommunication::IPCHandle *Handle = nullptr;
|
||||
while (Handle == nullptr)
|
||||
{
|
||||
debug("Searching for IPC with token %s", UniqueToken);
|
||||
Handle = TargetProcess->IPC->SearchByToken(UniqueToken);
|
||||
if (Handle == nullptr)
|
||||
debug("Failed");
|
||||
|
||||
TaskManager->Sleep(200);
|
||||
if (Handle == nullptr)
|
||||
debug("Retrying...");
|
||||
}
|
||||
debug("IPC found, sending data...");
|
||||
InterpreterIPCData *TmpBuffer = new InterpreterIPCData;
|
||||
strncpy(TmpBuffer->Path, TargetPath->c_str(), sizeof(TmpBuffer->Path) - 1);
|
||||
TmpBuffer->MemoryImage = MemoryImage;
|
||||
size_t NeededLibsSize = NeededLibraries.size();
|
||||
|
||||
for (size_t i = 0; i < NeededLibsSize; i++)
|
||||
strncpy(TmpBuffer->Libraries[i].Name, NeededLibraries[i],
|
||||
sizeof(TmpBuffer->Libraries[i].Name) - 1);
|
||||
|
||||
#ifdef DEBUG
|
||||
debug("Input:");
|
||||
debug("Path: %s", TargetPath->c_str());
|
||||
debug("MemoryImage: %p", MemoryImage);
|
||||
for (size_t i = 0; i < NeededLibsSize; i++)
|
||||
debug("Library: %s", NeededLibraries[i]);
|
||||
|
||||
debug("Buffer:");
|
||||
debug("Path: %s", TmpBuffer->Path);
|
||||
debug("MemoryImage: %p", TmpBuffer->MemoryImage);
|
||||
for (size_t i = 0; i < 64; i++)
|
||||
{
|
||||
if (TmpBuffer->Libraries[i].Name[0] != '\0')
|
||||
break;
|
||||
debug("Library: %s", TmpBuffer->Libraries[i].Name);
|
||||
}
|
||||
#endif
|
||||
|
||||
RetryIPCWrite:
|
||||
InterProcessCommunication::IPCErrorCode ret =
|
||||
TargetProcess->IPC->Write(Handle->ID, TmpBuffer, sizeof(InterpreterIPCData));
|
||||
debug("Write returned %d", ret);
|
||||
if (ret == InterProcessCommunication::IPCErrorCode::IPCNotListening)
|
||||
{
|
||||
debug("IPC not listening, retrying...");
|
||||
TaskManager->Sleep(100);
|
||||
goto RetryIPCWrite;
|
||||
}
|
||||
delete TmpBuffer;
|
||||
|
||||
while (!TargetProcess->IPC->SearchByToken(UniqueToken))
|
||||
TaskManager->Schedule();
|
||||
|
||||
debug("Interpreter thread finished for %s", TargetPath->c_str());
|
||||
|
||||
for (size_t i = 0; i < NeededLibsSize; i++)
|
||||
delete[] NeededLibraries[i];
|
||||
|
||||
delete TargetPath;
|
||||
TEXIT(0);
|
||||
}
|
||||
|
||||
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &vmm, 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 because
|
||||
the function that calls this already checks it. */
|
||||
VirtualFileSystem::File ElfFile = vfs->Open(Interpreter);
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
debug("Interpreter type: %#x", ELFHeader.e_type);
|
||||
|
||||
uintptr_t BaseAddress;
|
||||
size_t ElfPHDRsSize;
|
||||
|
||||
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
|
||||
MmImage MemoryImage = ELFCreateMemoryImage(mem, vmm, ElfFile, ElfPHDRsSize);
|
||||
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
|
||||
vfs->Close(ElfFile);
|
||||
|
||||
bool IsPIC = ELFHeader.e_type == ET_DYN;
|
||||
debug("Elf %s PIC", IsPIC ? "is" : "is not");
|
||||
|
||||
if (IsPIC)
|
||||
{
|
||||
debug("Interpreter entry point: %#lx (%#lx + %#lx)",
|
||||
(uintptr_t)MemoryImage.Physical + ELFHeader.e_entry,
|
||||
(uintptr_t)MemoryImage.Physical, ELFHeader.e_entry);
|
||||
|
||||
return (uintptr_t)MemoryImage.Physical + ELFHeader.e_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Interpreter entry point: %#lx", ELFHeader.e_entry);
|
||||
return ELFHeader.e_entry;
|
||||
}
|
||||
}
|
||||
}
|
480
Execute/Elf/ElfLoader.cpp
Normal file
480
Execute/Elf/ElfLoader.cpp
Normal file
@ -0,0 +1,480 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 namespace VirtualFileSystem;
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
ELFBaseLoad ELFObject::LoadExec_x86_32(File &ElfFile, PCB *TargetProcess)
|
||||
{
|
||||
stub;
|
||||
return {};
|
||||
}
|
||||
|
||||
ELFBaseLoad ELFObject::LoadExec_x86_64(File &ElfFile, PCB *TargetProcess)
|
||||
{
|
||||
ELFBaseLoad ELFBase{};
|
||||
|
||||
uintptr_t BaseAddress;
|
||||
size_t ElfPHDRsSize;
|
||||
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
uintptr_t EntryPoint = ELFHeader.e_entry;
|
||||
debug("%s's entry point is %#lx", ElfFile.Name, EntryPoint);
|
||||
|
||||
ELFBase.TmpMem = new Memory::MemMgr(TargetProcess->PageTable); /* This should be deleted inside BaseLoad.cpp */
|
||||
Memory::Virtual vmm(TargetProcess->PageTable);
|
||||
|
||||
/* If required, MemoryImage will be at virtual address. (unless is PIC)
|
||||
tl;dr this is where the code is stored. */
|
||||
MmImage MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, vmm, ElfFile, ElfPHDRsSize);
|
||||
|
||||
debug("Solving symbols for %s", ElfFile.Name);
|
||||
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(ElfFile, ".dynstr");
|
||||
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(ElfFile, ".strtab");
|
||||
|
||||
if (DynamicString.size() < 1) /* TODO: check if this is required */
|
||||
DynamicString = StringTable;
|
||||
|
||||
/* Calculate entry point */
|
||||
Elf64_Phdr FirstPhdr;
|
||||
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&FirstPhdr, sizeof(Elf64_Phdr));
|
||||
/* FIXME: this is not the correct way to calculate entry point */
|
||||
if (FirstPhdr.p_vaddr == 0)
|
||||
{
|
||||
debug("Entry point is null. Adding virtual address to entry point");
|
||||
EntryPoint += (uintptr_t)MemoryImage.Virtual;
|
||||
}
|
||||
|
||||
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
|
||||
|
||||
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
|
||||
{
|
||||
const char *ReqLib = new char[256];
|
||||
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
|
||||
|
||||
debug("DT_NEEDED - %s", ReqLib);
|
||||
ELFBase.NeededLibraries.push_back(ReqLib);
|
||||
}
|
||||
|
||||
char InterpreterPath[256] = {'\0'};
|
||||
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(ElfFile, PT_INTERP);
|
||||
foreach (auto Interp in PhdrINTERP)
|
||||
{
|
||||
const char *InterpPath = new char[256];
|
||||
vfs->Seek(ElfFile, Interp.p_offset, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)InterpPath, 256);
|
||||
|
||||
memcpy((void *)InterpreterPath, InterpPath,
|
||||
(strlen(InterpPath) > 256) ? 256 : strlen(InterpPath));
|
||||
debug("Interpreter: %s", InterpreterPath);
|
||||
delete[] InterpPath;
|
||||
|
||||
VirtualFileSystem::File InterpreterFile = vfs->Open(InterpreterPath);
|
||||
if (!InterpreterFile.IsOK())
|
||||
{
|
||||
warn("Failed to open interpreter file: %s", InterpreterPath);
|
||||
vfs->Close(InterpreterFile);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetBinaryType(InterpreterPath) != BinTypeELF)
|
||||
{
|
||||
warn("Interpreter %s is not an ELF file", InterpreterPath);
|
||||
vfs->Close(InterpreterFile);
|
||||
continue;
|
||||
}
|
||||
vfs->Close(InterpreterFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(InterpreterPath) > 1)
|
||||
{
|
||||
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, InterpreterPath);
|
||||
ELFBase.Interpreter = true;
|
||||
}
|
||||
|
||||
debug("Entry Point: %#lx", EntryPoint);
|
||||
|
||||
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true); /* TODO: 4096 bytes is too much for this */
|
||||
strcpy(aux_platform, "x86_64");
|
||||
|
||||
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)0 /* FIXME */}}});
|
||||
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.Virtual}}});
|
||||
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;
|
||||
ELFBase.MemoryImage = MemoryImage.Physical;
|
||||
ELFBase.VirtualMemoryImage = MemoryImage.Virtual;
|
||||
|
||||
ELFBase.Success = true;
|
||||
return ELFBase;
|
||||
}
|
||||
|
||||
ELFBaseLoad ELFObject::LoadDyn_x86_32(File &ElfFile, PCB *TargetProcess, bool IsLibrary)
|
||||
{
|
||||
stub;
|
||||
return {};
|
||||
}
|
||||
|
||||
ELFBaseLoad ELFObject::LoadDyn_x86_64(File &ElfFile, PCB *TargetProcess, bool IsLibrary)
|
||||
{
|
||||
ELFBaseLoad ELFBase{};
|
||||
|
||||
uintptr_t BaseAddress;
|
||||
size_t ElfPHDRsSize;
|
||||
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
uintptr_t EntryPoint = ELFHeader.e_entry;
|
||||
debug("%s's entry point is %#lx", ElfFile.Name, EntryPoint);
|
||||
|
||||
ELFBase.TmpMem = new Memory::MemMgr(TargetProcess->PageTable); /* This should be deleted inside BaseLoad.cpp */
|
||||
Memory::Virtual vmm(TargetProcess->PageTable);
|
||||
|
||||
/* If required, MemoryImage will be at virtual address. (unless is PIC)
|
||||
tl;dr this is where the code is stored. */
|
||||
MmImage MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, vmm, ElfFile, ElfPHDRsSize);
|
||||
|
||||
debug("Solving symbols for %s", ElfFile.Name);
|
||||
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(ElfFile, ".dynstr");
|
||||
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(ElfFile, ".strtab");
|
||||
|
||||
if (DynamicString.size() < 1) /* TODO: check if this is required */
|
||||
DynamicString = StringTable;
|
||||
|
||||
/* Calculate entry point */
|
||||
Elf64_Phdr FirstPhdr;
|
||||
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&FirstPhdr, sizeof(Elf64_Phdr));
|
||||
/* FIXME: this is not the correct way to calculate entry point */
|
||||
if (FirstPhdr.p_vaddr == 0)
|
||||
{
|
||||
debug("Entry point is null. Adding virtual address to entry point");
|
||||
EntryPoint += (uintptr_t)MemoryImage.Virtual;
|
||||
}
|
||||
|
||||
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
|
||||
|
||||
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
|
||||
{
|
||||
const char *ReqLib = new char[256];
|
||||
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
|
||||
|
||||
debug("DT_NEEDED - %s", ReqLib);
|
||||
ELFBase.NeededLibraries.push_back(ReqLib);
|
||||
}
|
||||
|
||||
std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(ElfFile, DT_JMPREL);
|
||||
std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(ElfFile, DT_SYMTAB);
|
||||
std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(ElfFile, DT_STRTAB);
|
||||
|
||||
if (JmpRel.size() < 1)
|
||||
{
|
||||
debug("No DT_JMPREL");
|
||||
}
|
||||
|
||||
if (SymTab.size() < 1)
|
||||
{
|
||||
debug("No DT_SYMTAB");
|
||||
}
|
||||
|
||||
if (StrTab.size() < 1)
|
||||
{
|
||||
debug("No DT_STRTAB");
|
||||
}
|
||||
|
||||
if (JmpRel.size() > 1 &&
|
||||
SymTab.size() > 1 &&
|
||||
StrTab.size() > 1)
|
||||
{
|
||||
debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx", JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, StrTab[0].d_un.d_ptr);
|
||||
Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)MemoryImage.Physical + (JmpRel[0].d_un.d_ptr - BaseAddress));
|
||||
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)MemoryImage.Physical + (SymTab[0].d_un.d_ptr - BaseAddress));
|
||||
|
||||
char *_DynStr = (char *)((uintptr_t)MemoryImage.Physical + (StrTab[0].d_un.d_ptr - BaseAddress));
|
||||
|
||||
Elf64_Shdr *gotSection = nullptr;
|
||||
Elf64_Shdr shdr;
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
|
||||
{
|
||||
vfs->Seek(ElfFile, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
|
||||
if (shdr.sh_type == SHT_PROGBITS &&
|
||||
(shdr.sh_flags & SHF_WRITE) &&
|
||||
(shdr.sh_flags & SHF_ALLOC))
|
||||
{
|
||||
gotSection = new Elf64_Shdr;
|
||||
*gotSection = shdr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gotSection)
|
||||
{
|
||||
Elf64_Xword numEntries = gotSection->sh_size / sizeof(Elf64_Addr);
|
||||
for (Elf64_Xword i = 0; i < numEntries - 3; i++)
|
||||
{
|
||||
Elf64_Rela *Rel = _JmpRel + i;
|
||||
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + (uintptr_t)MemoryImage.Physical);
|
||||
|
||||
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
|
||||
debug("r_offset: %#lx RelType: %d", Rel->r_offset, RelType);
|
||||
|
||||
switch (RelType)
|
||||
{
|
||||
case R_X86_64_NONE:
|
||||
break;
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
{
|
||||
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
|
||||
Elf64_Sym *Sym = _SymTab + SymIndex;
|
||||
|
||||
if (Sym->st_name)
|
||||
{
|
||||
char *SymName = _DynStr + Sym->st_name;
|
||||
debug("SymName: %s", SymName);
|
||||
|
||||
Elf64_Sym LibSym = ELFLookupSymbol(ElfFile, SymName);
|
||||
|
||||
if (LibSym.st_value)
|
||||
{
|
||||
*GOTEntry = (Elf64_Addr)((uintptr_t)MemoryImage.Physical + LibSym.st_value);
|
||||
debug("GOT[%ld]: %#lx + %#lx = %#lx",
|
||||
i, (uintptr_t)MemoryImage.Physical, LibSym.st_value, *GOTEntry);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("RelType %d not supported", RelType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("GOT[%ld](%#lx): %#lx", i, GOTEntry, *GOTEntry);
|
||||
}
|
||||
|
||||
delete gotSection;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("GOT section not found");
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
|
||||
{
|
||||
const char *ReqLib = new char[256];
|
||||
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
|
||||
|
||||
debug("DT_NEEDED - %s", ReqLib);
|
||||
ELFBase.NeededLibraries.push_back(ReqLib);
|
||||
}
|
||||
|
||||
char InterpreterPath[256] = {'\0'};
|
||||
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(ElfFile, PT_INTERP);
|
||||
foreach (auto Interp in PhdrINTERP)
|
||||
{
|
||||
const char *InterpPath = new char[256];
|
||||
vfs->Seek(ElfFile, Interp.p_offset, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)InterpPath, 256);
|
||||
|
||||
memcpy((void *)InterpreterPath, InterpPath,
|
||||
(strlen(InterpPath) > 256) ? 256 : strlen(InterpPath));
|
||||
debug("Interpreter: %s", InterpreterPath);
|
||||
delete[] InterpPath;
|
||||
|
||||
VirtualFileSystem::File InterpreterFile = vfs->Open(InterpreterPath);
|
||||
if (!InterpreterFile.IsOK())
|
||||
{
|
||||
warn("Failed to open interpreter file: %s", InterpreterPath);
|
||||
vfs->Close(InterpreterFile);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetBinaryType(InterpreterPath) != BinTypeELF)
|
||||
{
|
||||
warn("Interpreter %s is not an ELF file", InterpreterPath);
|
||||
vfs->Close(InterpreterFile);
|
||||
continue;
|
||||
}
|
||||
vfs->Close(InterpreterFile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(InterpreterPath) > 1)
|
||||
{
|
||||
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, InterpreterPath);
|
||||
ELFBase.Interpreter = true;
|
||||
}
|
||||
else if (IsLibrary)
|
||||
{
|
||||
/* FIXME: Detect interpreter from current running process. */
|
||||
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, "/lib/ld.so");
|
||||
ELFBase.Interpreter = true;
|
||||
}
|
||||
|
||||
debug("Entry Point: %#lx", EntryPoint);
|
||||
|
||||
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true); /* TODO: 4096 bytes is too much for this */
|
||||
strcpy(aux_platform, "x86_64");
|
||||
|
||||
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)0 /* FIXME */}}});
|
||||
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.Virtual}}});
|
||||
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;
|
||||
ELFBase.MemoryImage = MemoryImage.Physical;
|
||||
ELFBase.VirtualMemoryImage = MemoryImage.Virtual;
|
||||
|
||||
ELFBase.Success = true;
|
||||
return ELFBase;
|
||||
}
|
||||
|
||||
ELFObject::ELFObject(char *AbsolutePath,
|
||||
PCB *TargetProcess,
|
||||
bool IsLibrary)
|
||||
{
|
||||
if (GetBinaryType(AbsolutePath) != BinaryType::BinTypeELF)
|
||||
{
|
||||
error("%s is not an ELF file or is invalid.", AbsolutePath);
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualFileSystem::File ExFile = vfs->Open(AbsolutePath);
|
||||
|
||||
Elf32_Ehdr ELFHeader;
|
||||
vfs->Read(ExFile, (uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr));
|
||||
|
||||
ELFBaseLoad bl;
|
||||
switch (ELFHeader.e_type)
|
||||
{
|
||||
case ET_REL:
|
||||
{
|
||||
fixme("ET_REL not implemented");
|
||||
break;
|
||||
}
|
||||
case ET_EXEC:
|
||||
{
|
||||
switch (ELFHeader.e_machine)
|
||||
{
|
||||
case EM_386:
|
||||
this->BaseLoadInfo = this->LoadExec_x86_32(ExFile,
|
||||
TargetProcess);
|
||||
break;
|
||||
case EM_X86_64:
|
||||
this->BaseLoadInfo = this->LoadExec_x86_64(ExFile,
|
||||
TargetProcess);
|
||||
break;
|
||||
case EM_ARM:
|
||||
error("ARM is not supported yet!");
|
||||
break;
|
||||
case EM_AARCH64:
|
||||
error("ARM64 is not supported yet!");
|
||||
break;
|
||||
default:
|
||||
error("Unknown architecture: %d", ELFHeader.e_machine);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ET_DYN:
|
||||
{
|
||||
switch (ELFHeader.e_machine)
|
||||
{
|
||||
case EM_386:
|
||||
this->BaseLoadInfo = this->LoadDyn_x86_32(ExFile,
|
||||
TargetProcess,
|
||||
IsLibrary);
|
||||
break;
|
||||
case EM_X86_64:
|
||||
this->BaseLoadInfo = this->LoadDyn_x86_64(ExFile,
|
||||
TargetProcess,
|
||||
IsLibrary);
|
||||
break;
|
||||
case EM_ARM:
|
||||
error("ARM is not supported yet!");
|
||||
break;
|
||||
case EM_AARCH64:
|
||||
error("ARM64 is not supported yet!");
|
||||
break;
|
||||
default:
|
||||
error("Unknown architecture: %d", ELFHeader.e_machine);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ET_CORE:
|
||||
{
|
||||
fixme("ET_CORE not implemented");
|
||||
break;
|
||||
}
|
||||
case ET_NONE:
|
||||
default:
|
||||
{
|
||||
error("Unknown ELF Type: %d", ELFHeader.e_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vfs->Close(ExFile);
|
||||
}
|
||||
|
||||
ELFObject::~ELFObject()
|
||||
{
|
||||
}
|
||||
}
|
340
Execute/Elf/ElfParse.cpp
Normal file
340
Execute/Elf/ElfParse.cpp
Normal file
@ -0,0 +1,340 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <msexec.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../Fex.hpp"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
bool ELFIs64(void *Header)
|
||||
{
|
||||
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Header;
|
||||
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
|
||||
{
|
||||
Elf64_Shdr *SymbolTable = nullptr;
|
||||
Elf64_Shdr *StringTable = 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;
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SymbolTable == nullptr || StringTable == nullptr)
|
||||
return nullptr;
|
||||
|
||||
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
|
||||
{
|
||||
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
if (strcmp(String, Name) == 0)
|
||||
return Symbol;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Elf64_Sym ELFLookupSymbol(VirtualFileSystem::File &ElfFile, const char *Name)
|
||||
{
|
||||
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
|
||||
|
||||
Elf64_Ehdr Header;
|
||||
vfs->Seek(ElfFile, 0, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&Header, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Shdr SymbolTable;
|
||||
Elf64_Shdr StringTable;
|
||||
|
||||
for (Elf64_Half i = 0; i < Header.e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr shdr;
|
||||
vfs->Seek(ElfFile, Header.e_shoff + (i * sizeof(Elf64_Shdr)), SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
|
||||
|
||||
switch (shdr.sh_type)
|
||||
{
|
||||
case SHT_SYMTAB:
|
||||
SymbolTable = shdr;
|
||||
vfs->Seek(ElfFile, Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)), SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&StringTable, sizeof(Elf64_Shdr));
|
||||
break;
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SymbolTable.sh_name == 0 ||
|
||||
StringTable.sh_name == 0)
|
||||
{
|
||||
error("Symbol table not found.");
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
return {};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
|
||||
{
|
||||
// Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
Elf64_Sym Symbol;
|
||||
vfs->Seek(ElfFile, SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&Symbol, sizeof(Elf64_Sym));
|
||||
|
||||
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
char String[256];
|
||||
vfs->Seek(ElfFile, StringTable.sh_offset + Symbol.st_name, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&String, 256);
|
||||
|
||||
if (strcmp(String, Name) == 0)
|
||||
{
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
return Symbol;
|
||||
}
|
||||
}
|
||||
error("Symbol not found.");
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
return {};
|
||||
}
|
||||
|
||||
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
|
||||
{
|
||||
#if defined(a64)
|
||||
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 = (void *)ELFLookupSymbol(Header, Name)->st_value;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CopyLOADSegments(VirtualFileSystem::File &ElfFile, uintptr_t HdrsBase, uintptr_t PhysicalBase)
|
||||
{
|
||||
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Seek(ElfFile, 0, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Phdr ProgramHeaders;
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
vfs->Seek(ElfFile, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
|
||||
if (ProgramHeaders.p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
uintptr_t SegmentDestination = (ProgramHeaders.p_vaddr - HdrsBase) + PhysicalBase;
|
||||
|
||||
debug("Copying segment to %#lx (%ld file bytes, %ld mem bytes)",
|
||||
SegmentDestination,
|
||||
ProgramHeaders.p_filesz, ProgramHeaders.p_memsz);
|
||||
|
||||
if (ProgramHeaders.p_filesz > 0)
|
||||
{
|
||||
vfs->Seek(ElfFile, ProgramHeaders.p_offset, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)SegmentDestination, ProgramHeaders.p_filesz);
|
||||
}
|
||||
|
||||
if (ProgramHeaders.p_memsz - ProgramHeaders.p_filesz > 0)
|
||||
memset((void *)(SegmentDestination + ProgramHeaders.p_filesz),
|
||||
0,
|
||||
ProgramHeaders.p_memsz - ProgramHeaders.p_filesz);
|
||||
}
|
||||
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
}
|
||||
|
||||
void GetBaseAndSize(VirtualFileSystem::File &ElfFile, uintptr_t &Base, size_t &Size)
|
||||
{
|
||||
Base = UINTPTR_MAX;
|
||||
Size = 0;
|
||||
|
||||
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Seek(ElfFile, 0, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Phdr ProgramHeaders;
|
||||
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
Base = MIN(Base, ProgramHeaders.p_vaddr);
|
||||
uintptr_t SegmentEnd = ProgramHeaders.p_vaddr - Base + ProgramHeaders.p_memsz;
|
||||
Size = MAX(Size, SegmentEnd);
|
||||
|
||||
vfs->Seek(ElfFile, sizeof(Elf64_Phdr), SEEK_CUR);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
|
||||
}
|
||||
debug("Base: %#lx, Size: %#lx (%ld, %ld KB)", Base, Size, Size, TO_KB(Size));
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
}
|
||||
|
||||
MmImage ELFCreateMemoryImage(Memory::MemMgr *mem,
|
||||
Memory::Virtual &vmm,
|
||||
VirtualFileSystem::File &ElfFile,
|
||||
size_t Length)
|
||||
{
|
||||
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
|
||||
|
||||
void *MemoryImage = nullptr;
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Seek(ElfFile, 0, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
bool IsPIC = ELFHeader.e_type == ET_DYN;
|
||||
UNUSED(IsPIC);
|
||||
debug("Elf %s PIC", IsPIC ? "is" : "is not");
|
||||
|
||||
bool FirstProgramHeader = false;
|
||||
uintptr_t FirstProgramHeaderVirtualAddress = 0x0;
|
||||
|
||||
Elf64_Phdr ProgramHeaders;
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
vfs->Seek(ElfFile, ELFHeader.e_phoff + i * sizeof(Elf64_Phdr), SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
|
||||
if (ProgramHeaders.p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (!FirstProgramHeader)
|
||||
{
|
||||
FirstProgramHeader = true;
|
||||
FirstProgramHeaderVirtualAddress = ProgramHeaders.p_vaddr;
|
||||
}
|
||||
|
||||
if (ProgramHeaders.p_vaddr == 0)
|
||||
{
|
||||
debug("p_vaddr is 0, allocating %ld pages for image (size: %#lx)", TO_PAGES(Length), Length);
|
||||
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
|
||||
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + Length);
|
||||
memset(MemoryImage, 0, Length);
|
||||
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
return {MemoryImage, (void *)FirstProgramHeaderVirtualAddress};
|
||||
}
|
||||
}
|
||||
|
||||
debug("Allocating %ld pages for image (size: %#lx)", TO_PAGES(Length), Length);
|
||||
MemoryImage = mem->RequestPages(TO_PAGES(Length));
|
||||
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + Length);
|
||||
memset(MemoryImage, 0, Length);
|
||||
|
||||
uintptr_t FirstProgramHeaderVirtualAddressAligned = 0;
|
||||
|
||||
if (FirstProgramHeaderVirtualAddress != 0)
|
||||
{
|
||||
FirstProgramHeaderVirtualAddressAligned = ALIGN_DOWN(FirstProgramHeaderVirtualAddress, PAGE_SIZE);
|
||||
debug("Aligning address %#lx to %#lx",
|
||||
FirstProgramHeaderVirtualAddress,
|
||||
FirstProgramHeaderVirtualAddressAligned);
|
||||
}
|
||||
else
|
||||
FirstProgramHeaderVirtualAddress = (uintptr_t)MemoryImage;
|
||||
|
||||
for (size_t i = 0; i < TO_PAGES(Length); i++)
|
||||
{
|
||||
vmm.Remap((void *)((uintptr_t)FirstProgramHeaderVirtualAddressAligned + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
debug("Remapped: %#lx -> %#lx", (uintptr_t)FirstProgramHeaderVirtualAddressAligned + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
|
||||
}
|
||||
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
return {MemoryImage, (void *)FirstProgramHeaderVirtualAddress};
|
||||
}
|
||||
}
|
@ -27,11 +27,11 @@ namespace Execute
|
||||
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||
|
||||
ELFBaseLoad ELFLoadRel(void *BaseImage,
|
||||
VirtualFileSystem::File &ExFile,
|
||||
const char *Name,
|
||||
Tasking::PCB *Process)
|
||||
{
|
||||
#if defined(a64)
|
||||
UNUSED(ExFile);
|
||||
UNUSED(Name);
|
||||
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");
|
159
Execute/Elf/ElfSharedObjects.cpp
Normal file
159
Execute/Elf/ElfSharedObjects.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <msexec.h>
|
||||
#include <cwalk.h>
|
||||
#include <elf.h>
|
||||
#include <abi.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <dumper.hpp>
|
||||
#endif
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../Fex.hpp"
|
||||
|
||||
using namespace Tasking;
|
||||
|
||||
NewLock(ExecuteServiceLock);
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
Memory::MemMgr *mem = nullptr;
|
||||
std::vector<SharedLibrary> Libs;
|
||||
|
||||
void LibraryManagerService()
|
||||
{
|
||||
mem = new Memory::MemMgr;
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
foreach (auto &Lib in Libs)
|
||||
{
|
||||
if (Lib.RefCount > 0)
|
||||
{
|
||||
Lib.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
|
||||
debug("Reset timeout for %s", Lib.Identifier);
|
||||
continue;
|
||||
}
|
||||
if (Lib.Timeout < TimeManager->GetCounter())
|
||||
{
|
||||
// TODO: Remove library from memory
|
||||
fixme("Removed library %s because of timeout", Lib.Identifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Timeout for %s is %ld", Lib.Identifier, Lib.Timeout);
|
||||
}
|
||||
}
|
||||
debug("Waiting 10 seconds...");
|
||||
}
|
||||
TaskManager->Sleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
bool AddLibrary(char *Identifier,
|
||||
VirtualFileSystem::File &ExFile,
|
||||
const Memory::Virtual &vmm)
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
SharedLibrary sl;
|
||||
|
||||
foreach (auto lib in Libs)
|
||||
{
|
||||
if (strcmp(lib.Identifier, Identifier) == 0)
|
||||
{
|
||||
debug("Library %s already loaded", Identifier);
|
||||
lib.RefCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
PCB *Process = TaskManager->GetCurrentProcess();
|
||||
ELFObject *obj = new ELFObject(vfs->GetPathFromNode(ExFile.GetNode()).get(), Process, true);
|
||||
if (!obj->IsValid())
|
||||
{
|
||||
error("Failed to load dynamic ELF");
|
||||
return false;
|
||||
}
|
||||
ELFBaseLoad bl = obj->GetBaseLoadInfo();
|
||||
|
||||
strncpy(sl.Identifier, Identifier, sizeof(sl.Identifier) - 1);
|
||||
char *AbsolutePath = vfs->GetPathFromNode(ExFile.GetNode()).get();
|
||||
strncpy(sl.Path, AbsolutePath, sizeof(sl.Path) - 1);
|
||||
sl.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
|
||||
sl.RefCount = 0;
|
||||
sl.MemoryImage = (uintptr_t)bl.MemoryImage;
|
||||
sl.Length = ExFile.GetLength();
|
||||
Libs.push_back(sl);
|
||||
debug("Library %s loaded at %#lx", Identifier, sl.MemoryImage);
|
||||
|
||||
if (bl.InstructionPointer)
|
||||
{
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
bl.InstructionPointer,
|
||||
nullptr,
|
||||
nullptr,
|
||||
bl.auxv,
|
||||
Process->Info.Architecture,
|
||||
Process->Info.Compatibility,
|
||||
true);
|
||||
Thread->Rename(Identifier);
|
||||
Thread->Status = TaskStatus::Ready;
|
||||
|
||||
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
|
||||
{
|
||||
Thread->Memory->Add(p.Address, p.PageCount);
|
||||
bl.TmpMem->DetachAddress(p.Address);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
|
||||
{
|
||||
/* FIXME: MEMORY LEAK */
|
||||
// Process->Memory->Add(p.Address, p.PageCount);
|
||||
bl.TmpMem->DetachAddress(p.Address);
|
||||
fixme("Potential memory leak. (%#lx - %ld)",
|
||||
p.Address, p.PageCount);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedLibrary GetLibrary(char *Identifier)
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
foreach (auto Lib in Libs)
|
||||
{
|
||||
if (strcmp(Lib.Identifier, Identifier) == 0)
|
||||
{
|
||||
Lib.RefCount++;
|
||||
debug("Library %s found at %#lx", Identifier, Lib.MemoryImage);
|
||||
return Lib;
|
||||
}
|
||||
}
|
||||
error("Library %s not found", Identifier);
|
||||
return SharedLibrary();
|
||||
}
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 ELFLoadExec(void *ElfFile,
|
||||
VirtualFileSystem::File &ExFile,
|
||||
Tasking::PCB *Process)
|
||||
{
|
||||
#if defined(a64)
|
||||
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;
|
||||
debug("%s's entry point is %#lx", ExFile.Name, EntryPoint);
|
||||
|
||||
Elf64_Phdr ItrPhdr;
|
||||
|
||||
/* Get base address */
|
||||
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));
|
||||
|
||||
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
|
||||
}
|
||||
|
||||
/* Get size */
|
||||
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));
|
||||
|
||||
uintptr_t SegmentEnd;
|
||||
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
|
||||
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
|
||||
}
|
||||
debug("BaseAddress: %#lx | ElfAppSize: %#lx (%ld, %ld KB)", BaseAddress, ElfAppSize, ElfAppSize, TO_KB(ElfAppSize));
|
||||
|
||||
/* If required, MemoryImage will be at virtual address. (unless has PIE)
|
||||
*
|
||||
* tl;dr this is where the code is stored. */
|
||||
MmImage 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 *StringTable = nullptr;
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++)
|
||||
{
|
||||
char *DynamicStringTable = (char *)((uintptr_t)ElfFile + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
|
||||
|
||||
if (strcmp(DynamicStringTable, ".dynstr") == 0)
|
||||
{
|
||||
DynamicString = &ElfSections[i];
|
||||
debug("Found .dynstr");
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".strtab") == 0)
|
||||
{
|
||||
StringTable = &ElfSections[i];
|
||||
debug("Found .strtab");
|
||||
}
|
||||
}
|
||||
|
||||
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.Virtual;
|
||||
|
||||
char InterpreterPath[256] = {'\0'};
|
||||
|
||||
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));
|
||||
|
||||
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",
|
||||
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.Physical;
|
||||
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 *)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",
|
||||
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
|
||||
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
|
||||
|
||||
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 == DT_NEEDED)
|
||||
{
|
||||
if (!DynamicString)
|
||||
{
|
||||
error("DynamicString is null");
|
||||
break;
|
||||
}
|
||||
|
||||
const char *ReqLib = (const char *)((uintptr_t)ElfFile + DynamicString->sh_offset + Dynamic[i].d_un.d_val);
|
||||
debug("DT_NEEDED - Name[%ld]: %s", i, ReqLib);
|
||||
ELFBase.NeededLibraries.push_back(ReqLib);
|
||||
}
|
||||
else if (Dynamic[i].d_tag == DT_NULL)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PT_INTERP:
|
||||
{
|
||||
debug("PT_INTERP - 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);
|
||||
|
||||
memcpy((void *)InterpreterPath, (uint8_t *)ElfFile + ItrPhdr.p_offset, 256);
|
||||
debug("Interpreter: %s", InterpreterPath);
|
||||
|
||||
VirtualFileSystem::File InterpreterFile = vfs->Open(InterpreterPath);
|
||||
if (!InterpreterFile.IsOK())
|
||||
warn("Failed to open interpreter file: %s", InterpreterPath);
|
||||
|
||||
vfs->Close(InterpreterFile);
|
||||
break;
|
||||
}
|
||||
/* ... */
|
||||
case PT_PHDR:
|
||||
{
|
||||
fixme("PT_PHDR - 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);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
warn("Unknown or unsupported program header type: %d", ItrPhdr.p_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(InterpreterPath) > 1)
|
||||
{
|
||||
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, pV, InterpreterPath);
|
||||
ELFBase.Interpreter = true;
|
||||
}
|
||||
|
||||
debug("Entry Point: %#lx", EntryPoint);
|
||||
|
||||
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true);
|
||||
strcpy(aux_platform, "x86_64");
|
||||
|
||||
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.Virtual}}});
|
||||
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;
|
||||
ELFBase.MemoryImage = MemoryImage.Physical;
|
||||
ELFBase.VirtualMemoryImage = MemoryImage.Virtual;
|
||||
|
||||
ELFBase.Success = true;
|
||||
return ELFBase;
|
||||
#elif defined(a32)
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
}
|
@ -1,330 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
|
||||
{
|
||||
#if defined(a64)
|
||||
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;
|
||||
default:
|
||||
{
|
||||
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 Symbol;
|
||||
}
|
||||
#elif defined(a32)
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
|
||||
{
|
||||
#if defined(a64)
|
||||
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 = (void *)ELFLookupSymbol(Header, Name)->st_value;
|
||||
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;
|
||||
}
|
||||
#elif defined(a32)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag)
|
||||
{
|
||||
#if defined(a64)
|
||||
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;
|
||||
#elif defined(a32)
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
MmImage ELFCreateMemoryImage(Memory::MemMgr *mem, Memory::Virtual &pV, void *ElfFile, size_t Length)
|
||||
{
|
||||
#if defined(a64)
|
||||
void *MemoryImage = nullptr;
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||
bool IsPIC = ELFHeader->e_type == ET_DYN;
|
||||
UNUSED(IsPIC);
|
||||
debug("Elf %s PIC", IsPIC ? "is" : "is not");
|
||||
|
||||
/* 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 + 1), true);
|
||||
memset(MemoryImage, 0, Length);
|
||||
return {MemoryImage, 0x0};
|
||||
}
|
||||
|
||||
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 (size: %#lx)", TO_PAGES(Length), Length);
|
||||
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
|
||||
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + Length);
|
||||
memset(MemoryImage, 0, Length);
|
||||
return {MemoryImage, (void *)FirstProgramHeaderVirtualAddress};
|
||||
}
|
||||
}
|
||||
|
||||
debug("Allocating %ld pages for image (size: %#lx)", TO_PAGES(Length), Length);
|
||||
MemoryImage = mem->RequestPages(TO_PAGES(Length));
|
||||
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + 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, (void *)FirstProgramHeaderVirtualAddress};
|
||||
#elif defined(a32)
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
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. */
|
||||
VirtualFileSystem::File File = vfs->Open(Interpreter);
|
||||
|
||||
#if defined(a64)
|
||||
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);
|
||||
}
|
||||
|
||||
MmImage 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.Physical;
|
||||
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.Physical + ELFHeader->e_entry,
|
||||
(uintptr_t)MemoryImage.Physical, ELFHeader->e_entry);
|
||||
return (uintptr_t)MemoryImage.Physical + ELFHeader->e_entry;
|
||||
#elif defined(a32)
|
||||
vfs->Close(File);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
62
Execute/Elf/ParseFunctions/ELFGetDynamicTag.cpp
Normal file
62
Execute/Elf/ParseFunctions/ELFGetDynamicTag.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(VirtualFileSystem::File &ElfFile,
|
||||
DynamicArrayTags Tag)
|
||||
{
|
||||
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
|
||||
std::vector<Elf64_Dyn> Ret;
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Seek(ElfFile, 0, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(ElfFile, PT_DYNAMIC);
|
||||
|
||||
if (DYNAMICPhdrs.size() < 1)
|
||||
{
|
||||
error("No dynamic phdrs found.");
|
||||
return Ret;
|
||||
}
|
||||
|
||||
foreach (auto Phdr in DYNAMICPhdrs)
|
||||
{
|
||||
Elf64_Dyn Dynamic;
|
||||
for (size_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++)
|
||||
{
|
||||
vfs->Seek(ElfFile, Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&Dynamic, sizeof(Elf64_Dyn));
|
||||
|
||||
if (Dynamic.d_tag != Tag)
|
||||
continue;
|
||||
|
||||
debug("Found dynamic tag %d at %#lx [d_val: %#lx].",
|
||||
Tag, &Dynamic, Dynamic.d_un.d_val);
|
||||
Ret.push_back(Dynamic);
|
||||
}
|
||||
}
|
||||
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
return Ret;
|
||||
}
|
||||
}
|
54
Execute/Elf/ParseFunctions/ELFGetSections.cpp
Normal file
54
Execute/Elf/ParseFunctions/ELFGetSections.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf64_Shdr> ELFGetSections_x86_64(VirtualFileSystem::File &ElfFile,
|
||||
const char *SectionName)
|
||||
{
|
||||
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
|
||||
std::vector<Elf64_Shdr> Ret;
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Seek(ElfFile, 0, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum];
|
||||
vfs->Seek(ElfFile, ELFHeader.e_shoff, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum);
|
||||
|
||||
char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size];
|
||||
vfs->Seek(ElfFile, SectionHeaders[ELFHeader.e_shstrndx].sh_offset, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size);
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; ++i)
|
||||
{
|
||||
const char *Name = SectionNames + SectionHeaders[i].sh_name;
|
||||
if (strcmp(Name, SectionName) == 0)
|
||||
Ret.push_back(SectionHeaders[i]);
|
||||
}
|
||||
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
delete[] SectionHeaders;
|
||||
delete[] SectionNames;
|
||||
return Ret;
|
||||
}
|
||||
}
|
50
Execute/Elf/ParseFunctions/ELFGetSymbolType.cpp
Normal file
50
Execute/Elf/ParseFunctions/ELFGetSymbolType.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(VirtualFileSystem::File &ElfFile,
|
||||
SegmentTypes Tag)
|
||||
{
|
||||
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
|
||||
std::vector<Elf64_Phdr> Ret;
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
vfs->Seek(ElfFile, 0, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Phdr ProgramHeaders;
|
||||
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
if (ProgramHeaders.p_type == Tag)
|
||||
Ret.push_back(ProgramHeaders);
|
||||
|
||||
vfs->Seek(ElfFile, sizeof(Elf64_Phdr), SEEK_CUR);
|
||||
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
|
||||
}
|
||||
|
||||
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
|
||||
return Ret;
|
||||
}
|
||||
}
|
@ -1,263 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <msexec.h>
|
||||
#include <cwalk.h>
|
||||
#include <elf.h>
|
||||
#include <abi.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <dumper.hpp>
|
||||
#endif
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../Fex.hpp"
|
||||
|
||||
using namespace Tasking;
|
||||
|
||||
NewLock(ExecuteServiceLock);
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
Memory::MemMgr *mem = nullptr;
|
||||
std::vector<SharedLibraries> Libs;
|
||||
|
||||
void StartExecuteService()
|
||||
{
|
||||
mem = new Memory::MemMgr;
|
||||
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
foreach (auto &Lib in Libs)
|
||||
{
|
||||
if (Lib.RefCount > 0)
|
||||
{
|
||||
Lib.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
|
||||
debug("Reset timeout for %s", Lib.Identifier);
|
||||
continue;
|
||||
}
|
||||
if (Lib.Timeout < TimeManager->GetCounter())
|
||||
{
|
||||
// TODO: Remove
|
||||
fixme("Removed library %s because of timeout", Lib.Identifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Timeout for %s is %ld", Lib.Identifier, Lib.Timeout);
|
||||
}
|
||||
}
|
||||
debug("Waiting 10 seconds...");
|
||||
}
|
||||
TaskManager->Sleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
bool AddLibrary(char *Identifier, void *ElfImage, size_t Length, const Memory::Virtual &pV)
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
SharedLibraries sl;
|
||||
|
||||
foreach (auto lib in Libs)
|
||||
{
|
||||
if (strcmp(lib.Identifier, Identifier) == 0)
|
||||
{
|
||||
debug("Library %s already loaded", Identifier);
|
||||
lib.RefCount++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(sl.Identifier, Identifier);
|
||||
sl.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
|
||||
sl.RefCount = 0;
|
||||
|
||||
void *LibFile = mem->RequestPages(TO_PAGES(Length + 1), true);
|
||||
debug("LibFile: %#lx", LibFile);
|
||||
memcpy(LibFile, (void *)ElfImage, Length);
|
||||
Memory::Virtual().Map(LibFile, LibFile, Length, Memory::RW | Memory::US | Memory::G);
|
||||
|
||||
Memory::Virtual ncpV = pV;
|
||||
sl.MemoryImage = r_cst(uint64_t, ELFCreateMemoryImage(mem, ncpV, LibFile, Length).Physical);
|
||||
debug("MemoryImage: %#lx", sl.MemoryImage);
|
||||
|
||||
uintptr_t BaseAddress = UINTPTR_MAX;
|
||||
{
|
||||
#if defined(a64)
|
||||
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;
|
||||
#elif defined(a32)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(a64)
|
||||
struct Elf64_Dyn *JmpRel = ELFGetDynamicTag((void *)LibFile, DT_JMPREL);
|
||||
struct Elf64_Dyn *SymTab = ELFGetDynamicTag((void *)LibFile, DT_SYMTAB);
|
||||
struct Elf64_Dyn *StrTab = ELFGetDynamicTag((void *)LibFile, DT_STRTAB);
|
||||
|
||||
if (!JmpRel)
|
||||
{
|
||||
debug("No DT_JMPREL");
|
||||
}
|
||||
|
||||
if (!SymTab)
|
||||
{
|
||||
debug("No DT_SYMTAB");
|
||||
}
|
||||
|
||||
if (!StrTab)
|
||||
{
|
||||
debug("No DT_STRTAB");
|
||||
}
|
||||
|
||||
if (JmpRel && SymTab && StrTab)
|
||||
{
|
||||
debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx", JmpRel->d_un.d_ptr, SymTab->d_un.d_ptr, StrTab->d_un.d_ptr);
|
||||
Elf64_Rela *_JmpRel = (Elf64_Rela *)(sl.MemoryImage + (JmpRel->d_un.d_ptr - BaseAddress));
|
||||
Elf64_Sym *_SymTab = (Elf64_Sym *)(sl.MemoryImage + (SymTab->d_un.d_ptr - BaseAddress));
|
||||
|
||||
char *_DynStr = (char *)(sl.MemoryImage + (StrTab->d_un.d_ptr - BaseAddress));
|
||||
|
||||
Elf64_Shdr *gotSection = nullptr;
|
||||
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)LibFile)->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *shdr = (Elf64_Shdr *)((uint8_t *)LibFile + ((Elf64_Ehdr *)LibFile)->e_shoff + i * sizeof(Elf64_Shdr));
|
||||
if (shdr->sh_type == SHT_PROGBITS && (shdr->sh_flags & SHF_WRITE) && (shdr->sh_flags & SHF_ALLOC))
|
||||
{
|
||||
gotSection = shdr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("LIB_DBG");
|
||||
|
||||
if (gotSection)
|
||||
{
|
||||
Elf64_Xword numEntries = gotSection->sh_size / sizeof(Elf64_Addr);
|
||||
for (Elf64_Xword i = 0; i < numEntries - 3; i++)
|
||||
{
|
||||
Elf64_Rela *Rel = _JmpRel + i;
|
||||
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + sl.MemoryImage);
|
||||
|
||||
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
|
||||
debug("r_offset: %#lx RelType: %d", Rel->r_offset, RelType);
|
||||
|
||||
switch (RelType)
|
||||
{
|
||||
case R_X86_64_NONE:
|
||||
break;
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
{
|
||||
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
|
||||
Elf64_Sym *Sym = _SymTab + SymIndex;
|
||||
|
||||
if (Sym->st_name)
|
||||
{
|
||||
char *SymName = _DynStr + Sym->st_name;
|
||||
debug("SymName: %s", SymName);
|
||||
|
||||
Elf64_Sym *LibSym = ELFLookupSymbol((Elf64_Ehdr *)LibFile, SymName);
|
||||
|
||||
if (LibSym)
|
||||
{
|
||||
*GOTEntry = (Elf64_Addr)(sl.MemoryImage + LibSym->st_value);
|
||||
debug("GOT[%ld]: %#lx + %#lx = %#lx", i, sl.MemoryImage, LibSym->st_value, *GOTEntry);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("RelType %d not supported", RelType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("GOT[%ld](%#lx): %#lx", i, GOTEntry, *GOTEntry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("GOT section not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sl.Address = r_cst(uint64_t, LibFile);
|
||||
debug("Casted LibFile %#lx -> %#lx", LibFile, sl.Address);
|
||||
sl.Length = Length;
|
||||
|
||||
debug("Library %s loaded at %#lx (full file: %#lx)", Identifier, sl.MemoryImage, LibFile);
|
||||
|
||||
Libs.push_back(sl);
|
||||
return true;
|
||||
#elif defined(a32)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SearchLibrary(char *Identifier)
|
||||
{
|
||||
UNUSED(Identifier);
|
||||
SmartLock(ExecuteServiceLock);
|
||||
}
|
||||
|
||||
SharedLibraries GetLibrary(char *Identifier)
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
foreach (auto Lib in Libs)
|
||||
{
|
||||
if (strcmp(Lib.Identifier, Identifier) == 0)
|
||||
{
|
||||
Lib.RefCount++;
|
||||
debug("Library %s found (%#lx %#lx)", Identifier, Lib.Address, Lib.MemoryImage);
|
||||
return Lib;
|
||||
}
|
||||
}
|
||||
// throw std::runtime_error("Library not found");
|
||||
return SharedLibraries();
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
{
|
||||
void FEXLoad()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <msexec.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
#include "../Fex.hpp"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
BinaryType GetBinaryType(void *Image)
|
||||
{
|
||||
Fex *FexHdr = (Fex *)Image;
|
||||
|
||||
/* Elf64_Ehdr and Elf32_Ehdr are very similar (Elf64_Half and
|
||||
Elf32_Half are the same size type) so we can use directly Elf64_Ehdr. */
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)Image;
|
||||
|
||||
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Image;
|
||||
|
||||
/* Check Fex magic */
|
||||
if (FexHdr->Magic[0] == 'F' && FexHdr->Magic[1] == 'E' && FexHdr->Magic[2] == 'X' && FexHdr->Magic[3] == '\0')
|
||||
{
|
||||
/* If the fex type is driver, we shouldn't return as Fex. */
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
debug("Image - Fex");
|
||||
return BinaryType::BinTypeFex;
|
||||
}
|
||||
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
|
||||
{
|
||||
debug("Fex Driver is not supposed to be executed.");
|
||||
}
|
||||
}
|
||||
/* Check ELF magic. */
|
||||
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)
|
||||
{
|
||||
debug("Image - ELF");
|
||||
return BinaryType::BinTypeELF;
|
||||
}
|
||||
/* Every Windows executable starts with MZ header. */
|
||||
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Image) + MZHeader->e_lfanew);
|
||||
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Image) + MZHeader->e_lfanew);
|
||||
|
||||
/* TODO: LE, EDOS */
|
||||
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
debug("Image - PE");
|
||||
return BinaryType::BinTypePE;
|
||||
}
|
||||
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
|
||||
{
|
||||
debug("Image - NE");
|
||||
return BinaryType::BinTypeNE;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Image - MZ");
|
||||
return BinaryType::BinTypeMZ;
|
||||
}
|
||||
}
|
||||
|
||||
/* ... */
|
||||
return BinaryType::BinTypeUnknown;
|
||||
}
|
||||
|
||||
BinaryType GetBinaryType(char *Path)
|
||||
{
|
||||
BinaryType Type = BinaryType::BinTypeInvalid;
|
||||
VirtualFileSystem::File ExFile = vfs->Open(Path);
|
||||
|
||||
if (ExFile.IsOK())
|
||||
{
|
||||
debug("File opened: %s", Path);
|
||||
Type = GetBinaryType((void *)ExFile.node->Address);
|
||||
}
|
||||
|
||||
vfs->Close(ExFile);
|
||||
return Type;
|
||||
}
|
||||
}
|
@ -31,79 +31,69 @@ using namespace Tasking;
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
SpawnData Spawn(char *Path, const char **argv, const char **envp)
|
||||
{
|
||||
SpawnData ret = {.Status = ExStatus::Unknown,
|
||||
.Process = nullptr,
|
||||
.Thread = nullptr};
|
||||
SpawnData Spawn(char *Path, const char **argv, const char **envp)
|
||||
{
|
||||
SpawnData ret = {.Status = ExStatus::Unknown,
|
||||
.Process = nullptr,
|
||||
.Thread = nullptr};
|
||||
|
||||
VirtualFileSystem::File ExFile = vfs->Open(Path);
|
||||
VirtualFileSystem::File ExFile = vfs->Open(Path);
|
||||
|
||||
if (ExFile.IsOK())
|
||||
{
|
||||
if (ExFile.node->Flags != VirtualFileSystem::NodeFlags::FILE)
|
||||
{
|
||||
ret.Status = ExStatus::InvalidFilePath;
|
||||
goto Exit;
|
||||
}
|
||||
if (!ExFile.IsOK())
|
||||
{
|
||||
if (ExFile.Status == VirtualFileSystem::FileStatus::NotFound)
|
||||
{
|
||||
ret.Status = ExStatus::InvalidFilePath;
|
||||
goto Exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Status = ExStatus::InvalidFile;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
switch (GetBinaryType(Path))
|
||||
{
|
||||
case BinaryType::BinTypeFex:
|
||||
{
|
||||
Fex *FexHdr = (Fex *)ExFile.node->Address;
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User);
|
||||
if (ExFile.GetFlags() != VirtualFileSystem::NodeFlags::FILE)
|
||||
{
|
||||
ret.Status = ExStatus::InvalidFilePath;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile.node->Length + 1));
|
||||
memcpy(BaseImage, (void *)ExFile.node->Address, ExFile.node->Length);
|
||||
switch (GetBinaryType(Path))
|
||||
{
|
||||
case BinaryType::BinTypeFex:
|
||||
{
|
||||
Fex FexHdr;
|
||||
vfs->Read(ExFile, (uint8_t *)&FexHdr, sizeof(Fex));
|
||||
if (FexHdr.Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
stub;
|
||||
assert(false);
|
||||
}
|
||||
|
||||
Memory::Virtual(Process->PageTable).Map((void *)BaseImage, (void *)BaseImage, ExFile.node->Length, Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
ret.Status = ExStatus::InvalidFileHeader;
|
||||
break;
|
||||
}
|
||||
case BinaryType::BinTypeELF:
|
||||
{
|
||||
ELFBaseLoad bl = ELFLoad(Path, argv, envp);
|
||||
if (!bl.Success)
|
||||
{
|
||||
ret.Status = ExStatus::LoadingProcedureFailed;
|
||||
break;
|
||||
}
|
||||
ret = bl.sd;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ret.Status = ExStatus::Unsupported;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<AuxiliaryVector> auxv; // TODO!
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)FexHdr->EntryPoint,
|
||||
argv, envp, auxv,
|
||||
(IPOffset)BaseImage,
|
||||
TaskArchitecture::x64,
|
||||
TaskCompatibility::Native);
|
||||
ret.Process = Process;
|
||||
ret.Thread = Thread;
|
||||
ret.Status = ExStatus::OK;
|
||||
}
|
||||
|
||||
ret.Status = ExStatus::InvalidFileHeader;
|
||||
goto Exit;
|
||||
}
|
||||
case BinaryType::BinTypeELF:
|
||||
{
|
||||
ELFBaseLoad bl = ELFLoad(Path, argv, envp);
|
||||
if (!bl.Success)
|
||||
{
|
||||
ret.Status = ExStatus::GenericError;
|
||||
goto Exit;
|
||||
}
|
||||
ret = bl.sd;
|
||||
goto Exit;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ret.Status = ExStatus::Unsupported;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ExFile.Status == VirtualFileSystem::FileStatus::NotFound)
|
||||
ret.Status = ExStatus::InvalidFilePath;
|
||||
else
|
||||
ret.Status = ExStatus::InvalidFile;
|
||||
|
||||
Exit:
|
||||
vfs->Close(ExFile);
|
||||
return ret;
|
||||
}
|
||||
Exit:
|
||||
vfs->Close(ExFile);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user