void *jitcode(dasm_State **state) { size_t size; int dasm_status = dasm_link(state, &size); assert(dasm_status == DASM_S_OK); // Allocate memory readable and writable so we can // write the encoded instructions there. char *mem = malloc(size + sizeof(size_t)); assert(mem != NULL); // Store length at the beginning of the region, so we // can free it without additional context. *(size_t *) mem = size; void *ret = mem + sizeof(size_t); dasm_encode(state, ret); dasm_free(state); #ifndef NDEBUG // Write generated machine code to a temporary file. // View with: (x86-64) // objdump -D -b binary -mi386 -Mx86-64 /tmp/jitcode // Or: (arm) // arm-linux-gnueabihf-objdump -D -b binary -marm /tmp/jitcode FILE *f = fopen("jitcode", "wb"); fwrite(ret, size, 1, f); fclose(f); #endif return ret; }
int build_code(Dst_DECL) { int ret = 0; size_t codesz = 0; uint8_t* code = NULL; int nglob = GLOB_MAX; void **glob = (void **)malloc(nglob*sizeof(void *)); memset(glob, 0, nglob*sizeof(void *)); dasm_init(Dst, DASM_MAXSECTION); dasm_setupglobal(Dst, glob, nglob); dasm_setup(Dst, build_actionlist); (void)create_backend(Dst); /* Finalize */ (void)dasm_checkstep(Dst, -1); /* sanity check */ if((ret = dasm_link(Dst, &codesz))) return ret; code = (uint8_t *)pa_malloc(codesz, true); if((ret = dasm_encode(Dst, (void *)code))) return ret; //write_raw("debug.out", code, codesz); dasm_gen_func fp = (dasm_gen_func)code; ret = fp(); printf("generated function return value = %d\n",ret); dasm_free(Dst); free(glob); free(code); return 0; }
static compiled_code_t make_exec(program_t *prog, dasm_State **state) { size_t size; int dasm_status = dasm_link(state, &size); assert(dasm_status == DASM_S_OK); (void) dasm_status; ensure_space(prog, size); /* For performance reasons, we care about page RWX access only in * when asserts are enabled. */ int result = mprotect(prog->codepages, prog->codepages->size, PROT_READ | PROT_WRITE); assert(result == 0); (void) result; compiled_code_t code = (compiled_code_t) prog->begin; prog->begin += size; dasm_encode(state, code); dasm_free(state); result = mprotect(prog->codepages, size, PROT_EXEC | PROT_READ); assert(result == 0); (void) result; return code; }
static cfunction compile(struct jit* jit, lua_State* L, cfunction func, int ref) { struct jit_head* code; size_t codesz; int err; dasm_checkstep(jit, -1); if ((err = dasm_link(jit, &codesz)) != 0) { char buf[32]; sprintf(buf, "%x", err); luaL_error(L, "dasm_link error %s", buf); } codesz += sizeof(struct jit_head); code = (struct jit_head*) reserve_code(jit, L, codesz); code->ref = ref; code->size = codesz; compile_extern_jump(jit, L, func, code->jump); if ((err = dasm_encode(jit, code+1)) != 0) { char buf[32]; sprintf(buf, "%x", err); commit_code(jit, code, 0); luaL_error(L, "dasm_encode error %s", buf); } commit_code(jit, code, codesz); return (cfunction) (code+1); }
static void* link_and_encode(dasm_State**d) { size_t sz; void* buf; dasm_link(d, &sz); buf = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); dasm_encode(d, buf); //dumpcode(buf, sz); mprotect(buf, sz, PROT_READ|PROT_EXEC); return buf; }
static void* _jitcode_new(dasm_State** state){ size_t size; assert(dasm_link(state, &size)==DASM_S_OK); // printf("_jitcode_new size: %zd\n", size); char *mem = (char*)mmap(NULL, size + sizeof(size_t), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); assert(mem != MAP_FAILED); *(size_t*)mem = size; void *ret = mem + sizeof(size_t); dasm_encode(state, ret); assert(mprotect(mem, size, PROT_EXEC | PROT_READ)==0); return ret; }
static void* link_and_encode(dasm_State** d) { size_t sz; void* buf; dasm_link(d, &sz); #ifdef _WIN32 buf = VirtualAlloc(0, sz, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); #else buf = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #endif dasm_encode(d, buf); #ifdef _WIN32 {DWORD dwOld; VirtualProtect(buf, sz, PAGE_EXECUTE_READ, &dwOld); } #else mprotect(buf, sz, PROT_READ | PROT_EXEC); #endif return buf; }
/* Link generated code. Return mcode address, size and status. */ int luaJIT_link(jit_State *J, void **mcodep, size_t *szp) { size_t sz; void *mcode; /* Pass 2: link sections. */ if ((J->dasmstatus = dasm_link(Dst, &sz))) return JIT_S_DASM_ERROR; /* Check for hardcoded limit on mcode size. */ if (sz > LUAJIT_LIM_MCODE) return JIT_S_TOOLARGE; /* TODO: mark mcode readonly when we're done. */ mcode = mcode_alloc(J, sz); /* Pass 3: encode sections. */ if ((J->dasmstatus = dasm_encode(Dst, mcode))) { mcode_free(J->L, J, mcode, sz); return JIT_S_DASM_ERROR; } *mcodep = mcode; *szp = sz; return JIT_S_OK; }
void *jitcode(dasm_State **state) { size_t size; int dasm_status = dasm_link(state, &size); assert(dasm_status == DASM_S_OK); // Allocate memory readable and writable so we can // write the encoded instructions there. char *mem = mmap(NULL, size + sizeof(size_t), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); assert(mem != MAP_FAILED); // Store length at the beginning of the region, so we // can free it without additional context. *(size_t*)mem = size; void *ret = mem + sizeof(size_t); dasm_encode(state, ret); dasm_free(state); // Adjust the memory permissions so it is executable // but no longer writable. int success = mprotect(mem, size, PROT_EXEC | PROT_READ); assert(success == 0); #ifndef NDEBUG // Write generated machine code to a temporary file. // View with: // objdump -D -b binary -mi386 -Mx86-64 /tmp/jitcode FILE *f = fopen("/tmp/jitcode", "wb"); fwrite(ret, size, 1, f); fclose(f); #endif return ret; }
/* Build the machine code. */ static int build_code(BuildCtx *ctx) { int status; int i; /* Initialize DynASM structures. */ ctx->nglob = GLOB__MAX; ctx->glob = (void **)malloc(ctx->nglob*sizeof(void *)); memset(ctx->glob, 0, ctx->nglob*sizeof(void *)); ctx->nreloc = 0; ctx->globnames = globnames; ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *)); ctx->nrelocsym = 0; for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1; ctx->dasm_ident = DASM_IDENT; ctx->dasm_arch = DASM_ARCH; dasm_init(Dst, DASM_MAXSECTION); dasm_setupglobal(Dst, ctx->glob, ctx->nglob); dasm_setup(Dst, build_actionlist); /* Call arch-specific backend to emit the code. */ ctx->npc = build_backend(ctx); /* Finalize the code. */ (void)dasm_checkstep(Dst, -1); if ((status = dasm_link(Dst, &ctx->codesz))) return status; ctx->code = (uint8_t *)malloc(ctx->codesz); if ((status = dasm_encode(Dst, (void *)ctx->code))) return status; /* Allocate symbol table and bytecode offsets. */ ctx->beginsym = sym_decorate(ctx, "", LABEL_PREFIX "vm_asm_begin"); ctx->sym = (BuildSym *)malloc((ctx->npc+ctx->nglob+1)*sizeof(BuildSym)); ctx->nsym = 0; ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t)); /* Collect the opcodes (PC labels). */ for (i = 0; i < ctx->npc; i++) { int32_t ofs = dasm_getpclabel(Dst, i); if (ofs < 0) return 0x22000000|i; ctx->bc_ofs[i] = ofs; if ((LJ_HASJIT || !(i == BC_JFORI || i == BC_JFORL || i == BC_JITERL || i == BC_JLOOP || i == BC_IFORL || i == BC_IITERL || i == BC_ILOOP)) && (LJ_HASFFI || i != BC_KCDATA)) sym_insert(ctx, ofs, LABEL_PREFIX_BC, bc_names[i]); } /* Collect the globals (named labels). */ for (i = 0; i < ctx->nglob; i++) { const char *gl = globnames[i]; int len = (int)strlen(gl); if (!ctx->glob[i]) { fprintf(stderr, "Error: undefined global %s\n", gl); exit(2); } /* Skip the _Z symbols. */ if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z')) sym_insert(ctx, (int32_t)((uint8_t *)(ctx->glob[i]) - ctx->code), LABEL_PREFIX, globnames[i]); } /* Close the address range. */ sym_insert(ctx, (int32_t)ctx->codesz, "", ""); ctx->nsym--; dasm_free(Dst); return 0; }
SRE_API sre_int_t sre_vm_thompson_jit_compile(sre_pool_t *pool, sre_program_t *prog, sre_vm_thompson_code_t **pcode) { #if (SRE_TARGET != SRE_ARCH_X64) return SRE_DECLINED; #else int status; size_t codesz; size_t size; unsigned char *mem; dasm_State *dasm; void **glob; unsigned nglobs = SRE_VM_THOMPSON_GLOB__MAX; sre_vm_thompson_code_t *code; glob = sre_pcalloc(pool, nglobs * sizeof(void *)); if (glob == NULL) { return SRE_ERROR; } dasm_init(&dasm, 1); dasm_setupglobal(&dasm, glob, nglobs); dasm_setup(&dasm, sre_vm_thompson_jit_actions); dd("thread size: %d", (int) sizeof(sre_vm_thompson_thread_t)); if (sre_vm_thompson_jit_do_compile(&dasm, pool, prog) != SRE_OK) { dasm_free(&dasm); return SRE_ERROR; } status = dasm_link(&dasm, &codesz); if (status != DASM_S_OK) { dasm_free(&dasm); return SRE_ERROR; } size = codesz + sizeof(sre_vm_thompson_code_t); dd("size: %d, codesiz: %d", (int) size, (int) codesz); mem = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); if (mem == MAP_FAILED) { perror("mmap"); dasm_free(&dasm); return SRE_ERROR; } code = (sre_vm_thompson_code_t *) mem; code->size = size; code->handler = (sre_vm_thompson_exec_pt) (mem + sizeof(sre_vm_thompson_code_t)); *pcode = code; dasm_encode(&dasm, code->handler); #if (DDEBUG) { int i; int len; FILE *f; const char *gl; /* * write generated machine code to a temporary file. * wiew with objdump or ndisasm */ f = fopen("/tmp/thompson-jit.bin", "wb"); fwrite(code->handler, codesz, 1, f); fclose(f); f = fopen("/tmp/thompson-jit.txt", "w"); fprintf(f, "code section: start=%p len=%lu\n", code->handler, (unsigned long) codesz); fprintf(f, "global names:\n"); for (i = 0; i < nglobs; i++) { gl = sre_vm_thompson_jit_global_names[i]; len = (int) strlen(gl); if (!glob[i]) { continue; } /* Skip the _Z symbols. */ if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z')) { fprintf(f, " %s => %p\n", gl, glob[i]); } } fprintf(f, "\npc labels:\n"); for (i = 0; i < dasm->pcsize; i++) { int32_t ofs = dasm_getpclabel(&dasm, i); if (ofs >= 0) { fprintf(f, " %d => %ld\n", i, (long) ofs); } } fclose(f); } #endif dasm_free(&dasm); if (mprotect(mem, size, PROT_EXEC | PROT_READ) != 0) { (void) munmap(code, code->size); return SRE_ERROR; } dd("code start addr: %p", code->handler); return SRE_OK; #endif /* SRE_TARGET == SRE_ARCH_X64 */ }