ELFLoader: Read the ELF file header by header using the VFS

Instead of just allocating one big redundant blob of memory and reading into it, then having to free it...
This commit is contained in:
apio 2022-10-12 18:23:52 +02:00
parent 7a2e313a20
commit 261fc73146
2 changed files with 30 additions and 37 deletions

View File

@ -1,10 +1,11 @@
#pragma once
#include "fs/VFS.h"
#include "sys/elf/Image.h"
#include <stdint.h>
namespace ELFLoader
{
ELFImage* load_elf_from_address(uintptr_t addr);
ELFImage* load_elf_from_vfs(VFS::Node* node);
ELFImage* load_elf_from_filesystem(const char* filename);
void release_elf_image(ELFImage* image);
}

View File

@ -36,80 +36,72 @@ ELFImage* ELFLoader::load_elf_from_filesystem(const char* filename)
return 0;
}
void* file = kmalloc(node->length);
if (VFS::read(node, 0, node->length, (char*)file) < 0)
{
kwarnln("Failed to read ELF image from file");
kfree(file);
return 0;
}
ELFImage* result =
load_elf_from_address((uintptr_t)file); // FIXME: Read headers and sections as we go along the file, to avoid
// loading the entire file at once into memory.
kfree(file);
ELFImage* result = load_elf_from_vfs(node);
return result;
}
ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)
ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node)
{
Elf64_Ehdr* elf_ehdr = (Elf64_Ehdr*)addr;
if (strncmp((const char*)elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0)
Elf64_Ehdr elf_ehdr;
if (VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) < 0)
{
kwarnln("Unable to read ELF header");
return 0;
}
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)
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)
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)
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)
if (elf_ehdr.e_machine != EM_MACH)
{
kwarnln("Unsupported target machine");
return 0;
}
if (elf_ehdr->e_phnum == 0)
if (elf_ehdr.e_phnum == 0)
{
kwarnln("ELF file has no PHDRS");
return 0;
}
ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection));
memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection));
image->entry = elf_ehdr->e_entry;
image->entry = elf_ehdr.e_entry;
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))
Elf64_Phdr phdr;
for (VFS::read(node, elf_ehdr.e_phoff, sizeof(Elf64_Phdr), (char*)&phdr), i = 0; i < elf_ehdr.e_phnum;
i++, VFS::read(node, elf_ehdr.e_phoff + (i * elf_ehdr.e_phentsize), sizeof(Elf64_Phdr), (char*)&phdr))
{
if (phdr->p_type == PT_LOAD)
if (phdr.p_type == PT_LOAD)
{
kdbgln("Loading loadable segment at address %lx, file size %ld, mem size %ld, permissions %s",
phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz, format_permissions(phdr->p_flags));
if (!phdr->p_vaddr)
kdbgln("Loading loadable segment at address %lx, file size %ld, mem size %ld, permissions %s", phdr.p_vaddr,
phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags));
if (!phdr.p_vaddr)
{
kerrorln("Address is NULL, this is invalid :(");
return 0;
}
uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr->p_vaddr % PAGE_SIZE) + phdr->p_memsz);
uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz);
void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(
Utilities::round_down_to_nearest_page(phdr->p_vaddr), pages,
phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER) +
(phdr->p_vaddr % PAGE_SIZE));
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);
Utilities::round_down_to_nearest_page(phdr.p_vaddr), pages,
phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER) +
(phdr.p_vaddr % PAGE_SIZE));
VFS::read(node, phdr.p_offset, phdr.p_filesz, (char*)buffer);
memset((void*)((uint64_t)buffer + phdr.p_filesz), 0, phdr.p_memsz - phdr.p_filesz);
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
(image->section_count + 1) * sizeof(ELFSection));
ELFSection& section = image->sections[image->section_count];