Skip to content

Commit

Permalink
Add -runtime-code-size option to reserve a region for JIT code
Browse files Browse the repository at this point in the history
  • Loading branch information
titzer committed Sep 10, 2024
1 parent 63d0b81 commit 98633de
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 1 deletion.
1 change: 1 addition & 0 deletions aeneas/src/exe/ELF.v3
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ component ElfConst {
def PF_X = 0x1;
def PF_RX = 0x5;
def PF_RW = 0x6;
def PF_RWX = 0x7;
// constants for ei_ident[EI_CLASS]
def ELFCLASS32 = 1;
def ELFCLASS64 = 2;
Expand Down
2 changes: 2 additions & 0 deletions aeneas/src/mach/CiRuntime.v3
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ component CiRuntimeModule {
def STACK_END = addr("STACK_END");
def RESERVED_CODE_START = addr("RESERVED_CODE_START");
def RESERVED_CODE_END = addr("RESERVED_CODE_END");
def RUNTIME_CODE_START = addr("RUNTIME_CODE_START");
def RUNTIME_CODE_END = addr("RUNTIME_CODE_END");
def RESERVED_CODE_FILE_OFFSET = addr("RESERVED_CODE_FILE_OFFSET"); // TODO: technically not a pointer
// machine code stub for handling signals
def SIGNAL_STUB = addr("signalStub");
Expand Down
4 changes: 4 additions & 0 deletions aeneas/src/mach/MachRuntime.v3
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class MachRuntime(mach: MachProgram) {
recordAddr(CiRuntimeModule.RESERVED_CODE_END, startAddr + size);
recordAddr(CiRuntimeModule.RESERVED_CODE_FILE_OFFSET, fileOffset);
}
def recordRuntimeCode(startAddr: int, size: int) {
recordAddr(CiRuntimeModule.RUNTIME_CODE_START, startAddr);
recordAddr(CiRuntimeModule.RUNTIME_CODE_END, startAddr + size);
}
def recordCodeEnd(addr: int) {
recordAddr(CiRuntimeModule.CODE_END, addr);
}
Expand Down
2 changes: 2 additions & 0 deletions aeneas/src/main/CLOptions.v3
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ component CLOptions {
"Set the stack size of the compiled program, enabling robust stack overflow checking.");
def RESERVED_CODE_SIZE = wasmOpt.newSizeOption("reserved-code-size", 0,
"Set the reserved code size of the compiled program for supplemental code post-compilation.");
def RUNTIME_CODE_SIZE = wasmOpt.newSizeOption("runtime-code-size", 0,
"Set the size of runtime code region to support dynamic code generation.");
def VM_START_ADDR = rtOpt.newAddrOption("vm-start-addr", 0x08000000,
"Set the virtual memory start of all program segments.");
def CODE_START_ADDR = rtOpt.newAddrOption("code-start-addr", 0,
Expand Down
23 changes: 22 additions & 1 deletion aeneas/src/os/Linux.v3
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ class LinuxTarget extends Target {
data.p_memsz = pageAlign.size;
data.p_flags = ElfConst.PF_RW;

// reserve a region for runtime code if necessary.
var runtimeCodeSize = pageAlign.alignUp(int.!(CLOptions.RUNTIME_CODE_SIZE.get())); // runtime code region size
var rtexe = if(runtimeCodeSize > 0, elf.addProgramHeader());

// skip over ELF header
w.skipN(int.!(elf.size()));

// emit code
Expand All @@ -130,6 +135,22 @@ class LinuxTarget extends Target {
rt.recordCodeEnd(w.endAddr());

mach.reserveSupplementalCode(w); // TODO: add .reserved_code symbol

if (rtexe != null) {
// TODO: add .runtime_code symbol
var startAddr = pageAlign.alignUp(w.endAddr());
rt.recordRuntimeCode(startAddr, runtimeCodeSize);
rtexe.p_type = ElfConst.PT_LOAD;
rtexe.p_filesz = 1; // file size cannot be zero, apparently
rtexe.p_vaddr = startAddr;
rtexe.p_memsz = runtimeCodeSize;
rtexe.p_flags = ElfConst.PF_RWX;
w.skipN(1);
w.startAddr += runtimeCodeSize;
} else {
rt.recordRuntimeCode(0, 0);
}

mach.layoutMeta(w);
mach.layoutRuntime(w);
code.p_filesz = w.end();
Expand All @@ -141,7 +162,7 @@ class LinuxTarget extends Target {
w.skipPage();
var exStart = w.endPageAddr();
var exSize = pageAlign.alignUp(rt.src.layoutExRegion(exStart));
w.startAddr = w.startAddr + exSize;
w.startAddr += exSize;
ex.p_vaddr = exStart;
ex.p_memsz = exSize;
ex.p_filesz = 0;
Expand Down
99 changes: 99 additions & 0 deletions test/rt/runtime_code.v3
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
def RUNTIME_CODE_SIZE = 4096;

var result = 0;

def main(args: Array<string>) -> int {
begin("code size check");
checkCodeSize();

begin("generating code");
generateCode();

begin("checking code");
checkCode();

begin("running code");
runCode();

return result;
}

def checkCodeSize() {
var gotSize = int.!(CiRuntime.RUNTIME_CODE_END - CiRuntime.RUNTIME_CODE_START);
if (RUNTIME_CODE_SIZE == gotSize) ok();
else return fail("size does not match");
}

def generateCode() {
var region = getRuntimeCodeRegion();
var expected = getMachineCode();
for (i < expected.length) {
region[i] = expected[i];
}
ok();
}

def checkCode() {
var region = getRuntimeCodeRegion();
var expected = getMachineCode();
if (region.length == 0) return fail("no reserved code region");
if (region.length < expected.length) return fail("reserved code region too small");
for (i < expected.length) {
if (region[i] != expected[i]) return fail("machine code does not match expectation");
}
ok();
}

def runCode() {
var codePtr = CiRuntime.RUNTIME_CODE_START;
var f: void -> int = CiRuntime.forgeClosure<void, void, int>(codePtr, ());
var got = f();
if (got == 42) ok();
else fail("got wrong value");
}

def begin(str1: string) {
System.puts("##+");
System.puts(str1);
System.ln();
}

def ok() {
System.puts("##-ok\n");
}

def fail(msg: string) {
System.puts("##-fail: ");
if (msg != null) System.puts(msg);
System.ln();
result |= 1;
}

def getRuntimeCodeRegion() -> Range<byte> {
return CiRuntime.forgeRange<byte>(CiRuntime.RUNTIME_CODE_START,
int.!(CiRuntime.RUNTIME_CODE_END - CiRuntime.RUNTIME_CODE_START));
}

//==========================================================================================
//== Target-specific configuration =========================================================
//==========================================================================================

// Retarget this test by passing -redef-field=TARGET_<target>=true
def TARGET_x86_linux = false;
def TARGET_x86_darwin = false;
def TARGET_x86_64_linux = false;
def TARGET_x86_64_darwin = false;

def TARGET_x86 = TARGET_x86_linux || TARGET_x86_darwin;
def TARGET_x86_64 = TARGET_x86_64_linux || TARGET_x86_64_darwin;

def X86_CODE: Array<byte> = [
0xB8, 0x2A, 0x00, 0x00, 0x00, // mov eax, 42
0xc3 // ret
];

def getMachineCode() -> Array<byte> {
if (TARGET_x86 || TARGET_x86_64) return X86_CODE;
var x = 1/0;
return null; // no other targets supported now
}
1 change: 1 addition & 0 deletions test/rt/runtime_code.v3.exit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0
1 change: 1 addition & 0 deletions test/rt/runtime_code.v3.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
1 change: 1 addition & 0 deletions test/rt/runtime_code.v3.flags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-runtime-code-size=4K

0 comments on commit 98633de

Please sign in to comment.