Add an ELF Loader!!
This commit is contained in:
parent
53d36be339
commit
6e6cf5b2b0
48
kernel/include/sys/elf/ELF.h
Normal file
48
kernel/include/sys/elf/ELF.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define ELFMAG "\177ELF"
|
||||||
|
#define SELFMAG 4
|
||||||
|
#define EI_CLASS 4 /* File class byte index */
|
||||||
|
#define ELFCLASS64 2 /* 64-bit objects */
|
||||||
|
#define EI_DATA 5 /* Data encoding byte index */
|
||||||
|
#define ELFDATA2LSB 1 /* 2's complement, little endian */
|
||||||
|
#define ET_EXEC 2 /* Executable file */
|
||||||
|
#define PT_LOAD 1 /* Loadable program segment */
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#define EM_MACH 62 /* AMD x86-64 architecture */
|
||||||
|
#endif
|
||||||
|
#ifdef __aarch64__
|
||||||
|
#define EM_MACH 183 /* ARM aarch64 architecture */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t e_ident[16]; /* Magic number and other info */
|
||||||
|
uint16_t e_type; /* Object file type */
|
||||||
|
uint16_t e_machine; /* Architecture */
|
||||||
|
uint32_t e_version; /* Object file version */
|
||||||
|
uint64_t e_entry; /* Entry point virtual address */
|
||||||
|
uint64_t e_phoff; /* Program header table file offset */
|
||||||
|
uint64_t e_shoff; /* Section header table file offset */
|
||||||
|
uint32_t e_flags; /* Processor-specific flags */
|
||||||
|
uint16_t e_ehsize; /* ELF header size in bytes */
|
||||||
|
uint16_t e_phentsize; /* Program header table entry size */
|
||||||
|
uint16_t e_phnum; /* Program header table entry count */
|
||||||
|
uint16_t e_shentsize; /* Section header table entry size */
|
||||||
|
uint16_t e_shnum; /* Section header table entry count */
|
||||||
|
uint16_t e_shstrndx; /* Section header string table index */
|
||||||
|
} Elf64_Ehdr;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t p_type; /* Segment type */
|
||||||
|
uint32_t p_flags; /* Segment flags */
|
||||||
|
uint64_t p_offset; /* Segment file offset */
|
||||||
|
uint64_t p_vaddr; /* Segment virtual address */
|
||||||
|
uint64_t p_paddr; /* Segment physical address */
|
||||||
|
uint64_t p_filesz; /* Segment size in file */
|
||||||
|
uint64_t p_memsz; /* Segment size in memory */
|
||||||
|
uint64_t p_align; /* Segment alignment */
|
||||||
|
} Elf64_Phdr;
|
8
kernel/include/sys/elf/ELFLoader.h
Normal file
8
kernel/include/sys/elf/ELFLoader.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace ELFLoader
|
||||||
|
{
|
||||||
|
void* load_elf_from_address(uintptr_t addr);
|
||||||
|
void* load_elf_from_initrd(const char* filename);
|
||||||
|
}
|
79
kernel/src/sys/elf/ELFLoader.cpp
Normal file
79
kernel/src/sys/elf/ELFLoader.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#define MODULE "elf"
|
||||||
|
|
||||||
|
#include "sys/elf/ELFLoader.h"
|
||||||
|
#include "init/InitRD.h"
|
||||||
|
#include "log/Log.h"
|
||||||
|
#include "memory/MemoryManager.h"
|
||||||
|
#include "misc/utils.h"
|
||||||
|
#include "std/string.h"
|
||||||
|
#include "sys/elf/ELF.h"
|
||||||
|
|
||||||
|
void* ELFLoader::load_elf_from_initrd(const char* filename)
|
||||||
|
{
|
||||||
|
InitRD::File elf_file = InitRD::open(filename);
|
||||||
|
if (!elf_file.addr)
|
||||||
|
{
|
||||||
|
kwarnln("failed to open file %s for loading", filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return load_elf_from_address((uintptr_t)elf_file.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ELFLoader::load_elf_from_address(uintptr_t addr)
|
||||||
|
{
|
||||||
|
Elf64_Ehdr* elf_ehdr = (Elf64_Ehdr*)addr;
|
||||||
|
if (strncmp((const char*)elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0)
|
||||||
|
{
|
||||||
|
kwarnln("ELF file has invalid magic, skipping");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (elf_ehdr->e_ident[EI_CLASS] != ELFCLASS64)
|
||||||
|
{
|
||||||
|
kwarnln("ELF file is not ELF64, skipping");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (elf_ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||||
|
{
|
||||||
|
kwarnln("ELF file is not little-endian, skipping");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (elf_ehdr->e_type != ET_EXEC)
|
||||||
|
{
|
||||||
|
kwarnln("not supported: ELF file is not an executable");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (elf_ehdr->e_machine != EM_MACH)
|
||||||
|
{
|
||||||
|
kwarnln("unsupported target machine");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (elf_ehdr->e_phnum == 0)
|
||||||
|
{
|
||||||
|
kwarnln("ELF file has no PHDRS");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int i;
|
||||||
|
Elf64_Phdr* phdr;
|
||||||
|
for (phdr = (Elf64_Phdr*)((uint64_t)addr + elf_ehdr->e_phoff), i = 0; i < elf_ehdr->e_phnum;
|
||||||
|
i++, phdr = (Elf64_Phdr*)((uint8_t*)phdr + elf_ehdr->e_phentsize))
|
||||||
|
{
|
||||||
|
if (phdr->p_type == PT_LOAD)
|
||||||
|
{
|
||||||
|
kdbgln("loading loadable segment at vaddr %lx, filesz %ld, memsz %ld", phdr->p_vaddr, phdr->p_filesz,
|
||||||
|
phdr->p_memsz);
|
||||||
|
if (!phdr->p_vaddr)
|
||||||
|
{
|
||||||
|
kerrorln("vaddr is NULL, this is invalid :(");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int pages = Utilities::get_blocks_from_size(0x1000, phdr->p_memsz);
|
||||||
|
void* buffer = MemoryManager::get_pages_at(phdr->p_vaddr, pages,
|
||||||
|
phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
|
||||||
|
memcpy(buffer, (void*)(addr + phdr->p_offset), phdr->p_filesz);
|
||||||
|
memset((void*)((uint64_t)buffer + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
|
||||||
|
}
|
||||||
|
else { kdbgln("skipping non-loadable segment"); }
|
||||||
|
}
|
||||||
|
return (void*)elf_ehdr->e_entry;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user