feat: extend elf with elfSegmentPagingFlags and elfSlotBase
This commit is contained in:
1 parent
f0b99bc99a
commit
b6fbdb51aa
1 file changed
+89
-1
@@ -7,6 +7,15 @@
|
|||||||
#define elfTypeExec 2
|
#define elfTypeExec 2
|
||||||
#define elfMachineX8664 62
|
#define elfMachineX8664 62
|
||||||
|
|
||||||
|
/* Standard ELF64 Elf64ProgramHeader.flags bits (p_flags) -- PF_X/PF_W/PF_R
|
||||||
|
by their real numeric values, not this kernel's own invention. PF_R is
|
||||||
|
never consulted below: every mapping pagingMapUserRangeExact creates is
|
||||||
|
already readable by virtue of pageUser alone (x86_64 has no separate
|
||||||
|
read-disable outside SMAP/PKU, neither of which this kernel uses), so a
|
||||||
|
segment missing PF_R would be indistinguishable from one that has it. */
|
||||||
|
#define elfFlagExecute 1
|
||||||
|
#define elfFlagWrite 2
|
||||||
|
|
||||||
static bool validHeader(const Elf64Header* header)
|
static bool validHeader(const Elf64Header* header)
|
||||||
{
|
{
|
||||||
if (header->ident[0] != 0x7F || header->ident[1] != 'E' ||
|
if (header->ident[0] != 0x7F || header->ident[1] != 'E' ||
|
||||||
@@ -21,6 +30,26 @@ static bool validHeader(const Elf64Header* header)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Translates one ELF64 program header's own p_flags into the extra
|
||||||
|
paging.h leaf-PTE bits pagingMapUserRangeExact needs to map that exact
|
||||||
|
segment with real per-segment W^X: writable iff PF_W was set, and
|
||||||
|
pageNoExecute UNLESS PF_X was set (never both writable and executable
|
||||||
|
at once for a segment that asked for neither, or for one that asked
|
||||||
|
for only PF_W -- data/bss segments -- which is the whole point).
|
||||||
|
Pulled out as its own pure function, no paging/scheduler/VFS involved,
|
||||||
|
so elfTest.c can exercise every PF_X/PF_W combination deterministically
|
||||||
|
before the scheduler even starts, the same way this file's other pure
|
||||||
|
address-arithmetic helpers (elfSlotBase and friends) already are. */
|
||||||
|
uint64 elfSegmentPagingFlags(uint32 segmentFlags)
|
||||||
|
{
|
||||||
|
uint64 flags = 0;
|
||||||
|
if (segmentFlags & elfFlagWrite)
|
||||||
|
flags |= pageWrite;
|
||||||
|
if (!(segmentFlags & elfFlagExecute))
|
||||||
|
flags |= pageNoExecute;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
uint64 elfLoad(const void* image, uint64 imageSize)
|
uint64 elfLoad(const void* image, uint64 imageSize)
|
||||||
{
|
{
|
||||||
const Elf64Header* header = (const Elf64Header*)image;
|
const Elf64Header* header = (const Elf64Header*)image;
|
||||||
@@ -39,7 +68,8 @@ uint64 elfLoad(const void* image, uint64 imageSize)
|
|||||||
if (segment->type != programTypeLoad)
|
if (segment->type != programTypeLoad)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!pagingMapUserRange(segment->virtualAddr, segment->memorySize)) {
|
uint64 mapFlags = elfSegmentPagingFlags(segment->flags);
|
||||||
|
if (!pagingMapUserRangeExact(segment->virtualAddr, segment->memorySize, mapFlags)) {
|
||||||
kprintf("[elf] failed to map segment at %p\n", (void*)segment->virtualAddr);
|
kprintf("[elf] failed to map segment at %p\n", (void*)segment->virtualAddr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -49,3 +79,61 @@ uint64 elfLoad(const void* image, uint64 imageSize)
|
|||||||
|
|
||||||
return header->entry;
|
return header->entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64 elfSlotBase(uint64 entry)
|
||||||
|
{
|
||||||
|
return entry & ~(elfSlotSize - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 elfSlotStackTop(uint64 entry)
|
||||||
|
{
|
||||||
|
return elfSlotBase(entry) + elfSlotStackOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 elfSlotBrkStart(uint64 entry)
|
||||||
|
{
|
||||||
|
return elfSlotBase(entry) + elfSlotBrkOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool elfBuildInitialStack(uint64 stackTop, uint64 stackSize, const char* const* argv,
|
||||||
|
int argc, uint64* outRsp)
|
||||||
|
{
|
||||||
|
if (argc < 0 || argc > elfMaxArgs)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint64 stackBottom = stackTop - stackSize;
|
||||||
|
uint64 argvAddr[elfMaxArgs];
|
||||||
|
uint64 cursor = stackTop;
|
||||||
|
|
||||||
|
/* Strings first, growing downward from the top of the stack -- each
|
||||||
|
one's address is remembered so the pointer array below can point at
|
||||||
|
it once every string is placed. */
|
||||||
|
for (int i = argc - 1; i >= 0; i--) {
|
||||||
|
uint64 len = strlen(argv[i]) + 1;
|
||||||
|
if (cursor - stackBottom < len)
|
||||||
|
return false;
|
||||||
|
cursor -= len;
|
||||||
|
memcpy((void*)cursor, argv[i], len);
|
||||||
|
argvAddr[i] = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* argc slot + argv[0..argc-1] + a NULL terminator, SysV-style. Rounded
|
||||||
|
down to 16 bytes because that is where _start (crt.S) expects rsp to
|
||||||
|
sit at process entry (so that its own later `call main` leaves main
|
||||||
|
looking at the usual post-call rsp%16==8). */
|
||||||
|
uint64 fixedAreaBytes = (uint64)(argc + 2) * sizeof(uint64);
|
||||||
|
if (cursor - stackBottom < fixedAreaBytes)
|
||||||
|
return false;
|
||||||
|
uint64 base = (cursor - fixedAreaBytes) & ~15ull;
|
||||||
|
if (base < stackBottom)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint64* slots = (uint64*)base;
|
||||||
|
slots[0] = (uint64)argc;
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
slots[1 + i] = argvAddr[i];
|
||||||
|
slots[1 + argc] = 0;
|
||||||
|
|
||||||
|
*outRsp = base;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user