Restructured and rewritten entire codebase

This commit is contained in:
Alex
2023-10-09 01:16:24 +03:00
parent 446a571018
commit 889e1522a3
484 changed files with 15683 additions and 14032 deletions

115
exec/binary_parse.cpp Normal file
View File

@ -0,0 +1,115 @@
/*
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(const char *Path)
{
BinaryType Type;
int fd = fopen(Path, "r");
if (fd < 0)
return (BinaryType)fd;
debug("File opened: %s, descriptor %d", Path, fd);
Memory::SmartHeap sh = Memory::SmartHeap(1024);
fread(fd, sh, 128);
Fex *FexHdr = (Fex *)sh.Get();
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)sh.Get();
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)sh.Get();
/* 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_Executable)
{
debug("Image - Fex");
Type = BinaryType::BinTypeFex;
goto Success;
}
else if (FexHdr->Type == FexFormatType_Module)
{
fixme("Fex Module is not supposed to be executed.");
/* TODO: Module 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)
{
lseek(fd, MZHeader->e_lfanew, SEEK_SET);
fread(fd, sh, 512);
IMAGE_NT_HEADERS *PEHeader =
(IMAGE_NT_HEADERS *)(((char *)sh.Get()) +
MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader =
(IMAGE_OS2_HEADER *)(((char *)sh.Get()) +
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:
fclose(fd);
return Type;
}
}

862
exec/elf/elf_loader.cpp Normal file
View File

@ -0,0 +1,862 @@
/*
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 <rand.hpp>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using namespace vfs;
namespace Execute
{
void ELFObject::LoadPhdrs_x86_32(int fd,
Elf64_Ehdr ELFHeader,
Memory::VirtualMemoryArea *vma,
PCB *TargetProcess)
{
stub;
UNUSED(fd);
UNUSED(ELFHeader);
UNUSED(TargetProcess);
}
void ELFObject::LoadPhdrs_x86_64(int fd,
Elf64_Ehdr ELFHeader,
Memory::VirtualMemoryArea *vma,
PCB *TargetProcess)
{
#if defined(a64)
// assert(ELFHeader.e_phentsize == sizeof(Elf64_Phdr));
size_t size = ELFHeader.e_phnum * sizeof(Elf64_Phdr);
assert(size > 0);
assert(size < 65536);
assert(size < PAGE_SIZE);
ELFProgramHeaders = vma->RequestPages(TO_PAGES(size), true);
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (uint8_t *)ELFProgramHeaders, size);
#endif
}
void ELFObject::GenerateAuxiliaryVector_x86_32(Memory::VirtualMemoryArea *vma,
int fd,
Elf32_Ehdr ELFHeader,
uint32_t EntryPoint,
uint32_t BaseAddress)
{
}
void ELFObject::GenerateAuxiliaryVector_x86_64(Memory::VirtualMemoryArea *vma,
int fd,
Elf64_Ehdr ELFHeader,
uint64_t EntryPoint,
uint64_t BaseAddress)
{
#if defined(a64)
char *aux_platform = (char *)vma->RequestPages(1, true); /* TODO: 4KiB is too much for this */
strcpy(aux_platform, "x86_64");
const char *execfn = thisProcess->FileDescriptors->GetAbsolutePath(fd);
void *execfn_str = vma->RequestPages(TO_PAGES(strlen(execfn) + 1), true);
strcpy((char *)execfn_str, execfn);
delete[] execfn;
void *at_random = vma->RequestPages(1, true);
*(uint64_t *)at_random = Random::rand16();
Elfauxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
Elfauxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)execfn_str}}});
// AT_HWCAP2 26
Elfauxv.push_back({.archaux = {.a_type = AT_RANDOM, .a_un = {.a_val = (uint64_t)at_random}}});
Elfauxv.push_back({.archaux = {.a_type = AT_SECURE, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_EGID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_GID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_EUID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_UID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
// AT_FLAGS 8
Elfauxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)BaseAddress}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFProgramHeaders}}});
// AT_CLKTCK 17
Elfauxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
// AT_HWCAP 16
// AT_MINSIGSTKSZ 51
// AT_SYSINFO_EHDR 33
#endif
}
void ELFObject::LoadExec_x86_32(int fd, PCB *TargetProcess)
{
stub;
UNUSED(fd);
UNUSED(TargetProcess);
}
void ELFObject::LoadExec_x86_64(int fd, PCB *TargetProcess)
{
#if defined(a64)
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
Memory::SmartHeap InterpreterPath = Memory::SmartHeap(256);
lseek(fd, Interp.p_offset, SEEK_SET);
fread(fd, InterpreterPath, 256);
int ifd = fopen((const char *)InterpreterPath.Get(), "r");
if (ifd < 0)
{
warn("Failed to open interpreter file: %s",
(const char *)InterpreterPath.Get());
continue;
}
else
{
if (GetBinaryType((const char *)InterpreterPath.Get()) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file",
(const char *)InterpreterPath.Get());
fclose(ifd);
continue;
}
if (LoadInterpreter(ifd, TargetProcess))
{
/* FIXME: specify argv[1] as the location for the interpreter */
debug("Interpreter loaded successfully");
fclose(ifd);
return;
}
}
}
Elf64_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint);
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable);
Memory::VirtualMemoryArea *vma = TargetProcess->vma;
LoadPhdrs_x86_64(fd, ELFHeader, vma, TargetProcess);
/* Copy segments into memory */
{
Elf64_Phdr ProgramBreakHeader{};
Elf64_Phdr ProgramHeader;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
switch (ProgramHeader.p_type)
{
case PT_LOAD:
{
if (ProgramHeader.p_memsz == 0)
continue;
void *pAddr = vma->RequestPages(TO_PAGES(ProgramHeader.p_memsz), true);
void *SegmentDestination = (void *)ProgramHeader.p_vaddr;
vmm.Map(SegmentDestination, pAddr,
ProgramHeader.p_memsz,
Memory::P | Memory::RW | Memory::US);
debug("Mapped %#lx to %#lx", SegmentDestination, pAddr);
debug("Copying segment to p: %#lx-%#lx; v: %#lx-%#lx (%ld file bytes, %ld mem bytes)",
pAddr, uintptr_t(pAddr) + ProgramHeader.p_memsz,
SegmentDestination, uintptr_t(SegmentDestination) + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)pAddr, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(uintptr_t(pAddr) + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
ProgramBreakHeader = ProgramHeader;
break;
}
default:
{
fixme("Unhandled program header type: %#lx",
ProgramHeader.p_type);
break;
}
}
}
/* Set program break */
uintptr_t ProgramBreak = ROUND_UP(ProgramBreakHeader.p_vaddr +
ProgramBreakHeader.p_memsz,
PAGE_SIZE);
TargetProcess->ProgramBreak->InitBrk(ProgramBreak);
}
struct stat statbuf;
fstat(fd, &statbuf);
Memory::SmartHeap sh = Memory::SmartHeap(statbuf.st_size);
lseek(fd, 0, SEEK_SET);
fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get()));
debug("Entry Point: %#lx", EntryPoint);
this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader,
EntryPoint, 0);
this->ip = EntryPoint;
this->IsElfValid = true;
#endif
}
void ELFObject::LoadDyn_x86_32(int fd, PCB *TargetProcess)
{
stub;
UNUSED(fd);
UNUSED(TargetProcess);
}
void ELFObject::LoadDyn_x86_64(int fd, PCB *TargetProcess)
{
#if defined(a64)
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
Memory::SmartHeap InterpreterPath = Memory::SmartHeap(256);
lseek(fd, Interp.p_offset, SEEK_SET);
fread(fd, InterpreterPath, 256);
InterpreterPath = InterpreterPath;
int ifd = fopen((const char *)InterpreterPath.Get(), "r");
if (ifd < 0)
{
warn("Failed to open interpreter file: %s",
(const char *)InterpreterPath.Get());
continue;
}
else
{
if (GetBinaryType((const char *)InterpreterPath.Get()) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file",
(const char *)InterpreterPath.Get());
fclose(ifd);
continue;
}
if (LoadInterpreter(ifd, TargetProcess))
{
/* FIXME: specify argv[1] as the location for the interpreter */
debug("Interpreter loaded successfully");
fclose(ifd);
return;
}
}
}
Elf64_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint);
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable);
Memory::VirtualMemoryArea *vma = TargetProcess->vma;
uintptr_t BaseAddress = 0;
LoadPhdrs_x86_64(fd, ELFHeader, vma, TargetProcess);
/* Copy segments into memory */
{
Elf64_Phdr ProgramBreakHeader{};
Elf64_Phdr ProgramHeader;
size_t SegmentsSize = 0;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
if (ProgramHeader.p_type == PT_LOAD ||
ProgramHeader.p_type == PT_DYNAMIC)
{
if (SegmentsSize < ProgramHeader.p_vaddr + ProgramHeader.p_memsz)
{
SegmentsSize = ProgramHeader.p_vaddr + ProgramHeader.p_memsz;
ProgramBreakHeader = ProgramHeader;
}
}
}
debug("SegmentsSize: %#lx", SegmentsSize);
/* TODO: Check if this is correct and/or it needs more
complex calculations & allocations */
void *SegmentsAddress = vma->RequestPages(TO_PAGES(SegmentsSize) + 1, true);
BaseAddress = (uintptr_t)SegmentsAddress;
debug("BaseAddress: %#lx, End: %#lx (%#lx)", BaseAddress,
BaseAddress + FROM_PAGES(TO_PAGES(SegmentsSize)),
SegmentsSize);
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
switch (ProgramHeader.p_type)
{
case PT_LOAD:
{
/* Because this is ET_DYN, we can load the segments
anywhere we want. */
uintptr_t SegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
if (ProgramHeader.p_memsz == 0)
continue;
debug("Copying PT_LOAD to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
SegmentDestination, SegmentDestination + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)SegmentDestination, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(SegmentDestination + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
case PT_DYNAMIC:
{
/* PT_DYNAMIC contains the dynamic linking information for the
executable or shared library. */
uintptr_t DynamicSegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
if (ProgramHeader.p_memsz == 0)
continue;
debug("Copying PT_DYNAMIC to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
DynamicSegmentDestination, DynamicSegmentDestination + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)DynamicSegmentDestination, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(DynamicSegmentDestination + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
default:
{
fixme("Unhandled program header type: %#lx",
ProgramHeader.p_type);
break;
}
}
}
/* Set program break */
uintptr_t ProgramBreak = ROUND_UP(BaseAddress +
ProgramBreakHeader.p_vaddr +
ProgramBreakHeader.p_memsz,
PAGE_SIZE);
TargetProcess->ProgramBreak->InitBrk(ProgramBreak);
}
EntryPoint += BaseAddress;
debug("The new ep is %#lx", EntryPoint);
std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(fd, DT_JMPREL);
std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(fd, DT_STRTAB);
std::vector<Elf64_Dyn> RelaDyn = ELFGetDynamicTag_x86_64(fd, DT_RELA);
std::vector<Elf64_Dyn> RelaDynSize = ELFGetDynamicTag_x86_64(fd, DT_RELASZ);
size_t JmpRelSize = JmpRel.size();
size_t SymTabSize = SymTab.size();
size_t StrTabSize = StrTab.size();
size_t RelaDynSize_v = RelaDyn.size();
if (JmpRelSize < 1)
{
debug("No DT_JMPREL");
}
if (SymTabSize < 1)
{
debug("No DT_SYMTAB");
}
if (StrTabSize < 1)
{
debug("No DT_STRTAB");
}
if (RelaDynSize_v < 1)
{
debug("No DT_RELA");
}
if (RelaDynSize[0].d_un.d_val < 1)
{
debug("DT_RELASZ is < 1");
}
if (JmpRelSize > 0 && SymTabSize > 0 && StrTabSize > 0)
{
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)BaseAddress + JmpRel[0].d_un.d_ptr);
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr);
char *_DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr);
Elf64_Rela *_RelaDyn = (Elf64_Rela *)((uintptr_t)BaseAddress + RelaDyn[0].d_un.d_ptr);
Elf64_Shdr shdr;
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
{
lseek(fd, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET);
fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
char sectionName[32];
Elf64_Shdr n_shdr;
lseek(fd, ELFHeader.e_shoff + ELFHeader.e_shstrndx * sizeof(Elf64_Shdr), SEEK_SET);
fread(fd, (uint8_t *)&n_shdr, sizeof(Elf64_Shdr));
lseek(fd, n_shdr.sh_offset + shdr.sh_name, SEEK_SET);
fread(fd, (uint8_t *)sectionName, 32);
debug("shdr: %s", sectionName);
if (strcmp(sectionName, ".rela.plt") == 0)
{
// .rela.plt
// R_X86_64_JUMP_SLOT
Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize;
for (Elf64_Xword i = 0; i < numEntries; i++)
{
Elf64_Addr *GOTEntry = (Elf64_Addr *)(shdr.sh_addr +
BaseAddress +
i * sizeof(Elf64_Addr));
Elf64_Rela *Rel = _JmpRel + i;
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
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(fd, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
debug("GOT[%ld](%#lx): %#lx",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
continue;
}
default:
{
fixme("Unhandled relocation type: %#lx", RelType);
break;
}
}
}
}
else if (strcmp(sectionName, ".rela.dyn") == 0)
{
// .rela.dyn
// R_X86_64_RELATIVE
// R_X86_64_GLOB_DAT
if (RelaDynSize_v < 1 || RelaDynSize[0].d_un.d_val < 1)
continue;
Elf64_Xword numRelaDynEntries = RelaDynSize[0].d_un.d_val / sizeof(Elf64_Rela);
for (Elf64_Xword i = 0; i < numRelaDynEntries; i++)
{
Elf64_Rela *Rel = _RelaDyn + i;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + BaseAddress);
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
case R_X86_64_RELATIVE:
{
*GOTEntry = (Elf64_Addr)(BaseAddress + Rel->r_addend);
debug("GOT[%ld](%#lx): %#lx (R_X86_64_RELATIVE)",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
break;
}
case R_X86_64_GLOB_DAT:
{
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(fd, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
debug("GOT[%ld](%#lx): %#lx (R_X86_64_GLOB_DAT)",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
break;
}
default:
{
fixme("Unhandled relocation type: %#lx", RelType);
break;
}
}
}
}
else if (strcmp(sectionName, ".dynsym") == 0)
{
// .dynsym
// STT_OBJECT
Elf64_Sym *SymArray = (Elf64_Sym *)(shdr.sh_addr + BaseAddress);
Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize;
debug("start %#lx (off %#lx), entries %ld",
SymArray, shdr.sh_addr, numEntries);
for (Elf64_Xword j = 0; j < numEntries; j++)
{
Elf64_Sym Sym = SymArray[j];
if (Sym.st_shndx == SHN_UNDEF)
continue;
if (Sym.st_value == 0)
continue;
unsigned char SymType = ELF64_ST_TYPE(Sym.st_info);
if (SymType == STT_OBJECT)
{
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress);
*GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value);
debug("%ld: \"%s\" %#lx -> %#lx", j,
_DynStr + Sym.st_name,
uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
}
else if (strcmp(sectionName, ".symtab") == 0)
{
// .symtab
// STT_OBJECT
Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize;
Elf64_Sym *SymArray = new Elf64_Sym[numEntries];
lseek(fd, shdr.sh_offset, SEEK_SET);
fread(fd, (uint8_t *)SymArray, shdr.sh_size);
debug("start %#lx (off %#lx), entries %ld",
SymArray, shdr.sh_addr, numEntries);
for (Elf64_Xword j = 0; j < numEntries; j++)
{
Elf64_Sym Sym = SymArray[j];
if (Sym.st_shndx == SHN_UNDEF)
continue;
if (Sym.st_value == 0)
continue;
unsigned char SymType = ELF64_ST_TYPE(Sym.st_info);
if (SymType == STT_OBJECT)
{
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress);
*GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value);
debug("%ld: \"<fixme>\" %#lx -> %#lx", j,
/*_DynStr + Sym.st_name,*/
uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
delete[] SymArray;
}
// if (shdr.sh_type == SHT_PROGBITS &&
// (shdr.sh_flags & SHF_WRITE) &&
// (shdr.sh_flags & SHF_ALLOC))
}
}
/* ------------------------------------------------------------------------ */
struct stat statbuf;
fstat(fd, &statbuf);
Memory::SmartHeap sh = Memory::SmartHeap(statbuf.st_size);
lseek(fd, 0, SEEK_SET);
fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get()), BaseAddress);
debug("Entry Point: %#lx", EntryPoint);
this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader,
EntryPoint, BaseAddress);
this->ip = EntryPoint;
this->IsElfValid = true;
#endif
}
bool ELFObject::LoadInterpreter(int fd, PCB *TargetProcess)
{
Elf32_Ehdr ELFHeader;
fread(fd, &ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadExec_x86_32(fd, TargetProcess);
return true;
case EM_X86_64:
this->LoadExec_x86_64(fd, TargetProcess);
return true;
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->LoadDyn_x86_32(fd, TargetProcess);
return true;
case EM_X86_64:
this->LoadDyn_x86_64(fd, TargetProcess);
return true;
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;
}
}
return false;
}
ELFObject::ELFObject(char *AbsolutePath,
PCB *TargetProcess,
const char **argv,
const char **envp)
{
if (GetBinaryType(AbsolutePath) != BinaryType::BinTypeELF)
{
error("%s is not an ELF file or is invalid.", AbsolutePath);
return;
}
int fd = fopen(AbsolutePath, "r");
if (fd < 0)
{
error("Failed to open %s, errno: %d", AbsolutePath, fd);
return;
}
int argc = 0;
int envc = 0;
while (argv[argc] != nullptr)
argc++;
while (envp[envc] != nullptr)
envc++;
// ELFargv = new const char *[argc + 2];
size_t argv_size = TO_PAGES(argc + 2 * sizeof(char *));
ELFargv = (const char **)TargetProcess->vma->RequestPages(argv_size);
for (int i = 0; i < argc; i++)
{
size_t arg_size = TO_PAGES(strlen(argv[i]) + 1);
ELFargv[i] = (const char *)TargetProcess->vma->RequestPages(arg_size);
strcpy((char *)ELFargv[i], argv[i]);
}
ELFargv[argc] = nullptr;
// ELFenvp = new const char *[envc + 1];
size_t envp_size = TO_PAGES(envc + 1 * sizeof(char *));
ELFenvp = (const char **)TargetProcess->vma->RequestPages(envp_size);
for (int i = 0; i < envc; i++)
{
size_t env_size = TO_PAGES(strlen(envp[i]) + 1);
ELFenvp[i] = (const char *)TargetProcess->vma->RequestPages(env_size);
strcpy((char *)ELFenvp[i], envp[i]);
}
ELFenvp[envc] = nullptr;
Elf32_Ehdr ELFHeader;
fread(fd, &ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadExec_x86_32(fd, TargetProcess);
break;
case EM_X86_64:
this->LoadExec_x86_64(fd, 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->LoadDyn_x86_32(fd, TargetProcess);
break;
case EM_X86_64:
this->LoadDyn_x86_64(fd, 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_CORE:
{
fixme("ET_CORE not implemented");
break;
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader.e_type);
break;
}
}
fclose(fd);
}
ELFObject::~ELFObject()
{
}
}

207
exec/elf/elf_parse.cpp Normal file
View File

@ -0,0 +1,207 @@
/*
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(int fd, const char *Name)
{
#if defined(a64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
Elf64_Ehdr Header;
lseek(fd, 0, SEEK_SET);
fread(fd, (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;
lseek(fd, Header.e_shoff + (i * sizeof(Elf64_Shdr)), SEEK_SET);
fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
switch (shdr.sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
lseek(fd, Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)), SEEK_SET);
fread(fd, (uint8_t *)&StringTable, sizeof(Elf64_Shdr));
break;
default:
{
break;
}
}
}
if (SymbolTable.sh_name == 0 ||
StringTable.sh_name == 0)
{
error("Symbol table not found.");
lseek(fd, 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;
lseek(fd, SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), SEEK_SET);
fread(fd, (uint8_t *)&Symbol, sizeof(Elf64_Sym));
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
char String[256];
lseek(fd, StringTable.sh_offset + Symbol.st_name, SEEK_SET);
fread(fd, (uint8_t *)&String, 256);
if (strcmp(String, Name) == 0)
{
lseek(fd, OldOffset, SEEK_SET);
return Symbol;
}
}
error("Symbol not found.");
lseek(fd, OldOffset, SEEK_SET);
#endif
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;
}
#elif defined(a32)
return 0xdead;
#endif
}
}

102
exec/elf/elf_rel.cpp Normal file
View File

@ -0,0 +1,102 @@
/*
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 */
void ELFLoadRel(void *BaseImage,
const char *Name,
Tasking::PCB *Process)
{
#if defined(a64)
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");
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_NOBITS)
{
if (!Section->sh_size)
continue;
if (Section->sh_flags & SHF_ALLOC)
{
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size + 1));
memset(Buffer, 0, Section->sh_size);
Memory::Virtual(Process->PageTable).Map((void *)Buffer, (void *)Buffer, Section->sh_size, Memory::PTFlag::RW | Memory::PTFlag::US);
Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage;
debug("Section %ld", Section->sh_size);
}
}
}
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_REL)
{
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
{
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index];
Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info);
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset);
uint64_t SymbolValue = 0;
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
{
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead)
return;
}
switch (ELF64_R_TYPE(RelTable->r_info))
{
case R_386_NONE:
break;
case R_386_32:
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
break;
case R_386_PC32:
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
break;
default:
{
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
return;
}
}
debug("Symbol value: %#lx", SymbolValue);
}
}
}
#elif defined(a32)
#endif
}
}

View File

@ -0,0 +1,66 @@
/*
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(int fd,
DynamicArrayTags Tag)
{
#if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Dyn> Ret;
Elf64_Ehdr ELFHeader;
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, 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++)
{
lseek(fd, Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET);
fread(fd, (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);
}
}
lseek(fd, OldOffset, SEEK_SET);
return Ret;
#elif defined(a32)
return {};
#endif
}
}

View File

@ -0,0 +1,58 @@
/*
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(int fd,
const char *SectionName)
{
#if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Shdr> Ret;
Elf64_Ehdr ELFHeader;
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum];
lseek(fd, ELFHeader.e_shoff, SEEK_SET);
fread(fd, (uint8_t *)SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum);
char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size];
lseek(fd, SectionHeaders[ELFHeader.e_shstrndx].sh_offset, SEEK_SET);
fread(fd, (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]);
}
lseek(fd, OldOffset, SEEK_SET);
delete[] SectionHeaders;
delete[] SectionNames;
return Ret;
#elif defined(a32)
return {};
#endif
}
}

View 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_Phdr> ELFGetSymbolType_x86_64(int fd,
SegmentTypes Tag)
{
#if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Phdr> Ret;
Elf64_Ehdr ELFHeader;
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Phdr ProgramHeaders;
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (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);
lseek(fd, sizeof(Elf64_Phdr), SEEK_CUR);
fread(fd, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
}
lseek(fd, OldOffset, SEEK_SET);
return Ret;
#elif defined(a32)
return {};
#endif
}
}

179
exec/spawn.cpp Normal file
View File

@ -0,0 +1,179 @@
/*
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
{
int Spawn(char *Path, const char **argv, const char **envp,
Tasking::PCB *Parent,
Tasking::TaskCompatibility Compatibility,
bool Critical)
{
int fd = fopen(Path, "r");
if (fd < 0)
return fd;
struct stat statbuf;
fstat(fd, &statbuf);
if (!S_ISREG(statbuf.st_mode))
{
fclose(fd);
return -EISDIR;
}
switch (GetBinaryType(Path))
{
case BinaryType::BinTypeFex:
{
Fex FexHdr;
fread(fd, (uint8_t *)&FexHdr, sizeof(Fex));
if (FexHdr.Type == FexFormatType::FexFormatType_Executable)
{
stub;
assert(false);
}
fclose(fd);
return -ENOEXEC;
}
case BinaryType::BinTypeELF:
{
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
Elf32_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr));
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:
error("Unknown ELF architecture %d",
ELFHeader.e_machine);
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
/* ------------------------------------------------------------------------------------------------------------------------------ */
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(statbuf.st_size + 1));
fread(fd, (uint8_t *)ElfFile, statbuf.st_size);
debug("Loaded elf %s at %#lx with the length of %ld",
Path, ElfFile, statbuf.st_size);
if (Parent == nullptr)
Parent = thisProcess;
PCB *Process = TaskManager->CreateProcess(Parent,
BaseName,
TaskExecutionMode::User,
ElfFile, false,
0, 0);
KernelAllocator.FreePages(ElfFile, TO_PAGES(statbuf.st_size + 1));
Process->SetWorkingDirectory(fs->GetNodeFromPath(Path)->Parent);
Process->Info.Compatibility = TaskCompatibility::Native;
Process->Info.Architecture = TaskArchitecture::x64;
ELFObject *obj = new ELFObject(Path, Process, argv, envp);
if (!obj->IsValid)
{
error("Failed to load ELF object");
fclose(fd);
delete Process;
return -ENOEXEC;
}
/* FIXME: implement stdio fildes */
vfs::FileDescriptorTable *fdt = Process->FileDescriptors;
// stdin
fdt->_open("/dev/tty", O_RDWR, 0666);
// stdout
fdt->_open("/dev/tty", O_RDWR, 0666);
// stderr
fdt->_open("/dev/tty", O_RDWR, 0666);
TCB *Thread = nullptr;
{
CriticalSection cs;
Thread = TaskManager->CreateThread(Process,
obj->InstructionPointer,
obj->argv, obj->envp, obj->auxv,
Arch,
Compatibility);
Thread->SetCritical(Critical);
}
fclose(fd);
return Thread->ID;
}
default:
{
debug("Unknown binary type: %d",
GetBinaryType(Path));
fclose(fd);
return -ENOEXEC;
}
}
fclose(fd);
return -ENOEXEC;
}
}