Allow emitting native code into preallocated buffer

This commit is contained in:
Dmitry Stogov 2022-06-10 11:30:19 +03:00
parent 5cafe50d36
commit af4558e439
8 changed files with 65 additions and 30 deletions

3
ir.c
View File

@ -306,6 +306,9 @@ void ir_init(ir_ctx *ctx, ir_ref consts_limit, ir_ref insns_limit)
ctx->prev_insn_len = NULL;
ctx->data = NULL;
ctx->code_buffer = NULL;
ctx->code_buffer_size = 0;
ir_strtab_init(&ctx->strtab, 64, 4096);
buf = ir_mem_malloc((consts_limit + insns_limit) * sizeof(ir_insn));

3
ir.h
View File

@ -439,6 +439,8 @@ typedef struct _ir_ctx {
void *data;
uint32_t rodata_offset;
uint32_t jmp_table_offset;
void *code_buffer;
size_t code_buffer_size;
ir_strtab strtab;
ir_ref prev_insn_chain[IR_LAST_FOLDABLE_OP + 1];
ir_ref prev_const_chain[IR_LAST_TYPE];
@ -550,6 +552,7 @@ void ir_disasm_add_symbol(const char *name, uint64_t addr, uint64_t size);
int ir_disasm(const char *name,
const void *start,
size_t size,
bool asm_addr,
uint32_t rodata_offset,
uint32_t jmp_table_offset,
FILE *f);

View File

@ -4188,7 +4188,7 @@ static void ir_calc_stack_frame_size(ir_ctx *ctx, ir_backend_data *data)
static void* dasm_labels[ir_lb_MAX];
void *ir_emit_code(ir_ctx *ctx, size_t *size)
void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
{
int b, n, target;
ir_block *bb;
@ -4199,6 +4199,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
dasm_State **Dst;
int ret;
void *entry;
size_t size;
ctx->data = &data;
data.ra_data.stack_frame_size = 0;
@ -4468,14 +4469,23 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
|.code
}
ret = dasm_link(&data.dasm_state, size);
ret = dasm_link(&data.dasm_state, size_ptr);
if (ret != DASM_S_OK) {
IR_ASSERT(0);
return NULL;
}
size = *size_ptr;
entry = ir_mem_mmap(4096);
ir_mem_unprotect(entry, 4096);
if (ctx->code_buffer != NULL) {
if (IR_ALIGNED_SIZE(size, 16) > ctx->code_buffer_size) {
return NULL;
}
entry = ctx->code_buffer;
IR_ASSERT((uintptr_t)entry % 16 == 0);
} else {
entry = ir_mem_mmap(size);
}
ir_mem_unprotect(entry, size);
ret = dasm_encode(&data.dasm_state, entry);
@ -4494,13 +4504,15 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
if (ret != DASM_S_OK) {
IR_ASSERT(0);
ir_mem_unmap(entry, 4096);
if (ctx->code_buffer == NULL) {
ir_mem_unmap(entry, size);
}
return NULL;
}
dasm_free(&data.dasm_state);
ir_mem_flush(entry, 4096);
ir_mem_protect(entry, 4096);
ir_mem_flush(entry, size);
ir_mem_protect(entry, size);
return entry;
}

View File

@ -458,6 +458,7 @@ static void ir_addrtab_sort(ir_addrtab *addrtab)
int ir_disasm(const char *name,
const void *start,
size_t size,
bool asm_addr,
uint32_t rodata_offset,
uint32_t jmp_table_offset,
FILE *f)
@ -579,7 +580,7 @@ int ir_disasm(const char *name,
}
# ifdef HAVE_CAPSTONE_ITER
if (0) {
if (asm_addr) {
fprintf(f, " %" PRIx64 ":", insn->address);
}
p = insn->op_str;
@ -590,7 +591,7 @@ int ir_disasm(const char *name,
fprintf(f, "\t%s ", insn->mnemonic);
}
# else
if (0) {
if (asm_addr) {
fprintf(f, " %" PRIx64 ":", insn[i].address);
}
p = insn[i].op_str;

View File

@ -620,12 +620,6 @@ int ir_gdb_register(const char *name,
return ir_gdb_register_code(&ctx.obj, ctx.objsize);
}
int ir_gdb_unregister(void)
{
ir_gdb_unregister_all();
return 1;
}
void ir_gdb_init(void)
{
/* This might enable registration of all JIT-ed code, but unfortunately,

View File

@ -389,7 +389,7 @@ int main(int argc, char **argv)
if (entry) {
if (dump_asm) {
ir_disasm_add_symbol("test", (uintptr_t)entry, size);
ir_disasm("test", entry, size, ctx.rodata_offset, ctx.jmp_table_offset, stderr);
ir_disasm("test", entry, size, 0, ctx.rodata_offset, ctx.jmp_table_offset, stderr);
}
if (run) {
int (*func)(void) = entry;

View File

@ -208,7 +208,7 @@ int main(int argc, char **argv)
void *entry = ir_emit_code(&ctx, &size);
if (entry) {
ir_disasm("test", entry, size, ctx.rodata_offset, ctx.jmp_table_offset, stderr);
ir_disasm("test", entry, size, 0, ctx.rodata_offset, ctx.jmp_table_offset, stderr);
ir_perf_map_register("test", entry, size);
ir_perf_jitdump_open();

View File

@ -213,7 +213,7 @@
|.macro ASM_REG_MREF_OP, _op, type, dst, src
|| if (IR_IS_CONST_REF(src)) {
|| ir_insn *_insn = &ctx->ir_base[src];
|| IR_ASSERT(IR_IS_SIGNED_32BIT(_insn->val.i64));
|| IR_ASSERT(IR_IS_32BIT(_insn->type, _insn->val));
| ASM_REG_IMM_OP _op, type, dst, _insn->val.i32
|| } else {
|| int32_t offset = ir_ref_spill_slot(ctx, src);
@ -295,7 +295,7 @@
|.macro ASM_REG_MREF_IMUL, type, dst, src
|| if (IR_IS_CONST_REF(src)) {
|| ir_insn *_insn = &ctx->ir_base[src];
|| IR_ASSERT(IR_IS_SIGNED_32BIT(_insn->val.i64));
|| IR_ASSERT(IR_IS_32BIT(_insn->type, _insn->val));
| ASM_REG_IMM_IMUL type, dst, _insn->val.i32
|| } else {
|| int32_t offset = ir_ref_spill_slot(ctx, src);
@ -4976,11 +4976,16 @@ static void ir_emit_call(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} else {
addr = (void*)addr_insn->val.addr;
}
if (sizeof(void*) == 4 /*|| IR_IS_SIGNED_32BIT(addr)*/) { // TODO: 32-bit IP relative or 64-bit absolute address
if (sizeof(void*) == 4 || (ctx->code_buffer_size
&& IR_IS_SIGNED_32BIT((char*)addr - (char*)ctx->code_buffer_size))) {
| call aword &addr
} else {
|.if X64
| mov64 rax, ((ptrdiff_t)addr) // 0x48 0xb8 <imm-64-bit>
if (IR_IS_SIGNED_32BIT(addr)) {
| mov rax, ((ptrdiff_t)addr) // 0x48 0xc7 0xc0 <imm-32-bit>
} else {
| mov64 rax, ((ptrdiff_t)addr) // 0x48 0xb8 <imm-64-bit>
}
| call rax
|.endif
}
@ -5062,11 +5067,16 @@ static void ir_emit_tailcall(ir_ctx *ctx, ir_ref def, ir_insn *insn)
} else {
addr = (void*)addr_insn->val.addr;
}
if (sizeof(void*) == 4 /*|| IR_IS_SIGNED_32BIT(addr)*/) { // TODO: 32-bit IP relative or 64-bit absolute address
if (sizeof(void*) == 4 || (ctx->code_buffer_size
&& IR_IS_SIGNED_32BIT((char*)addr - (char*)ctx->code_buffer_size))) {
| jmp aword &addr
} else {
|.if X64
| mov64 rax, ((ptrdiff_t)addr) // 0x48 0xb8 <imm-64-bit>
if (IR_IS_SIGNED_32BIT(addr)) {
| mov rax, ((ptrdiff_t)addr) // 0x48 0xc7 0xc0 <imm-32-bit>
} else {
| mov64 rax, ((ptrdiff_t)addr) // 0x48 0xb8 <imm-64-bit>
}
| jmp rax
|.endif
}
@ -5938,7 +5948,7 @@ static void ir_calc_stack_frame_size(ir_ctx *ctx, ir_backend_data *data)
static void* dasm_labels[ir_lb_MAX];
void *ir_emit_code(ir_ctx *ctx, size_t *size)
void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
{
int b, n, target;
ir_block *bb;
@ -5949,6 +5959,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
dasm_State **Dst;
int ret;
void *entry;
size_t size;
ctx->data = &data;
data.ra_data.stack_frame_size = 0;
@ -6503,14 +6514,23 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
|.code
}
ret = dasm_link(&data.dasm_state, size);
ret = dasm_link(&data.dasm_state, size_ptr);
if (ret != DASM_S_OK) {
IR_ASSERT(0);
return NULL;
}
size = *size_ptr;
entry = ir_mem_mmap(4096);
ir_mem_unprotect(entry, 4096);
if (ctx->code_buffer != NULL) {
if (IR_ALIGNED_SIZE(size, 16) > ctx->code_buffer_size) {
return NULL;
}
entry = ctx->code_buffer;
IR_ASSERT((uintptr_t)entry % 16 == 0);
} else {
entry = ir_mem_mmap(size);
}
ir_mem_unprotect(entry, size);
ret = dasm_encode(&data.dasm_state, entry);
@ -6529,13 +6549,15 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size)
if (ret != DASM_S_OK) {
IR_ASSERT(0);
ir_mem_unmap(entry, 4096);
if (ctx->code_buffer == NULL) {
ir_mem_unmap(entry, size);
}
return NULL;
}
dasm_free(&data.dasm_state);
ir_mem_flush(entry, 4096);
ir_mem_protect(entry, 4096);
ir_mem_flush(entry, size);
ir_mem_protect(entry, size);
return entry;
}