83 lines
2.6 KiB
C
83 lines
2.6 KiB
C
#include "elf.h"
|
|
|
|
extern void* memset(void* dest, int ch, uptr count);
|
|
extern void* memcpy(void* dest, const void* src, uptr count);
|
|
|
|
[[noreturn]]
|
|
void ElfExecute(void* Binary, void* LoadAddr, struct boot_params* BootParams) {
|
|
struct Elf64_Ehdr* ElfHeader = (struct Elf64_Ehdr*)Binary;
|
|
|
|
// Here we would check if we have a valid elf binary
|
|
// unfortunately, we would have no way to notify the
|
|
// user, so we'll just pray it is
|
|
|
|
// Hopefully we have progtam headers
|
|
void* ProgramHeaders = Binary + ElfHeader->e_phoff;
|
|
|
|
// Load everything into memory
|
|
for (int i = 0; i < ElfHeader->e_phnum; i++) {
|
|
struct Elf64_Phdr* ProgramHeader = (struct Elf64_Phdr*)ProgramHeaders;
|
|
|
|
// Only load loadable segments
|
|
if (ProgramHeader->p_type == PT_LOAD) {
|
|
void* FileStart = Binary + ProgramHeader->p_offset;
|
|
void* LoadStart = LoadAddr + ProgramHeader->p_vaddr;
|
|
|
|
uptr LoadSize = ProgramHeader->p_memsz;
|
|
if (LoadSize > ProgramHeader->p_filesz) LoadSize = ProgramHeader->p_filesz;
|
|
|
|
memset(LoadStart, 0, ProgramHeader->p_memsz);
|
|
memcpy(LoadStart, FileStart, LoadSize);
|
|
}
|
|
|
|
ProgramHeaders += ElfHeader->e_phentsize;
|
|
}
|
|
|
|
// Dynamically link ourself
|
|
void* SectionHeaders = Binary + ElfHeader->e_shoff;
|
|
for (int i = 0; i < ElfHeader->e_shnum; i++) {
|
|
struct Elf64_Shdr* SectionHeader = (struct Elf64_Shdr*)SectionHeaders;
|
|
|
|
// Find RELA segments
|
|
if (SectionHeader->sh_type == SHT_RELA) {
|
|
struct Elf64_Shdr* SymbolTable = (struct Elf64_Shdr*)(Binary + ElfHeader->e_shoff + ElfHeader->e_shentsize * SectionHeader->sh_link);
|
|
|
|
void* RelocTab = Binary + SectionHeader->sh_offset;
|
|
void* SymblTab = Binary + SymbolTable->sh_offset;
|
|
|
|
for (int RelocOffset = 0; RelocOffset < SectionHeader->sh_size; RelocOffset += SectionHeader->sh_entsize) {
|
|
struct Elf64_Rela* Reloc = RelocTab + RelocOffset;
|
|
[[maybe_unused]] struct Elf64_Sym* Symbol = SymblTab + SymbolTable->sh_entsize * ELF64_R_SYM(Reloc->r_info);
|
|
|
|
void* Target = LoadAddr + Reloc->r_offset;
|
|
|
|
switch (ELF64_R_TYPE(Reloc->r_info)) {
|
|
case ELF64_R_AMD64_RELATIVE: {
|
|
*((u64*)Target) = (u64)(LoadAddr + Reloc->r_addend);
|
|
break;
|
|
}
|
|
default: {
|
|
while (1) {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SectionHeaders += ElfHeader->e_shentsize;
|
|
}
|
|
|
|
// Collect entry point
|
|
[[noreturn]] void fake_dont_call(struct boot_params*); // stupid hack
|
|
typeof(fake_dont_call)* KernelEntry = LoadAddr + ElfHeader->e_entry;
|
|
|
|
// Set boot parameters
|
|
struct setup_info* SetupInfo = (void*)BootParams + 0x1f1;
|
|
SetupInfo->code32_start = (u64)LoadAddr;
|
|
|
|
// Enter the kernel
|
|
KernelEntry(BootParams);
|
|
|
|
// we shouldnt ever end up here
|
|
__builtin_unreachable();
|
|
}
|