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:
parent
7a2e313a20
commit
261fc73146
@ -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);
|
||||
}
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user