bd-jb/src/com/bdjb/jit/AbstractJit.java

115 lines
3.1 KiB
Java

/*
* Copyright (C) 2021 Andy Nguyen
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
package com.bdjb.jit;
import com.bdjb.api.API;
import java.io.RandomAccessFile;
abstract class AbstractJit {
public static final int PROT_NONE = 0x0;
public static final int PROT_READ = 0x1;
public static final int PROT_WRITE = 0x2;
public static final int PROT_EXEC = 0x4;
public static final int MAP_SHARED = 0x1;
public static final int MAP_PRIVATE = 0x2;
public static final int MAP_FIXED = 0x10;
public static final int MAP_ANONYMOUS = 0x1000;
public static final long MAP_FAILED = -1;
public static final int PAGE_SIZE = 0x4000;
public static final int ALIGNMENT = 0x100000;
protected static final int CHUNK_SIZE = 0x30;
protected static final API api;
private static final String MMAP_SYMBOL = "mmap";
static {
try {
api = API.getInstance();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
protected long mmap;
protected AbstractJit() {
mmap = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, MMAP_SYMBOL);
if (mmap == 0) {
throw new InternalError("symbols not found");
}
}
protected long mmap(long addr, long len, int prot, int flags, int fd, long offset) {
return api.call(mmap, addr, len, prot, flags, fd, offset);
}
protected long align(long x, long align) {
return (x + align - 1) & ~(align - 1);
}
protected abstract long jitMap(long size, long alignment);
protected abstract void jitCopy(long dest, byte[] src, long n);
public long mapPayload(String path, long dataSectionOffset) throws Exception {
RandomAccessFile file = new RandomAccessFile(path, "r");
if ((dataSectionOffset & (PAGE_SIZE - 1)) != 0) {
throw new IllegalArgumentException("unaligned data section offset");
}
if (dataSectionOffset < 0 || dataSectionOffset > file.length()) {
throw new IllegalArgumentException("invalid data section offset");
}
// Allocate JIT memory.
long address = jitMap(file.length(), ALIGNMENT);
byte[] chunk = new byte[CHUNK_SIZE];
// Copy .text section.
for (long i = 0; i < dataSectionOffset; i += chunk.length) {
api.memset(chunk, 0, chunk.length);
file.seek(i);
int read = file.read(chunk, 0, (int) Math.min(dataSectionOffset - i, chunk.length));
jitCopy(address + i, chunk, read);
}
// Map the .data section as RW.
if (mmap(
address + dataSectionOffset,
align(file.length() - dataSectionOffset, PAGE_SIZE),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS,
-1,
0)
== MAP_FAILED) {
throw new InternalError("mmap failed");
}
// Copy .data section.
for (long i = dataSectionOffset; i < file.length(); i += chunk.length) {
api.memset(chunk, 0, chunk.length);
file.seek(i);
int read = file.read(chunk, 0, (int) Math.min(file.length() - i, chunk.length));
api.memcpy(address + i, chunk, read);
}
return address;
}
}