This defines required information such as the type of architecture (Support checker) and where the process entry is for starting it. Also the offsets of the Program headers
This is very important as it describes the sections of the program that are needed to be loaded into memory (vaddr) and where about they are in the elf file (paddr) and the specific sizes.
The type is the important factor in understanding this. There are 3 main types for this.
#definePT_NULL0 // Ignore#definePT_LOAD1 // Defines that it needs to be loaded into memory// GNU#definePT_GNU_STACK0x6474E551 // Defines the requirement of no execute bit or not.
Loading
In order to load the ELF, I use two loops. One loop is in order to allocate all the memory using the Program Headers. (We do this as if we did it while we load some memory issues occur as some memory isn't allocated.)
{for (uint16_t i =0; i <elfHdr.phNum; i++) { ELF64ProgramHeader elfPHdr =*((ELF64ProgramHeader*)(elf +elfHdr.phOff + i *elfHdr.phEntrySize));if(elfPHdr.memSize ==0||elfPHdr.type != PT_LOAD) continue;else { // Load the data anywaysuint64_t size_alligned_down =elfPHdr.memSize + (elfPHdr.vaddr & PAGE_SIZE_4K); // Calculate page countuint64_t pages = (size_alligned_down + PAGE_SIZE_4K -1) / PAGE_SIZE_4K; // Calculate VAddruint64_t virtAddress = base +elfPHdr.vaddr - (elfPHdr.vaddr &0xFFF); // Remove end bytessize_t flags =0; flags |= (size_t)PAGE_PRESENT; flags |= (size_t)PAGE_USER; flags |= (size_t)PAGE_WRITABLE; // Allocate the region Drivers::Video::Print("ELF Allocator: Allocaing range of %x to %x\n", virtAddress, virtAddress + pages * PAGE_SIZE_4K); Paging::Region* r =proc->allocator->AllocateMemory(pages * PAGE_SIZE_4K, virtAddress,true,true, flags); } }}
And the other stage is actually loading the data into memory, and to check if we need the No execute. We also use it to check if the process is static or dynamic and so if we need to load the linker as well for library loading.
{ // DATA Loaderfor (uint16_t i =0; i <elfHdr.phNum; i++) { ELF64ProgramHeader elfPHdr =*((ELF64ProgramHeader*)(elf +elfHdr.phOff + i *elfHdr.phEntrySize)); Drivers::Video::Print("Program header: type=%x, offset=%x filesz=%x, memsz=%x\n",elfPHdr.type,elfPHdr.offset,elfPHdr.fileSize,elfPHdr.memSize);if(elfPHdr.memSize ==0) Drivers::Video::Print(" ! Empty PHdr\n");else { // Load the data anyways // Calculate sizeuint64_t size_alligned_down =elfPHdr.memSize + (elfPHdr.vaddr & PAGE_SIZE_4K); // Calculate page countuint64_t pages = (size_alligned_down + PAGE_SIZE_4K -1) / PAGE_SIZE_4K; // Loadinguint64_t virtAddress = base +elfPHdr.vaddr - (elfPHdr.vaddr &0xFFF); // Remove end bytesuint64_t offset =elfPHdr.vaddr &0xFFF; // Calculate its offset into the allocated memory Drivers::Video::Print("Memcpy data from %x into %x of size %x\n", elf +elfPHdr.offset, (uint8_t*)(virtAddress + offset),elfPHdr.fileSize);asmvolatile("cli; mov %%rax, %%cr3"::"a"(proc->GetPageMap()->pml4Phys) :"memory");memcpy((uint8_t*)(virtAddress + offset), elf +elfPHdr.offset,elfPHdr.fileSize);asmvolatile("mov %%rax, %%cr3; sti"::"a"(pml4Phys) :"memory"); Drivers::Video::Print(" Loaded program header (%x Bytes) at offset %x into %x\n",elfPHdr.fileSize,elfPHdr.offset, base +elfPHdr.vaddr); }if (elfPHdr.type == PT_PHDR) { Drivers::Video::Print(" ! PHDR found, saving address: %x!\n",elfPHdr.vaddr);elfInfo.pHdrSegment = base +elfPHdr.vaddr; }elseif (elfPHdr.type == PT_GNU_STACK){ Drivers::Video::Print(" ! Stack permission set by GNU_STACK Program header!: %Y\n",!(elfPHdr.flags & PF_X));if (!(elfPHdr.flags & PF_X)) stack_flags |= PAGE_NX; } elseif (elfPHdr.type == PT_INTERP) { // Linker location linkPath = (char*)Memory::Heap::malloc(elfPHdr.fileSize +1);strncpy(linkPath, (char*)(elf +elfPHdr.offset),elfPHdr.fileSize);linkPath[elfPHdr.fileSize] =0; // Null terminate the pathelfInfo.linkerPath = linkPath; Drivers::Video::Print(" ! Linker path found: %s!\n", linkPath); } }}