Last active
November 23, 2021 10:43
-
-
Save Glavo/aabbac7f206c56beeacd711c4726e260 to your computer and use it in GitHub Desktop.
PanamaJIT Demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import jdk.incubator.foreign.*; | |
import java.lang.invoke.*; | |
// Original code (C++): https://stackoverflow.com/a/40937610/7659948 | |
public class PanamaJIT { | |
public static final int MEM_COMMIT = 0x00001000; | |
public static final int PAGE_READWRITE = 0x04; | |
public static final int PAGE_EXECUTE_READ = 0x20; | |
public static final int PAGE_SIZE = 4096; | |
private static final MethodHandle virtualAllocHandle; | |
private static final MethodHandle virtualProtectHandle; | |
static { | |
System.loadLibrary("Kernel32"); | |
virtualAllocHandle = CLinker.getInstance().downcallHandle( | |
SymbolLookup.loaderLookup().lookup("VirtualAlloc").orElseThrow(UnsatisfiedLinkError::new), | |
MethodType.methodType(MemoryAddress.class, MemoryAddress.class, long.class, int.class, int.class), | |
FunctionDescriptor.of(CLinker.C_POINTER, CLinker.C_POINTER, CLinker.C_LONG_LONG, CLinker.C_LONG, CLinker.C_LONG) | |
); | |
virtualProtectHandle = CLinker.getInstance().downcallHandle( | |
SymbolLookup.loaderLookup().lookup("VirtualProtect").orElseThrow(UnsatisfiedLinkError::new), | |
MethodType.methodType(int.class, MemoryAddress.class, long.class, int.class, MemoryAddress.class), | |
FunctionDescriptor.of(CLinker.C_INT, CLinker.C_POINTER, CLinker.C_LONG_LONG, CLinker.C_LONG, CLinker.C_POINTER) | |
); | |
} | |
public static MemoryAddress VirtualAlloc(MemoryAddress lpAddress, long dwSize, int flAllocationType, int flProtect) { | |
try { | |
return (MemoryAddress) virtualAllocHandle.invokeExact(lpAddress, dwSize, flAllocationType, flProtect); | |
} catch (Throwable e) { | |
throw new AssertionError(e); | |
} | |
} | |
public static boolean VirtualProtect(MemoryAddress lpAddress, long dwSize, int flNewProtect, MemoryAddress lpflOldProtect) { | |
try { | |
return (int) virtualProtectHandle.invokeExact(lpAddress, dwSize, flNewProtect, lpflOldProtect) != 0; | |
} catch (Throwable e) { | |
throw new AssertionError(e); | |
} | |
} | |
/* | |
* Return: () -> value | |
*/ | |
private static byte[] compile(int value) { | |
/* | |
* movl $value, %eax | |
* retq | |
*/ | |
return new byte[]{ | |
(byte) 0xb8, | |
(byte) (value), (byte) (value >>> 8), (byte) (value >>> 16), (byte) (value >>> 24), | |
(byte) 0xc3 | |
}; | |
} | |
public static void main(String[] args) throws Throwable { | |
byte[] code = compile(Integer.parseInt(args[0])); | |
MemoryAddress buffer = VirtualAlloc(MemoryAddress.NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE); | |
buffer.asSegment(code.length, ResourceScope.globalScope()).copyFrom(MemorySegment.ofArray(code)); | |
MemoryAddress dummy = CLinker.allocateMemory(4); | |
VirtualProtect(buffer, code.length, PAGE_EXECUTE_READ, dummy); | |
MethodHandle functionPtr = CLinker.getInstance().downcallHandle( | |
buffer, | |
MethodType.methodType(int.class), | |
FunctionDescriptor.of(CLinker.C_INT) | |
); | |
int result = (int) functionPtr.invokeExact(); | |
assert result == Integer.parseInt(args[0]); | |
System.out.println("Result: " + result); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Platform: Windows AMD64, Java 17
Use
java --add-modules jdk.incubator.foreign --enable-native-access=ALL-UNNAMED PanamaJIT.java <any integer>
to run it.