wip: shared library support

This commit is contained in:
2026-04-05 15:14:07 +02:00
parent d6c0470c62
commit 01c242d4de
20 changed files with 1026 additions and 4 deletions
+138
View File
@@ -149,4 +149,142 @@ namespace Sched {
return entryPoint;
}
uint64_t ElfLoadLib(const char* vfsPath, uint64_t pml4Phys, int slot) {
Fs::Vfs::BackendFile file = {-1, -1};
if (Fs::Vfs::OpenBackendFile(vfsPath, file) < 0) {
return 0;
}
uint64_t fileSize = Fs::Vfs::GetBackendFileSize(file);
if (fileSize < sizeof(Elf64Header)) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "File too small (" << fileSize << " bytes)";
Fs::Vfs::CloseBackendFile(file);
return 0;
}
// Read entire file into a heap buffer
uint8_t* fileData = (uint8_t*)Memory::g_heap->Request(fileSize);
if (fileData == nullptr) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Failed to allocate " << fileSize << " bytes for file";
Fs::Vfs::CloseBackendFile(file);
return 0;
}
Fs::Vfs::ReadBackendFile(file, fileData, 0, fileSize);
Fs::Vfs::CloseBackendFile(file);
asm volatile("" ::: "memory");
Elf64Header* hdr = (Elf64Header*)fileData;
// Validate ELF header
if (hdr->e_ident[0] != 0x7f ||
hdr->e_ident[1] != 'E' ||
hdr->e_ident[2] != 'L' ||
hdr->e_ident[3] != 'F') {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Invalid ELF magic";
Memory::g_heap->Free(fileData);
return 0;
}
if (hdr->e_ident[4] != 2) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Not a 64-bit ELF";
Memory::g_heap->Free(fileData);
return 0;
}
if (hdr->e_ident[5] != 1) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Not little-endian";
Memory::g_heap->Free(fileData);
return 0;
}
// Libraries are built as ET_EXEC at a fixed base (0x60000000)
if (hdr->e_type != ET_EXEC) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Library not ET_EXEC (type=" << (uint64_t)hdr->e_type << ")";
Memory::g_heap->Free(fileData);
return 0;
}
if (hdr->e_machine != EM_X86_64) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Not x86_64 (machine=" << (uint64_t)hdr->e_machine << ")";
Memory::g_heap->Free(fileData);
return 0;
}
// Calculate library base for this slot (each slot gets LIB_MAX_SIZE region)
uint64_t libBase = LIB_BASE + (uint64_t(slot) * LIB_MAX_SIZE);
// Process program headers
for (uint16_t i = 0; i < hdr->e_phnum; i++) {
Elf64ProgramHeader* phdr = (Elf64ProgramHeader*)(fileData + hdr->e_phoff + i * hdr->e_phentsize);
if (phdr->p_type != PT_LOAD) {
continue;
}
if (phdr->p_memsz == 0) {
continue;
}
// The library is linked at 0x400000. We need to relocate it to libBase.
// target_vaddr = libBase + (file_vaddr - 0x400000)
uint64_t targetSegStart = libBase + (phdr->p_vaddr - 0x400000ULL);
uint64_t targetSegFileEnd = targetSegStart + phdr->p_filesz; // only file data
uint64_t targetSegMemEnd = targetSegStart + phdr->p_memsz; // includes bss
// Align segment start down, segment end up to page boundaries
uint64_t pageSegStart = targetSegStart & ~0xFFFULL;
uint64_t pageSegEnd = (targetSegMemEnd + 0xFFFULL) & ~0xFFFULL;
uint64_t numPages = (pageSegEnd - pageSegStart) / 0x1000;
for (uint64_t p = 0; p < numPages; p++) {
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Out of physical pages";
Memory::g_heap->Free(fileData);
return 0;
}
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
uint64_t pageStart = pageSegStart + p * 0x1000;
uint64_t pageEnd = pageStart + 0x1000;
// Check that we're within the library region
if (pageStart < libBase || pageEnd > libBase + LIB_MAX_SIZE) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Segment outside library region";
Memory::g_heap->Free(fileData);
return 0;
}
if (!Memory::VMM::Paging::MapUserIn(pml4Phys, physAddr, pageStart)) {
Kt::KernelLogStream(Kt::ERROR, "ELF") << "Failed to map page";
Memory::g_heap->Free(fileData);
return 0;
}
// Calculate overlap between this page and the file-data portion of the segment
uint64_t copyStart = (pageStart > targetSegStart) ? pageStart : targetSegStart;
uint64_t copyEnd = (pageEnd < targetSegFileEnd) ? pageEnd : targetSegFileEnd;
if (copyStart < copyEnd) {
// Source: file data at (copyStart - targetSegStart) offset from p_offset
uint64_t srcOffset = phdr->p_offset + (copyStart - targetSegStart);
// Dest: page at (copyStart - pageStart) offset
uint64_t dstOffset = copyStart - pageStart;
uint64_t copySize = copyEnd - copyStart;
uint8_t* dst = (uint8_t*)Memory::HHDM(physAddr) + dstOffset;
uint8_t* src = fileData + srcOffset;
memcpy(dst, src, copySize);
}
}
}
Memory::g_heap->Free(fileData);
// Return the library base address for this slot
return libBase;
}
}