From 10374c95ee72aa5b4af16e9d26be501a7022909a Mon Sep 17 00:00:00 2001 From: "yu.dongliang" <18588496441@163.com> Date: Tue, 28 Mar 2023 20:51:46 +0800 Subject: [PATCH] 1, add Naja Virtual Machine for naja bytecode, 2, lexer: support "\033" in string, so printf() can print with color. --- elf/scf_elf.c | 9 + elf/scf_elf.h | 10 + elf/scf_elf_arm64.c | 3 +- elf/scf_elf_naja.c | 12 +- elf/scf_elf_naja_so.c | 42 +- elf/scf_elf_native.c | 54 + elf/scf_elf_native.h | 2 + lex/scf_lex.c | 28 +- native/risc/scf_arm64.c | 65 +- native/risc/scf_naja.c | 99 +- native/risc/scf_risc_bb_color.c | 52 +- native/scf_native.h | 4 +- parse/Makefile | 7 +- vm/Makefile | 40 + vm/scf_vm.c | 99 ++ vm/scf_vm.h | 99 ++ vm/scf_vm_naja.c | 1673 +++++++++++++++++++++++++++++++ vm/scf_vm_naja_asm.c | 808 +++++++++++++++ vm/scf_vm_test.c | 22 + 19 files changed, 3027 insertions(+), 101 deletions(-) create mode 100644 vm/Makefile create mode 100644 vm/scf_vm.c create mode 100644 vm/scf_vm.h create mode 100644 vm/scf_vm_naja.c create mode 100644 vm/scf_vm_naja_asm.c create mode 100644 vm/scf_vm_test.c diff --git a/elf/scf_elf.c b/elf/scf_elf.c index 5577d72..60a4ef4 100644 --- a/elf/scf_elf.c +++ b/elf/scf_elf.c @@ -200,6 +200,15 @@ int scf_elf_read_relas(scf_elf_context_t* elf, scf_vector_t* relas, const char* return -1; } +int scf_elf_read_phdrs(scf_elf_context_t* elf, scf_vector_t* phdrs) +{ + if (elf && elf->ops && elf->ops->read_phdrs && phdrs) + return elf->ops->read_phdrs(elf, phdrs); + + scf_loge("\n"); + return -1; +} + int scf_elf_write_rel(scf_elf_context_t* elf) { if (elf && elf->ops && elf->ops->write_rel) diff --git a/elf/scf_elf.h b/elf/scf_elf.h index 0cdb91f..cc9717f 100644 --- a/elf/scf_elf.h +++ b/elf/scf_elf.h @@ -42,6 +42,14 @@ typedef struct { uint32_t sh_info; } scf_elf_section_t; +typedef struct { + Elf64_Phdr ph; + + uint64_t addr; + uint64_t len; + void* data; +} scf_elf_phdr_t; + struct scf_elf_ops_s { const char* machine; @@ -52,6 +60,7 @@ struct scf_elf_ops_s int (*add_sym )(scf_elf_context_t* elf, const scf_elf_sym_t* sym, const char* sh_name); int (*read_syms )(scf_elf_context_t* elf, scf_vector_t* syms, const char* sh_name); int (*read_relas)(scf_elf_context_t* elf, scf_vector_t* relas, const char* sh_name); + int (*read_phdrs)(scf_elf_context_t* elf, scf_vector_t* phdrs); int (*add_section )(scf_elf_context_t* elf, const scf_elf_section_t* section); int (*read_section)(scf_elf_context_t* elf, scf_elf_section_t** psection, const char* name); @@ -94,6 +103,7 @@ int scf_elf_read_section(scf_elf_context_t* elf, scf_elf_section_t** psection, c int scf_elf_read_syms (scf_elf_context_t* elf, scf_vector_t* syms, const char* sh_name); int scf_elf_read_relas(scf_elf_context_t* elf, scf_vector_t* relas, const char* sh_name); +int scf_elf_read_phdrs(scf_elf_context_t* elf, scf_vector_t* phdrs); int scf_elf_write_rel( scf_elf_context_t* elf); int scf_elf_write_exec(scf_elf_context_t* elf); diff --git a/elf/scf_elf_arm64.c b/elf/scf_elf_arm64.c index ea13de4..f8e14ef 100644 --- a/elf/scf_elf_arm64.c +++ b/elf/scf_elf_arm64.c @@ -52,11 +52,10 @@ static int _arm64_elf_link_cs(elf_native_t* arm64, elf_section_t* s, elf_section } offset &= 0x3ffffff; - offset |= (0x25 << 26); scf_loge("sym: %s, offset: %#x, %#lx\n", sym->name->data, offset, rela->r_offset); - *(uint32_t*)(s->data + rela->r_offset) = offset; + *(uint32_t*)(s->data + rela->r_offset) |= offset; break; case R_AARCH64_ADR_PREL_PG_HI21: diff --git a/elf/scf_elf_naja.c b/elf/scf_elf_naja.c index fe4e21f..e62bbe6 100644 --- a/elf/scf_elf_naja.c +++ b/elf/scf_elf_naja.c @@ -52,24 +52,23 @@ static int _naja_elf_link_cs(elf_native_t* naja, elf_section_t* s, elf_section_t } offset &= 0x3ffffff; - offset |= (0x25 << 26); scf_loge("sym: %s, offset: %#x, %#lx\n", sym->name->data, offset, rela->r_offset); - *(uint32_t*)(s->data + rela->r_offset) = offset; + *(uint32_t*)(s->data + rela->r_offset) |= offset; break; case R_AARCH64_ADR_PREL_PG_HI21: - offset >>= 12; - offset = ((offset & 0x3) << 29) | (((offset >> 2) & 0x7ffff) << 5); + offset >>= 15; + offset &= 0x1fffff; *(uint32_t*)(s->data + rela->r_offset) |= offset; break; case R_AARCH64_ADD_ABS_LO12_NC: - *(uint32_t*)(s->data + rela->r_offset) |= (sym->sym.st_value & 0xfff) << 10; + *(uint32_t*)(s->data + rela->r_offset) |= (sym->sym.st_value & 0x7fff) << 5; break; default: @@ -343,7 +342,7 @@ static int _naja_elf_write_exec(scf_elf_context_t* elf) for (i = 0; i < naja->symbols->size; i++) { sym = naja->symbols->data[i]; - if (!strcmp(sym->name->data, "_start")) { + if (!strcmp(sym->name->data, "main")) { if (0 != _start) { scf_loge("\n"); @@ -469,6 +468,7 @@ scf_elf_ops_t elf_ops_naja = .read_syms = elf_read_syms, .read_relas = elf_read_relas, .read_section = elf_read_section, + .read_phdrs = elf_read_phdrs, .write_rel = _naja_elf_write_rel, .write_exec = _naja_elf_write_exec, diff --git a/elf/scf_elf_naja_so.c b/elf/scf_elf_naja_so.c index 345a9af..6e2fb8c 100644 --- a/elf/scf_elf_naja_so.c +++ b/elf/scf_elf_naja_so.c @@ -2,22 +2,23 @@ #include"scf_elf_link.h" static uint32_t naja_plt_lazy[8] = { - 0xa9bf7bf0, // stp x16, x30, [sp, #-16]! - 0x90000010, // adrp x16, 0 - 0xf9400211, // ldr x17, [x16, #0] - 0x91000210, // add x16, x16, #0 - - 0xd61f0220, // br x17 - 0xd503201f, // nop - 0xd503201f, // nop - 0xd503201f, // nop + // str x16, x30, [sp, #-16]! + (5 << 26) | (16 << 21) | (1 << 20) | (3 << 17) | (((-1) & 0xfff) << 5) | 0x1f, + (5 << 26) | (30 << 21) | (1 << 20) | (3 << 17) | (((-1) & 0xfff) << 5) | 0x1f, + (0x2a << 26) | (16 << 21), // adrp x16, 0 + (0 << 26) | (16 << 21) | (1 << 20) | 16, // add x16, x16, #0 + + (4 << 26) | (17 << 21) | (3 << 17) | 16, // ldr x17, [x16, #0] + (0xa << 26) | (17 << 21), // jmp *x17 + (0xf << 26), // nop, mov r0, r0 + (0xf << 26), // nop, mov r0, r0 }; static uint32_t naja_plt[4] = { - 0x90000010, // adrp x16, 0 - 0xf9400211, // ldr x17, [x16, #0] - 0x91000210, // add x16, x16, #0 - 0xd61f0220, // br x17 + (0x2a << 26) | (16 << 21), // adrp x16, 0 + (0 << 26) | (16 << 21) | (1 << 20) | 16, // add x16, x16, #0 + (4 << 26) | (17 << 21) | (3 << 17) | 16, // ldr x17, [x16, #0] + (0xa << 26) | (17 << 21), // jmp *x17 }; @@ -539,7 +540,7 @@ int __naja_elf_add_dyn (elf_native_t* naja) Elf64_Dyn* dyns = (Elf64_Dyn*)naja->dynamic->data; - size_t prefix = strlen("../lib/naja"); + size_t prefix = strlen("../lib/arm64"); for (i = 0; i < naja->dyn_needs->size; i++) { scf_string_t* needed = naja->dyn_needs->data[i]; @@ -687,9 +688,8 @@ int __naja_elf_post_dyn(elf_native_t* naja, uint64_t rx_base, uint64_t rw_base, scf_loge("got_addr: %#lx, plt_addr: %#lx, offset: %d, %#x\n", got_addr, plt_addr, offset, offset); - plt[1] |= (((offset >> 12) & 0x3) << 29) | (((offset >> 14) & 0x7ffff) << 5); - plt[2] |= ((got_addr & 0xfff) >> 3) << 10; - plt[3] |= (got_addr & 0xfff) << 10; + plt[2] |= (offset >> 15) & 0x1fffff; + plt[3] |= (got_addr & 0x7fff) << 5; got_addr += 8; plt_addr += sizeof(naja_plt_lazy); @@ -707,9 +707,8 @@ int __naja_elf_post_dyn(elf_native_t* naja, uint64_t rx_base, uint64_t rw_base, scf_loge("i: %d, got_addr: %#lx, plt_addr: %#lx, offset: %d, %#x\n", i, got_addr, plt_addr, offset, offset); - plt[0] |= (((offset >> 12) & 0x3) << 29) | (((offset >> 14) & 0x7ffff) << 5); - plt[1] |= ((got_addr & 0xfff) >> 3) << 10; - plt[2] |= (got_addr & 0xfff) << 10; + plt[0] |= (offset >> 15) & 0x1fffff; + plt[1] |= (got_addr & 0x7fff) << 5; plt += sizeof(naja_plt) / sizeof(naja_plt[0]); plt_addr += sizeof(naja_plt); @@ -739,9 +738,8 @@ int __naja_elf_post_dyn(elf_native_t* naja, uint64_t rx_base, uint64_t rw_base, } offset &= 0x3ffffff; - offset |= (0x25 << 26); - *(uint32_t*)(cs->data + r->r_offset) = offset; + *(uint32_t*)(cs->data + r->r_offset) |= offset; } Elf64_Dyn* dtags = (Elf64_Dyn*)naja->dynamic->data; diff --git a/elf/scf_elf_native.c b/elf/scf_elf_native.c index 9a38604..3a32ffe 100644 --- a/elf/scf_elf_native.c +++ b/elf/scf_elf_native.c @@ -376,6 +376,60 @@ static int __elf_read_section_by_index(scf_elf_context_t* elf, elf_section_t** p return -1; } +int elf_read_phdrs(scf_elf_context_t* elf, scf_vector_t* phdrs) +{ + elf_native_t* e = elf->priv; + scf_elf_phdr_t* ph; + Elf64_Ehdr eh; + + if (!e || !elf->fp) + return -1; + + if (!elf->fp) + return -EINVAL; + + int ret = fseek(elf->fp, elf->start, SEEK_SET); + if (ret < 0) + return ret; + + ret = fread(&eh, sizeof(Elf64_Ehdr), 1, elf->fp); + if (ret != 1) + return -1; + + if (ELFMAG0 != eh.e_ident[EI_MAG0] + || ELFMAG1 != eh.e_ident[EI_MAG1] + || ELFMAG2 != eh.e_ident[EI_MAG2] + || ELFMAG3 != eh.e_ident[EI_MAG3]) { + + scf_loge("not elf file\n"); + return -1; + } + + fseek(elf->fp, elf->start + eh.e_phoff, SEEK_SET); + + int i; + for (i = 0; i < eh.e_phnum; i++) { + + ph = calloc(1, sizeof(scf_elf_phdr_t)); + if (!ph) + return -ENOMEM; + + ret = fread(&ph->ph, sizeof(Elf64_Phdr), 1, elf->fp); + + if (ret != 1) { + free(ph); + return -1; + } + + if (scf_vector_add(phdrs, ph) < 0) { + free(ph); + return -ENOMEM; + } + } + + return 0; +} + static int __elf_read_section(scf_elf_context_t* elf, elf_section_t** psection, const char* name) { elf_native_t* e = elf->priv; diff --git a/elf/scf_elf_native.h b/elf/scf_elf_native.h index 08916c3..179b4b5 100644 --- a/elf/scf_elf_native.h +++ b/elf/scf_elf_native.h @@ -41,6 +41,7 @@ typedef struct { Elf64_Shdr sh_null; scf_vector_t* sections; + scf_vector_t* phdrs; Elf64_Shdr sh_symtab; scf_vector_t* symbols; @@ -82,6 +83,7 @@ int elf_read_section (scf_elf_context_t* elf, scf_elf_section_t** psection, con int elf_add_dyn_need(scf_elf_context_t* elf, const char* soname); int elf_add_dyn_rela(scf_elf_context_t* elf, const scf_elf_rela_t* rela); +int elf_read_phdrs (scf_elf_context_t* elf, scf_vector_t* phdrs); int elf_read_relas (scf_elf_context_t* elf, scf_vector_t* relas, const char* sh_name); int elf_read_syms (scf_elf_context_t* elf, scf_vector_t* syms, const char* sh_name); diff --git a/lex/scf_lex.c b/lex/scf_lex.c index 1768b37..7402ddf 100644 --- a/lex/scf_lex.c +++ b/lex/scf_lex.c @@ -839,14 +839,36 @@ static int _lex_string(scf_lex_t* lex, scf_lex_word_t** pword, scf_lex_char_t* c scf_string_cat_cstr_len(s, (char*)&c1->c, 1); scf_string_cat_cstr_len(s, (char*)&c2->c, 1); - - scf_string_cat_cstr_len(data, (char*)&ch2, 1); lex->pos += 2; free(c2); - c2 = NULL; free(c1); + c2 = NULL; c1 = NULL; + + if (0 == ch2) { + while (1) { + c1 = _lex_pop_char(lex); + + if ('0' <= c1->c && c1->c <= '7') { + ch2 <<= 3; + ch2 += c1->c - '0'; + + scf_string_cat_cstr_len(s, (char*)&c1->c, 1); + lex->pos++; + + free(c1); + c1 = NULL; + } else { + _lex_push_char(lex, c1); + break; + } + } + + scf_string_cat_cstr_len(data, (char*)&ch2, 1); + } else + scf_string_cat_cstr_len(data, (char*)&ch2, 1); + } else if (EOF == c1->c) { printf("%s(),%d, error: \n", __func__, __LINE__); return -1; diff --git a/native/risc/scf_arm64.c b/native/risc/scf_arm64.c index d72007b..b8e46e6 100644 --- a/native/risc/scf_arm64.c +++ b/native/risc/scf_arm64.c @@ -1488,7 +1488,7 @@ scf_instruction_t* arm64_inst_JBE(scf_3ac_code_t* c) return NULL; } -void risc_set_jmp_offset(scf_instruction_t* inst, int32_t bytes) +void arm64_set_jmp_offset(scf_instruction_t* inst, int32_t bytes) { if (0x54 == inst->code[3]) { @@ -1522,6 +1522,66 @@ void risc_set_jmp_offset(scf_instruction_t* inst, int32_t bytes) } } +int arm64_cmp_update(scf_3ac_code_t* c, scf_function_t* f, scf_instruction_t* cmp) +{ + scf_instruction_t* inst; + scf_register_t* r16 = risc_find_register_type_id_bytes(0, 16, 8); + scf_register_t* r17 = risc_find_register_type_id_bytes(0, 17, 8); + scf_register_t* r0; + + uint32_t opcode; + uint32_t mov; + uint32_t i0; + uint32_t i1; + + opcode = cmp->code[0]; + opcode |= cmp->code[1] << 8; + opcode |= cmp->code[2] << 16; + opcode |= cmp->code[3] << 24; + + switch (cmp->code[3] & 0x7f) { + // arm64 + case 0x71: // imm + i0 = (opcode >> 5) & 0x1f; + r0 = risc_find_register_type_id_bytes(0, i0, 8); + inst = f->iops->MOV_G(c, r16, r0); // use r16 to backup r0 + RISC_INST_ADD_CHECK(c->instructions, inst); + + opcode &= ~(0x1f << 5); + opcode |= (0x10 << 5); + break; + + case 0x6b: // register + i0 = (opcode >> 5) & 0x1f; + i1 = (opcode >> 16) & 0x1f; + + r0 = risc_find_register_type_id_bytes(0, i0, 8); + inst = f->iops->MOV_G(c, r16, r0); // use r16 to backup r0 + RISC_INST_ADD_CHECK(c->instructions, inst); + + r0 = risc_find_register_type_id_bytes(0, i1, 8); + inst = f->iops->MOV_G(c, r17, r0); // use r17 to backup r1 + RISC_INST_ADD_CHECK(c->instructions, inst); + + opcode &= ~(0x1f << 5); + opcode |= (0x10 << 5); + + opcode &= ~(0x1f << 16); + opcode |= (0x11 << 16); + break; + default: + scf_loge("%#x\n", opcode); + return -EINVAL; + break; + }; + + cmp->code[0] = 0xff & opcode; + cmp->code[1] = 0xff & (opcode >> 8); + cmp->code[2] = 0xff & (opcode >> 16); + cmp->code[3] = 0xff & (opcode >> 24); + return 0; +} + scf_inst_ops_t inst_ops_arm64 = { .name = "arm64", @@ -1604,6 +1664,7 @@ scf_inst_ops_t inst_ops_arm64 = .ADRP2G = arm64_inst_ADRP2G, .ADRSIB2G = arm64_inst_ADRSIB2G, - .set_jmp_offset = risc_set_jmp_offset, + .set_jmp_offset = arm64_set_jmp_offset, + .cmp_update = arm64_cmp_update, }; diff --git a/native/risc/scf_naja.c b/native/risc/scf_naja.c index 53ee2cd..63f1565 100644 --- a/native/risc/scf_naja.c +++ b/native/risc/scf_naja.c @@ -167,7 +167,7 @@ int naja_inst_M2G(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_ return -EINVAL; } - offset >> 1; + offset >>= 1; SIZE = 1; } else if (4 == size) { @@ -177,7 +177,7 @@ int naja_inst_M2G(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_ return -EINVAL; } - offset >> 2; + offset >>= 2; SIZE = 2; } else if (8 == size) { @@ -187,7 +187,7 @@ int naja_inst_M2G(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_ return -EINVAL; } - offset >> 3; + offset >>= 3; SIZE = 3; } else return -EINVAL; @@ -274,7 +274,7 @@ int naja_inst_G2M(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rs, scf_ return -EINVAL; } - offset >> 1; + offset >>= 1; SIZE = 1; } else if (4 == size) { @@ -284,7 +284,7 @@ int naja_inst_G2M(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rs, scf_ return -EINVAL; } - offset >> 2; + offset >>= 2; SIZE = 2; } else if (8 == size) { @@ -294,12 +294,14 @@ int naja_inst_G2M(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rs, scf_ return -EINVAL; } - offset >> 3; + offset >>= 3; SIZE = 3; } else return -EINVAL; + scf_loge("offset: %ld, SIZE: %d\n", offset, SIZE); + if (offset >= -0x7ff && offset <= 0x7ff) opcode = (0x5 << 26) | ((offset & 0xfff) << 5) | rb->id; else { @@ -376,7 +378,7 @@ int naja_inst_G2P(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rs, scf_ return -EINVAL; } - offset >> 1; + offset >>= 1; SIZE = 1; } else if (4 == size) { @@ -386,7 +388,7 @@ int naja_inst_G2P(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rs, scf_ return -EINVAL; } - offset >> 2; + offset >>= 2; SIZE = 2; } else if (8 == size) { @@ -396,7 +398,7 @@ int naja_inst_G2P(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rs, scf_ return -EINVAL; } - offset >> 3; + offset >>= 3; SIZE = 3; } else @@ -447,7 +449,7 @@ int naja_inst_P2G(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_ return -EINVAL; } - offset >> 1; + offset >>= 1; SIZE = 1; } else if (4 == size) { @@ -457,7 +459,7 @@ int naja_inst_P2G(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_ return -EINVAL; } - offset >> 2; + offset >>= 2; SIZE = 2; } else if (8 == size) { @@ -467,7 +469,7 @@ int naja_inst_P2G(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_ return -EINVAL; } - offset >> 3; + offset >>= 3; SIZE = 3; } else @@ -653,7 +655,7 @@ scf_instruction_t* naja_inst_PUSH(scf_3ac_code_t* c, scf_register_t* r) scf_instruction_t* inst; uint32_t opcode; - opcode = (0x5 << 26) | (r->id << 21) | (1 << 20) | (3 << 17) | (1 << 5) | 0x1f; + opcode = (0x5 << 26) | (r->id << 21) | (1 << 20) | (3 << 17) | ((0xfff & -1) << 5) | 0x1f; inst = risc_make_inst(c, opcode); return inst; @@ -664,7 +666,7 @@ scf_instruction_t* naja_inst_POP(scf_3ac_code_t* c, scf_register_t* r) scf_instruction_t* inst; uint32_t opcode; - opcode = (0x4 << 26) | (r->id << 21) | (1 << 20) | (3 << 17) | ((0xfff & -1) << 5) | 0x1f; + opcode = (0x4 << 26) | (r->id << 21) | (1 << 20) | (3 << 17) | (1 << 5) | 0x1f; inst = risc_make_inst(c, opcode); return inst; @@ -1296,7 +1298,7 @@ scf_instruction_t* naja_inst_JBE(scf_3ac_code_t* c) void naja_set_jmp_offset(scf_instruction_t* inst, int32_t bytes) { - if (0xa == inst->code[3] && 1 == (inst->code[0] & 1)) { + if (0x28 == inst->code[3] && 1 == (inst->code[0] & 1)) { if (bytes >= 0 && bytes < (0x1 << 20)) { bytes >>= 2; @@ -1305,7 +1307,7 @@ void naja_set_jmp_offset(scf_instruction_t* inst, int32_t bytes) } else if (bytes < 0 && bytes > -(0x1 << 20)) { bytes >>= 2; - bytes &= 0x7ffff; + bytes &= 0x1fffff; bytes <<= 5; } else assert(0); @@ -1313,9 +1315,10 @@ void naja_set_jmp_offset(scf_instruction_t* inst, int32_t bytes) inst->code[0] |= 0xff & bytes; inst->code[1] |= 0xff & (bytes >> 8); inst->code[2] |= 0xff & (bytes >> 16); + inst->code[3] |= 0x3 & (bytes >> 24); } else { - assert(8 == inst->code[3]); + assert(0x20 == inst->code[3]); bytes >>= 2; @@ -1328,6 +1331,67 @@ void naja_set_jmp_offset(scf_instruction_t* inst, int32_t bytes) } } +int naja_cmp_update(scf_3ac_code_t* c, scf_function_t* f, scf_instruction_t* cmp) +{ + scf_instruction_t* inst; + scf_register_t* r16 = risc_find_register_type_id_bytes(0, 16, 8); + scf_register_t* r17 = risc_find_register_type_id_bytes(0, 17, 8); + scf_register_t* r0; + + uint32_t opcode; + uint32_t mov; + uint32_t i0; + uint32_t i1; + + opcode = cmp->code[0]; + opcode |= cmp->code[1] << 8; + opcode |= cmp->code[2] << 16; + opcode |= cmp->code[3] << 24; + + switch (cmp->code[3]) { + + case 0x14: // imm + i0 = opcode & 0x1f; + r0 = risc_find_register_type_id_bytes(0, i0, 8); + inst = f->iops->MOV_G(c, r16, r0); // use r16 to backup r0 + RISC_INST_ADD_CHECK(c->instructions, inst); + + opcode &= ~0x1f; + opcode |= 0x10; + break; + + case 0x24: // register + i0 = opcode & 0x1f; + i1 = (opcode >> 5) & 0x1f; + + r0 = risc_find_register_type_id_bytes(0, i0, 8); + inst = f->iops->MOV_G(c, r16, r0); // use r16 to backup r0 + RISC_INST_ADD_CHECK(c->instructions, inst); + + r0 = risc_find_register_type_id_bytes(0, i1, 8); + inst = f->iops->MOV_G(c, r17, r0); // use r17 to backup r1 + RISC_INST_ADD_CHECK(c->instructions, inst); + + opcode &= ~0x1f; + opcode |= 0x10; + + opcode &= ~(0x1f << 5); + opcode |= (0x11 << 5); + break; + default: + scf_loge("%#x\n", opcode); + return -EINVAL; + break; + }; + + cmp->code[0] = 0xff & opcode; + cmp->code[1] = 0xff & (opcode >> 8); + cmp->code[2] = 0xff & (opcode >> 16); + cmp->code[3] = 0xff & (opcode >> 24); + return 0; +} + + scf_inst_ops_t inst_ops_naja = { .name = "naja", @@ -1411,5 +1475,6 @@ scf_inst_ops_t inst_ops_naja = .ADRSIB2G = naja_inst_ADRSIB2G, .set_jmp_offset = naja_set_jmp_offset, + .cmp_update = naja_cmp_update, }; diff --git a/native/risc/scf_risc_bb_color.c b/native/risc/scf_risc_bb_color.c index 668b018..0cac255 100644 --- a/native/risc/scf_risc_bb_color.c +++ b/native/risc/scf_risc_bb_color.c @@ -190,55 +190,13 @@ int risc_bb_load_dn2(intptr_t color, scf_dag_node_t* dn, scf_basic_block_t* bb, if (bb->cmp_flag) { cmp = c->instructions->data[c->instructions->size - 1]; - c->instructions->size--; - opcode = cmp->code[0]; - opcode |= cmp->code[1] << 8; - opcode |= cmp->code[2] << 16; - opcode |= cmp->code[3] << 24; - - switch (cmp->code[3] & 0x7f) { - - case 0x71: // imm - i0 = (opcode >> 5) & 0x1f; - r0 = risc_find_register_type_id_bytes(0, i0, 8); - inst = f->iops->MOV_G(c, r16, r0); // use r16 to backup r0 - RISC_INST_ADD_CHECK(c->instructions, inst); - - opcode &= ~(0x1f << 5); - opcode |= (0x10 << 5); - break; - - case 0x6b: // register - i0 = (opcode >> 5) & 0x1f; - i1 = (opcode >> 16) & 0x1f; - - r0 = risc_find_register_type_id_bytes(0, i0, 8); - inst = f->iops->MOV_G(c, r16, r0); // use r16 to backup r0 - RISC_INST_ADD_CHECK(c->instructions, inst); - - r0 = risc_find_register_type_id_bytes(0, i1, 8); - inst = f->iops->MOV_G(c, r17, r0); // use r17 to backup r1 - RISC_INST_ADD_CHECK(c->instructions, inst); - - opcode &= ~(0x1f << 5); - opcode |= (0x10 << 5); - - opcode &= ~(0x1f << 16); - opcode |= (0x11 << 16); - break; - - default: - scf_loge("%#x\n", opcode); - return -EINVAL; - break; - }; - - cmp->code[0] = 0xff & opcode; - cmp->code[1] = 0xff & (opcode >> 8); - cmp->code[2] = 0xff & (opcode >> 16); - cmp->code[3] = 0xff & (opcode >> 24); + int ret = f->iops->cmp_update(c, f, cmp); + if (ret < 0) { + scf_loge("\n"); + return ret; + } } int ret = risc_bb_load_dn(color, dn, c, bb, f); diff --git a/native/scf_native.h b/native/scf_native.h index 9bc8648..9124750 100644 --- a/native/scf_native.h +++ b/native/scf_native.h @@ -174,7 +174,9 @@ struct scf_inst_ops_s int (*G2SIB )(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_sib_t* sib); int (*ADR2G )(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_variable_t* vs); int (*ADRP2G)(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_register_t* rb, int32_t offset); - int (*ADRSIB2G)(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_sib_t* sib); + + int (*ADRSIB2G )(scf_3ac_code_t* c, scf_function_t* f, scf_register_t* rd, scf_sib_t* sib); + int (*cmp_update)(scf_3ac_code_t* c, scf_function_t* f, scf_instruction_t* inst); void (*set_jmp_offset)(scf_instruction_t* inst, int32_t bytes); }; diff --git a/parse/Makefile b/parse/Makefile index 0766f2f..10395df 100644 --- a/parse/Makefile +++ b/parse/Makefile @@ -53,6 +53,10 @@ CFILES += ../elf/scf_dwarf_abbrev.c CFILES += ../elf/scf_dwarf_info.c CFILES += ../elf/scf_dwarf_line.c +CFILES += ../vm/scf_vm.c +CFILES += ../vm/scf_vm_naja.c +CFILES += ../vm/scf_vm_naja_asm.c + CFILES += ../core/scf_lex_word.c CFILES += ../core/scf_type.c CFILES += ../core/scf_variable.c @@ -156,11 +160,12 @@ CFLAGS += -I../core CFLAGS += -I../lex CFLAGS += -I../parse CFLAGS += -I../elf +CFLAGS += -I../vm CFLAGS += -I../native CFLAGS += -I../native/x64 CFLAGS += -I../native/risc -LDFLAGS += +LDFLAGS += -ldl all: gcc $(CFLAGS) $(CFILES) $(LDFLAGS) -o scf diff --git a/vm/Makefile b/vm/Makefile new file mode 100644 index 0000000..9d1be3e --- /dev/null +++ b/vm/Makefile @@ -0,0 +1,40 @@ +CFILES += ../util/scf_string.c + +CFILES += ../elf/scf_elf.c +CFILES += ../elf/scf_elf_link.c +CFILES += ../elf/scf_elf_native.c +CFILES += ../elf/scf_elf_x64.c +CFILES += ../elf/scf_elf_x64_so.c +CFILES += ../elf/scf_elf_arm64.c +CFILES += ../elf/scf_elf_arm64_so.c +CFILES += ../elf/scf_elf_naja.c +CFILES += ../elf/scf_elf_naja_so.c +CFILES += ../elf/scf_dwarf.c +CFILES += ../elf/scf_dwarf_abbrev.c +CFILES += ../elf/scf_dwarf_info.c +CFILES += ../elf/scf_dwarf_line.c + +CFILES += ../vm/scf_vm.c +CFILES += ../vm/scf_vm_naja.c +CFILES += ../vm/scf_vm_naja_asm.c +CFILES += ../vm/scf_vm_test.c + +CFLAGS += -g +#CFLAGS += -Wall +CFLAGS += -I../util +CFLAGS += -I../core +CFLAGS += -I../lex +CFLAGS += -I../parse +CFLAGS += -I../elf +CFLAGS += -I../vm +CFLAGS += -I../native +CFLAGS += -I../native/x64 +CFLAGS += -I../native/risc + +LDFLAGS += -ldl + +all: + gcc $(CFLAGS) $(CFILES) $(LDFLAGS) -o nvm + +clean: + rm *.o diff --git a/vm/scf_vm.c b/vm/scf_vm.c new file mode 100644 index 0000000..48a2be6 --- /dev/null +++ b/vm/scf_vm.c @@ -0,0 +1,99 @@ +#include"scf_vm.h" + +extern scf_vm_ops_t vm_ops_naja; +extern scf_vm_ops_t vm_ops_naja_asm; + +static scf_vm_ops_t* vm_ops_array[] = +{ + &vm_ops_naja, + &vm_ops_naja_asm, + + NULL, +}; + +int scf_vm_open(scf_vm_t** pvm, const char* arch) +{ + scf_vm_ops_t* ops = NULL; + scf_vm_t* vm; + + int i; + for (i = 0; vm_ops_array[i]; i++) { + + if (!strcmp(vm_ops_array[i]->name, arch)) { + ops = vm_ops_array[i]; + break; + } + } + + if (!ops) { + scf_loge("\n"); + return -EINVAL; + } + + vm = calloc(1, sizeof(scf_vm_t)); + if (!vm) + return -ENOMEM; + + vm->ops = ops; + + if (vm->ops->open) { + int ret = vm->ops->open(vm); + if (ret < 0) + return ret; + } + + *pvm = vm; + return 0; +} + +int scf_vm_clear(scf_vm_t* vm) +{ + if (!vm) + return -EINVAL; + + if (vm->elf) { + scf_elf_close(vm->elf); + vm->elf = NULL; + } + + if (vm->sofiles) { + int i; + + for (i = 0; i < vm->sofiles->size; i++) + dlclose(vm->sofiles->data[i]); + + scf_vector_free(vm->sofiles); + vm->sofiles = NULL; + } + + vm->text = NULL; + vm->rodata = NULL; + vm->data = NULL; + + return 0; +} + +int scf_vm_close(scf_vm_t* vm) +{ + if (vm) { + scf_vm_clear(vm); + + if (vm->ops && vm->ops->close) + vm->ops->close(vm); + + free(vm); + vm = NULL; + } + + return 0; +} + +int scf_vm_run(scf_vm_t* vm, const char* path, const char* sys) +{ + if (vm && vm->ops && vm->ops->run && path) + return vm->ops->run(vm, path, sys); + + scf_loge("\n"); + return -EINVAL; +} + diff --git a/vm/scf_vm.h b/vm/scf_vm.h new file mode 100644 index 0000000..23ea753 --- /dev/null +++ b/vm/scf_vm.h @@ -0,0 +1,99 @@ +#ifndef SCF_VM_H +#define SCF_VM_H + +#include"scf_elf.h" +#include + +typedef struct scf_vm_s scf_vm_t; +typedef struct scf_vm_ops_s scf_vm_ops_t; + +struct scf_vm_s +{ + scf_elf_context_t* elf; + + scf_vector_t* sofiles; + scf_vector_t* phdrs; + + scf_elf_phdr_t* text; + scf_elf_phdr_t* rodata; + scf_elf_phdr_t* data; + + scf_elf_phdr_t* dynamic; + Elf64_Rela* jmprel; + uint64_t jmprel_addr; + uint64_t jmprel_size; + Elf64_Sym* dynsym; + uint64_t* pltgot; + uint8_t* dynstr; + + scf_vm_ops_t* ops; + void* priv; +}; + +struct scf_vm_ops_s +{ + const char* name; + + int (*open )(scf_vm_t* vm); + int (*close)(scf_vm_t* vm); + + int (*run )(scf_vm_t* vm, const char* path, const char* sys); +}; + +#define SCF_VM_Z 0 +#define SCF_VM_NZ 1 +#define SCF_VM_GE 2 +#define SCF_VM_GT 3 +#define SCF_VM_LE 4 +#define SCF_VM_LT 5 + +typedef struct { + uint64_t regs[32]; + + uint64_t ip; + uint64_t flags; + +#define STACK_INC 16 + uint8_t* stack; + int64_t size; + + uint64_t _start; + +} scf_vm_naja_t; + +#define NAJA_ADD 0 +#define NAJA_SUB 1 +#define NAJA_MUL 2 +#define NAJA_DIV 3 +#define NAJA_LDR_DISP 4 +#define NAJA_STR_DISP 5 +#define NAJA_AND 6 +#define NAJA_OR 7 +#define NAJA_JMP_DISP 8 +#define NAJA_CMP 9 +#define NAJA_JMP_REG 10 +#define NAJA_SETCC 11 +#define NAJA_LDR_SIB 12 +#define NAJA_STR_SIB 13 +#define NAJA_TEQ 14 +#define NAJA_MOV 15 + +#define NAJA_CALL_DISP 24 +#define NAJA_CALL_REG 26 +#define NAJA_ADRP 42 +#define NAJA_RET 56 + +typedef int (*naja_opcode_pt)(scf_vm_t* vm, uint32_t inst); + +int scf_vm_open (scf_vm_t** pvm, const char* arch); +int scf_vm_close(scf_vm_t* vm); +int scf_vm_clear(scf_vm_t* vm); + +int scf_vm_run (scf_vm_t* vm, const char* path, const char* sys); + +int naja_vm_open(scf_vm_t* vm); +int naja_vm_close(scf_vm_t* vm); +int naja_vm_init(scf_vm_t* vm, const char* path, const char* sys); + +#endif + diff --git a/vm/scf_vm_naja.c b/vm/scf_vm_naja.c new file mode 100644 index 0000000..9656fa4 --- /dev/null +++ b/vm/scf_vm_naja.c @@ -0,0 +1,1673 @@ +#include"scf_vm.h" + +#define NAJA_REG_FP 29 +#define NAJA_REG_LR 30 +#define NAJA_REG_SP 31 + +static const char* somaps[][3] = +{ + {"x64", "/lib/ld-linux-aarch64.so.1", "/lib64/ld-linux-x86-64.so.2"}, + {"x64", "/lib/aarch64-linux-gnu/libc.so.6", "/lib/x86_64-linux-gnu/libc.so.6"}, +}; + +typedef int64_t (*naja_dyn_func_pt)(uint64_t r0, + uint64_t r1, + uint64_t r2, + uint64_t r3, + uint64_t r4, + uint64_t r5, + uint64_t r6, + uint64_t r7); + +int naja_vm_open(scf_vm_t* vm) +{ + if (!vm) + return -EINVAL; + + scf_vm_naja_t* naja = calloc(1, sizeof(scf_vm_naja_t)); + if (!naja) + return -ENOMEM; + + vm->priv = naja; + return 0; +} + +int naja_vm_close(scf_vm_t* vm) +{ + if (vm) { + if (vm->priv) { + free(vm->priv); + vm->priv = NULL; + } + } + + return 0; +} + +static int naja_vm_dynamic_link(scf_vm_t* vm) +{ + naja_dyn_func_pt f = NULL; + scf_vm_naja_t* naja = vm->priv; + + int64_t sp = naja->regs[NAJA_REG_SP]; + + uint64_t r30 = *(uint64_t*)(naja->stack - (sp + 8)); + uint64_t r16 = *(uint64_t*)(naja->stack - (sp + 16)); + + scf_logw("sp: %ld, r16: %#lx, r30: %#lx, vm->jmprel_size: %ld\n", sp, r16, r30, vm->jmprel_size); + + if (r16 > (uint64_t)vm->data->data) { + r16 -= (uint64_t)vm->data->data; + r16 += vm->data->addr; + } + + scf_logw("r16: %#lx, text: %p, rodata: %p, data: %p\n", r16, vm->text->data, vm->rodata->data, vm->data->data); + + int i; + for (i = 0; i < vm->jmprel_size / sizeof(Elf64_Rela); i++) { + + if (r16 == vm->jmprel[i].r_offset) { + + int j = ELF64_R_SYM(vm->jmprel[i].r_info); + + char* fname = vm->dynstr + vm->dynsym[j].st_name; + + scf_logw("j: %d, %s\n", j, fname); + + int k; + for (k = 0; k < vm->sofiles->size; k++) { + + f = dlsym(vm->sofiles->data[k], fname); + if (f) + break; + } + + if (f) { + int64_t offset = vm->jmprel[i].r_offset - vm->data->addr; + + if (offset < 0 || offset > vm->data->len) { + scf_loge("\n"); + return -1; + } + + *(void**)(vm->data->data + offset) = f; + + naja->regs[0] = f(naja->regs[0], + naja->regs[1], + naja->regs[2], + naja->regs[3], + naja->regs[4], + naja->regs[5], + naja->regs[6], + naja->regs[7]); + + naja->regs[NAJA_REG_SP] += 16; + return 0; + } + break; + } + } + + return -1; +} + +int naja_vm_init(scf_vm_t* vm, const char* path, const char* sys) +{ + if (!vm || !path) + return -EINVAL; + + if (vm->elf) + scf_vm_clear(vm); + + if (vm->priv) + memset(vm->priv, 0, sizeof(scf_vm_naja_t)); + else { + vm->priv = calloc(1, sizeof(scf_vm_naja_t)); + if (!vm->priv) + return -ENOMEM; + } + + if (vm->phdrs) + scf_vector_clear(vm->phdrs, (void (*)(void*) )free); + else { + vm->phdrs = scf_vector_alloc(); + if (!vm->phdrs) + return -ENOMEM; + } + + if (vm->sofiles) + scf_vector_clear(vm->phdrs, (void (*)(void*) )dlclose); + else { + vm->sofiles = scf_vector_alloc(); + if (!vm->sofiles) + return -ENOMEM; + } + + int ret = scf_elf_open(&vm->elf, "naja", path, "rb"); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + + ret = scf_elf_read_phdrs(vm->elf, vm->phdrs); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + + scf_elf_phdr_t* ph; + int i; + for (i = 0; i < vm->phdrs->size; i++) { + ph = vm->phdrs->data[i]; + + if (PT_LOAD == ph->ph.p_type) { + + ph->addr = (ph->ph.p_vaddr + ph->ph.p_memsz) & ~(ph->ph.p_align - 1); + ph->len = (ph->ph.p_vaddr + ph->ph.p_memsz) - ph->addr; + + ph->data = calloc(1, ph->len); + if (!ph->data) + return -ENOMEM; + + fseek(vm->elf->fp, 0, SEEK_SET); + + ret = fread(ph->data, ph->len, 1, vm->elf->fp); + if (1 != ret) { + scf_loge("\n"); + return -1; + } + + scf_loge("i: %d, ph->p_offset: %#lx, ph->p_filesz: %#lx\n", i, ph->ph.p_offset, ph->ph.p_filesz); + + scf_loge("i: %d, ph->addr: %#lx, ph->len: %#lx, %#lx, ph->flags: %#x\n", i, ph->addr, ph->len, ph->ph.p_memsz, ph->ph.p_flags); + + if ((PF_X | PF_R) == ph->ph.p_flags) + vm->text = ph; + + else if ((PF_W | PF_R) == ph->ph.p_flags) + vm->data = ph; + + else if (PF_R == ph->ph.p_flags) + vm->rodata = ph; + else { + scf_loge("\n"); + return -1; + } + + } else if (PT_DYNAMIC == ph->ph.p_type) { + ph->addr = ph->ph.p_vaddr; + ph->len = ph->ph.p_memsz; + + vm->dynamic = ph; + + scf_loge("ph->addr: %#lx, ph->len: %#lx, %#lx, ph->p_offset: %#lx\n", ph->addr, ph->len, ph->ph.p_memsz, ph->ph.p_offset); + } + } + + scf_loge("\n\n"); + + if (vm->dynamic) { + Elf64_Dyn* d = (Elf64_Dyn*)(vm->data->data + vm->dynamic->ph.p_offset); + + vm->jmprel = NULL; + for (i = 0; i < vm->dynamic->ph.p_filesz / sizeof(Elf64_Dyn); i++) { + + switch (d[i].d_tag) { + + case DT_STRTAB: + scf_loge("dynstr: %#lx\n", d[i].d_un.d_ptr); + vm->dynstr = d[i].d_un.d_ptr - vm->text->addr + vm->text->data; + break; + + case DT_SYMTAB: + scf_loge("dynsym: %#lx\n", d[i].d_un.d_ptr); + vm->dynsym = (Elf64_Sym*)(d[i].d_un.d_ptr - vm->text->addr + vm->text->data); + break; + + case DT_JMPREL: + scf_loge("JMPREL: %#lx\n", d[i].d_un.d_ptr); + vm->jmprel = (Elf64_Rela*)(d[i].d_un.d_ptr - vm->text->addr + vm->text->data); + vm->jmprel_addr = d[i].d_un.d_ptr; + break; + + case DT_PLTGOT: + scf_loge("PLTGOT: %#lx\n", d[i].d_un.d_ptr); + vm->pltgot = (uint64_t*)(d[i].d_un.d_ptr - vm->data->addr + vm->data->data); + break; + + default: + break; + }; + } + + for (i = 0; i < vm->dynamic->ph.p_filesz / sizeof(Elf64_Dyn); i++) { + + if (DT_NEEDED == d[i].d_tag) { + + uint8_t* name = d[i].d_un.d_ptr + vm->dynstr; + + int j; + for (j = 0; j < sizeof(somaps) / sizeof(somaps[0]); j++) { + + if (!strcmp(somaps[j][0], sys) + && !strcmp(somaps[j][1], name)) { + name = somaps[j][2]; + break; + } + } + + scf_loge("needed: %s\n", name); + + void* so = dlopen(name, RTLD_LAZY); + if (!so) { + scf_loge("dlopen error, so: %s\n", name); + return -1; + } + + if (scf_vector_add(vm->sofiles, so) < 0) { + dlclose(so); + return -ENOMEM; + } + } + } + + vm->pltgot[2] = (uint64_t)naja_vm_dynamic_link; + } + + return 0; +} + +static int __naja_add(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + naja->regs[rd] = naja->regs[rs0] + uimm15; + + printf("add r%d, r%d, %lu\n", rd, rs0, uimm15); + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) { + naja->regs[rd] = naja->regs[rs0] + (naja->regs[rs1] << uimm8); + + printf("add r%d, r%d, r%d << %lu\n", rd, rs0, rs1, uimm8); + + } else if (1 == sh) { + naja->regs[rd] = naja->regs[rs0] + (naja->regs[rs1] >> uimm8); + + printf("add r%d, r%d, r%d LSR %lu\n", rd, rs0, rs1, uimm8); + + } else { + naja->regs[rd] = naja->regs[rs0] + (((int64_t)naja->regs[rs1]) >> uimm8); + + printf("add r%d, r%d, r%d ASR %lu\n", rd, rs0, rs1, uimm8); + } + } + + naja->ip += 4; + return 0; +} + +static int __naja_sub(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + naja->regs[rd] = naja->regs[rs0] - uimm15; + + printf("sub r%d, r%d, %lu\n", rd, rs0, uimm15); + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) { + naja->regs[rd] = naja->regs[rs0] - (naja->regs[rs1] << uimm8); + + printf("sub r%d, r%d, r%d << %lu\n", rd, rs0, rs1, uimm8); + + } else if (1 == sh) { + naja->regs[rd] = naja->regs[rs0] - (naja->regs[rs1] >> uimm8); + + printf("sub r%d, r%d, r%d LSR %lu\n", rd, rs0, rs1, uimm8); + + } else { + naja->regs[rd] = naja->regs[rs0] - (((int64_t)naja->regs[rs1]) >> uimm8); + + printf("sub r%d, r%d, r%d ASR %lu\n", rd, rs0, rs1, uimm8); + } + } + + naja->ip += 4; + return 0; +} + +static int __naja_cmp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + int ret = 0; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + ret = naja->regs[rs0] - uimm15; + + printf("cmp r%d, %ld, rs0: %lx, ret: %d\n", rs0, uimm15, naja->regs[rs0], ret); + + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) { + ret = naja->regs[rs0] - (naja->regs[rs1] << uimm8); + + printf("cmp r%d, r%d LSL %ld, rs0: %#lx, rs1: %#lx, ret: %d\n", rs0, rs1, uimm8, naja->regs[rs0], naja->regs[rs1], ret); + + } else if (1 == sh) { + ret = naja->regs[rs0] - (naja->regs[rs1] >> uimm8); + + printf("cmp r%d, r%d LSR %ld, rs0: %#lx, rs1: %#lx, ret: %d\n", rs0, rs1, uimm8, naja->regs[rs0], naja->regs[rs1], ret); + + } else { + ret = naja->regs[rs0] - (((int64_t)naja->regs[rs1]) >> uimm8); + + printf("cmp r%d, r%d ASR %ld, rs0: %#lx, rs1: %ld, ret: %d\n", rs0, rs1, uimm8, naja->regs[rs0], naja->regs[rs1], ret); + } + } + + if (0 == ret) + naja->flags = 0x1; + else if (ret > 0) + naja->flags = 0x4; + else + naja->flags = 0x2; + + naja->ip += 4; + return 0; +} + +static int __naja_mul(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rs1 = (inst >> 5) & 0x1f; + int rs2 = (inst >> 10) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int S = (inst >> 20) & 0x1; + int opt = (inst >> 15) & 0x3; + + scf_logw("\n"); + if (S) + naja->regs[rd] = (int64_t)naja->regs[rs0] * (int64_t)naja->regs[rs1]; + else + naja->regs[rd] = naja->regs[rs0] * naja->regs[rs1]; + + if (0 == opt) + naja->regs[rd] += naja->regs[rs2]; + else if (1 == opt) + naja->regs[rd] = naja->regs[rs2] - naja->regs[rd]; + + naja->ip += 4; + return 0; +} + +static int __naja_div(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rs1 = (inst >> 5) & 0x1f; + int rs2 = (inst >> 10) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int S = (inst >> 20) & 0x1; + int opt = (inst >> 15) & 0x3; + + scf_logw("\n"); + if (S) + naja->regs[rd] = (int64_t)naja->regs[rs0] / (int64_t)naja->regs[rs1]; + else + naja->regs[rd] = naja->regs[rs0] / naja->regs[rs1]; + + if (0 == opt) + naja->regs[rd] += naja->regs[rs2]; + else if (1 == opt) + naja->regs[rd] = naja->regs[rs2] - naja->regs[rd]; + + naja->ip += 4; + return 0; +} + +static int __naja_ldr_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int A = (inst >> 20) & 0x1; + int ext = (inst >> 17) & 0x7; + int s12 = (inst >> 5) & 0xfff; + + if (s12 & 0x800) + s12 |= 0xfffff000; + + scf_logd("rd: %d, rb: %d, s12: %d, ext: %d\n", rd, rb, s12, ext); + + int64_t addr = naja->regs[rb]; + int64_t offset = 0; + uint8_t* data; + + if (addr >= (int64_t)vm->data->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->data->data + vm->data->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= (int64_t)vm->rodata->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->rodata->data + vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= (int64_t)vm->text->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->text->data + vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x800000) { + data = vm->data->data; + offset = addr - vm->data->addr; + + if (offset >= vm->data->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x600000) { + data = vm->rodata->data; + offset = addr - vm->rodata->addr; + + if (offset >= vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x400000) { + data = vm->text->data; + offset = addr - vm->text->addr; + + if (offset >= vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else { + data = naja->stack; + offset = addr; + } + + if (!A) + offset += s12 << (ext & 0x3); + + if (data == naja->stack) { + offset = -offset; + + scf_logd("offset0: %ld, size: %ld\n", offset, naja->size); + assert(offset >= 0); + + if (naja->size < offset) { + scf_loge("offset: %ld, size: %ld\n", offset, naja->size); + return -EINVAL; + } + + offset -= 1 << (ext & 0x3); + } + + switch (ext) { + case 0: + naja->regs[rd] = *(uint8_t*)(data + offset); + if (A) { + naja->regs[rb] += s12; + printf("ldrb r%d, [r%d, %d]!\n", rd, rb, s12); + } else + printf("ldrb r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 1: + naja->regs[rd] = *(uint16_t*)(data + offset); + if (A) { + naja->regs[rb] += s12 << 1; + printf("ldrw r%d, [r%d, %d]!\n", rd, rb, s12 << 1); + } else + printf("ldrw r%d, [r%d, %d]\n", rd, rb, s12 << 1); + break; + + case 2: + naja->regs[rd] = *(uint32_t*)(data + offset); + if (A) { + naja->regs[rb] += s12 << 2; + printf("ldrl r%d, [r%d, %d]!\n", rd, rb, s12 << 2); + } else + printf("ldrl r%d, [r%d, %d], %ld, %p\n", rd, rb, s12 << 2, naja->regs[rd], data + offset); + break; + + case 3: + naja->regs[rd] = *(uint64_t*)(data + offset); + if (A) { + naja->regs[rb] += s12 << 3; + printf("ldr r%d, [r%d, %d]!, rd: %#lx, rb: %ld, %p\n", rd, rb, s12 << 3, naja->regs[rd], naja->regs[rb], data + offset); + } else + printf("ldr r%d, [r%d, %d]\n", rd, rb, s12 << 3); + break; + + case 4: + naja->regs[rd] = *(int8_t*)(data + offset); + if (A) { + naja->regs[rb] += s12; + printf("ldrsb r%d, [r%d, %d]!\n", rd, rb, s12); + } else + printf("ldrsb r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 5: + naja->regs[rd] = *(int16_t*)(data + offset); + if (A) { + naja->regs[rb] += s12 << 1; + printf("ldrsw r%d, [r%d, %d]!\n", rd, rb, s12 << 1); + } else + printf("ldrsw r%d, [r%d, %d]\n", rd, rb, s12 << 1); + break; + + case 6: + naja->regs[rd] = *(int32_t*)(data + offset); + if (A) { + naja->regs[rb] += s12 << 2; + printf("ldrsl r%d, [r%d, %d]!\n", rd, rb, s12 << 2); + } else + printf("ldrsl r%d, [r%d, %d]\n", rd, rb, s12 << 2); + break; + default: + scf_loge("\n"); + return -1; + break; + }; + + naja->ip += 4; + return 0; +} + +static int __naja_ldr_sib(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int ri = (inst >> 5) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int ext = (inst >> 17) & 0x7; + int u7 = (inst >> 10) & 0x7f; + + int64_t addr = naja->regs[rb]; + uint64_t offset; + uint8_t* data; + + scf_logd("ldr r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + scf_logd("rd: %#lx\n", naja->regs[rd]); + scf_logd("rb: %#lx\n", naja->regs[rb]); + scf_logd("ri: %#lx\n", naja->regs[ri]); + + if (addr >= (int64_t)vm->data->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->data->data + vm->data->len) { + scf_loge("addr: %#lx, %#lx\n", addr, (int64_t)vm->data->data + vm->data->len); + return -1; + } + + } else if (addr >= (int64_t)vm->rodata->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->rodata->data + vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= (int64_t)vm->text->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->text->data + vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x800000) { + data = vm->data->data; + offset = addr - vm->data->addr; + + if (offset >= vm->data->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x600000) { + data = vm->rodata->data; + offset = addr - vm->rodata->addr; + + if (offset >= vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x400000) { + data = vm->text->data; + offset = addr - vm->text->addr; + + if (offset >= vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else { + data = naja->stack; + offset = addr; + } + + offset += (naja->regs[ri] << u7); + + if (data == naja->stack) { + offset = -offset; + + assert(offset >= 0); + + if (naja->size < offset) { + scf_loge("\n"); + return -1; + } + + offset -= 1 << (ext & 0x3); + } + + switch (ext) { + case 0: + printf("ldrb r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + naja->regs[rd] = *(uint8_t*)(data + offset); + break; + + case 1: + printf("ldrw r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + naja->regs[rd] = *(uint16_t*)(data + offset); + break; + + case 2: + printf("ldrl r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + naja->regs[rd] = *(uint32_t*)(data + offset); + break; + + case 3: + printf("ldr r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + naja->regs[rd] = *(uint64_t*)(data + offset); + break; + + case 4: + printf("ldrsb r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + naja->regs[rd] = *(int8_t*)(data + offset); + break; + + case 5: + printf("ldrsw r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + naja->regs[rd] = *(int16_t*)(data + offset); + break; + + case 6: + printf("ldrsl r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + naja->regs[rd] = *(int32_t*)(data + offset); + break; + default: + scf_loge("\n"); + return -1; + break; + }; + + naja->ip += 4; + return 0; +} + +static int __naja_str_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int A = (inst >> 20) & 0x1; + int ext = (inst >> 17) & 0x3; + int s12 = (inst >> 5) & 0xfff; + + if (s12 & 0x800) + s12 |= 0xfffff000; + + int64_t addr = naja->regs[rb]; + int64_t offset = 0; + uint8_t* data; + + if (addr >= (int64_t)vm->data->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->data->data + vm->data->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= (int64_t)vm->rodata->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->rodata->data + vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= (int64_t)vm->text->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->text->data + vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x800000) { + data = vm->data->data; + offset = addr - vm->data->addr; + + scf_loge("rb: %d, offset: %ld, addr: %#lx, %#lx\n", rb, offset, addr, vm->data->addr); + + if (offset >= vm->data->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x600000) { + data = vm->rodata->data; + offset = addr - vm->rodata->addr; + + if (offset >= vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x400000) { + data = vm->text->data; + offset = addr - vm->text->addr; + + if (offset >= vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else { + data = naja->stack; + offset = addr; + } + + offset += s12 << ext; + + if (data == naja->stack) { + offset = -offset; + + scf_logd("offset0: %ld, size: %ld\n", offset, naja->size); + + assert(offset > 0); + + if (naja->size < offset) { + data = realloc(naja->stack, offset + STACK_INC); + if (!data) + return -ENOMEM; + + naja->stack = data; + naja->size = offset + STACK_INC; + } + + offset -= 1 << ext; + } + + switch (ext) { + case 0: + *(uint8_t*)(data + offset) = naja->regs[rd]; + if (A) { + naja->regs[rb] += s12; + printf("strb r%d, [r%d, %d]!\n", rd, rb, s12); + } else + printf("strb r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 1: + *(uint16_t*)(data + offset) = naja->regs[rd]; + if (A) { + naja->regs[rb] += s12 << 1; + printf("strw r%d, [r%d, %d]!\n", rd, rb, s12 << 1); + } else + printf("strw r%d, [r%d, %d]\n", rd, rb, s12 << 1); + break; + + case 2: + *(uint32_t*)(data + offset) = naja->regs[rd]; + if (A) { + naja->regs[rb] += s12 << 2; + printf("strl r%d, [r%d, %d]!\n", rd, rb, s12 << 2); + } else + printf("strl r%d, [r%d, %d], %d, %p\n", rd, rb, s12 << 2, *(uint32_t*)(data + offset), data + offset); + break; + + case 3: + *(uint64_t*)(data + offset) = naja->regs[rd]; + if (A) { + naja->regs[rb] += s12 << 3; + printf("str r%d, [r%d, %d]!, rd: %#lx, rb: %ld, %p\n", rd, rb, s12 << 3, naja->regs[rd], naja->regs[rb], data + offset); + } else + printf("str r%d, [r%d, %d]\n", rd, rb, s12 << 3); + break; + + default: + scf_loge("\n"); + return -1; + break; + }; + + naja->ip += 4; + return 0; +} + +static int __naja_str_sib(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int ri = (inst >> 5) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int ext = (inst >> 17) & 0x3; + int u7 = (inst >> 10) & 0x7f; + + uint64_t addr = naja->regs[rb]; + uint64_t offset = 0; + uint8_t* data; + + if (addr >= (int64_t)vm->data->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->data->data + vm->data->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= (int64_t)vm->rodata->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->rodata->data + vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= (int64_t)vm->text->data) { + data = (uint8_t*)addr; + + if (addr >= (int64_t)vm->text->data + vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x800000) { + data = vm->data->data; + offset = addr - vm->data->addr; + + if (offset >= vm->data->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x600000) { + data = vm->rodata->data; + offset = addr - vm->rodata->addr; + + if (offset >= vm->rodata->len) { + scf_loge("\n"); + return -1; + } + + } else if (addr >= 0x400000) { + data = vm->text->data; + offset = addr - vm->text->addr; + + if (offset >= vm->text->len) { + scf_loge("\n"); + return -1; + } + + } else { + data = naja->stack; + offset = addr; + } + + offset += naja->regs[ri] << u7; + + if (data == naja->stack) { + offset = -offset; + + assert(offset >= 0); + + if (naja->size < offset) { + scf_loge("\n"); + return -1; + } + + offset -= 1 << ext; + } + + switch (ext) { + case 0: + printf("strb r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + *(uint8_t*)(data + offset) = naja->regs[rd]; + break; + + case 1: + printf("strw r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + *(uint16_t*)(data + offset) = naja->regs[rd]; + break; + + case 2: + printf("strl r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + *(uint32_t*)(data + offset) = naja->regs[rd]; + break; + + case 3: + printf("str r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + + *(uint64_t*)(data + offset) = naja->regs[rd]; + break; + + default: + scf_loge("\n"); + return -1; + break; + }; + + naja->ip += 4; + return 0; +} + +static int __naja_and(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + scf_logw("\n"); + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + naja->regs[rd] = naja->regs[rs0] & uimm15; + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + uint64_t rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + naja->regs[rd] = naja->regs[rs0] & (naja->regs[rs1] << uimm8); + else if (1 == sh) + naja->regs[rd] = naja->regs[rs0] & (naja->regs[rs1] >> uimm8); + else + naja->regs[rd] = naja->regs[rs0] & (((int64_t)naja->regs[rs1]) >> uimm8); + } + + naja->ip += 4; + return 0; +} + +static int __naja_teq(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + scf_logw("\n"); + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + naja->flags = naja->regs[rs0] & uimm15; + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + uint64_t rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + naja->flags = naja->regs[rs0] & (naja->regs[rs1] << uimm8); + else if (1 == sh) + naja->flags = naja->regs[rs0] & (naja->regs[rs1] >> uimm8); + else + naja->flags = naja->regs[rs0] & (((int64_t)naja->regs[rs1]) >> uimm8); + } + + naja->flags = !naja->flags; + + naja->ip += 4; + return 0; +} + +static int __naja_or(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + scf_logw("\n"); + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + naja->regs[rd] = naja->regs[rs0] | uimm15; + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + uint64_t rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + naja->regs[rd] = naja->regs[rs0] | (naja->regs[rs1] << uimm8); + else if (1 == sh) + naja->regs[rd] = naja->regs[rs0] | (naja->regs[rs1] >> uimm8); + else + naja->regs[rd] = naja->regs[rs0] | (((int64_t)naja->regs[rs1]) >> uimm8); + } + + naja->ip += 4; + return 0; +} + +static int __naja_jmp_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int simm26 = inst & 0x3ffffff; + + if (simm26 & 0x2000000) + simm26 |= 0xfc000000; + + naja->ip += simm26 << 2; + printf("jmp %#lx\n", naja->ip); + return 0; +} + +static int __naja_call_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int simm26 = inst & 0x3ffffff; + + if (simm26 & 0x2000000) + simm26 |= 0xfc000000; + + naja->regs[NAJA_REG_LR] = naja->ip + 4; + + naja->ip += simm26 << 2; + + printf("call %#lx\n", naja->ip); + return 0; +} + +static int __naja_jmp_reg(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + if (inst & 0x1) { + + int cc = (inst >> 1) & 0xf; + int s21 = (inst >> 5) & 0x1fffff; + + if (s21 & 0x100000) + s21 |= 0xffe00000; + + s21 <<= 2; + + if (0 == (cc & naja->flags)) + naja->ip += s21; + else + naja->ip += 4; + + if (0 == cc) + printf("jz %#lx, flags: %#lx\n", naja->ip, naja->flags); + + else if (1 == cc) + printf("jnz %#lx, flags: %#lx\n", naja->ip, naja->flags); + + else if (2 == cc) + printf("jge %#lx, flags: %#lx\n", naja->ip, naja->flags); + + else if (3 == cc) + printf("jgt %#lx, flags: %#lx\n", naja->ip, naja->flags); + + else if (4 == cc) + printf("jle %#lx, flags: %#lx\n", naja->ip, naja->flags); + + else if (5 == cc) + printf("jlt %#lx, flags: %#lx\n", naja->ip, naja->flags); + else { + scf_loge("\n"); + return -EINVAL; + } + + } else { + int rd = (inst >> 21) & 0x1f; + + if (naja_vm_dynamic_link == (void*)naja->regs[rd]) { + + printf("\033[36mjmp r%d, %#lx@plt\033[0m\n", rd, naja->regs[rd]); + + int ret = naja_vm_dynamic_link(vm); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + + naja->ip = naja->regs[NAJA_REG_LR]; + + } else if (naja->regs[rd] < vm->text->addr + || naja->regs[rd] > vm->text->addr + vm->text->len) { + + printf("\033[36mjmp r%d, %#lx@plt\033[0m\n", rd, naja->regs[rd]); + + naja_dyn_func_pt pt = (naja_dyn_func_pt) naja->regs[rd]; + + naja->regs[0] = pt(naja->regs[0], + naja->regs[1], + naja->regs[2], + naja->regs[3], + naja->regs[4], + naja->regs[5], + naja->regs[6], + naja->regs[7]); + + naja->ip = naja->regs[NAJA_REG_LR]; + } else { + naja->ip = naja->regs[rd]; + + printf("jmp r%d, %#lx\n", rd, naja->regs[rd]); + } + } + + return 0; +} + + +static int __naja_call_reg(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + + naja->regs[NAJA_REG_LR] = naja->ip + 4; + + if (naja_vm_dynamic_link == (void*)naja->regs[rd]) { + + printf("\033[36mcall r%d, %#lx@plt\033[0m\n", rd, naja->regs[rd]); + + int ret = naja_vm_dynamic_link(vm); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + + naja->ip = naja->regs[NAJA_REG_LR]; + + } else if (naja->regs[rd] < vm->text->addr + || naja->regs[rd] > vm->text->addr + vm->text->len) { + + printf("\033[36mcall r%d, %#lx@plt\033[0m\n", rd, naja->regs[rd]); + + naja_dyn_func_pt pt = (naja_dyn_func_pt) naja->regs[rd]; + + naja->regs[0] = pt(naja->regs[0], + naja->regs[1], + naja->regs[2], + naja->regs[3], + naja->regs[4], + naja->regs[5], + naja->regs[6], + naja->regs[7]); + + naja->ip = naja->regs[NAJA_REG_LR]; + } else { + printf("call r%d, %#lx\n", rd, naja->regs[rd]); + naja->ip = naja->regs[rd]; + } + + return 0; +} + +static int __naja_adrp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + int s21 = inst & 0x1fffff; + + if (s21 & 0x100000) + s21 |= ~0x1fffff; + + naja->regs[rd] = (naja->ip + ((int64_t)s21 << 15)) & ~0x7fffULL; + + if (naja->regs[rd] >= 0x800000) + naja->regs[rd] = naja->regs[rd] - vm->data->addr + (uint64_t)vm->data->data; + + else if (naja->regs[rd] >= 0x600000) + naja->regs[rd] = naja->regs[rd] - vm->rodata->addr + (uint64_t)vm->rodata->data; + + else if (naja->regs[rd] >= 0x400000) + naja->regs[rd] = naja->regs[rd] - vm->text->addr + (uint64_t)vm->text->data; + + printf("adrp r%d, [rip, %d], %#lx\n", rd, s21, naja->regs[rd]); + + naja->ip += 4; + return 0; +} + +static int __naja_ret(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + naja->ip = naja->regs[NAJA_REG_LR]; + int64_t sp = -naja->regs[NAJA_REG_SP]; + + assert (sp >= 0); + + if (naja->size > sp + STACK_INC) { + + void* p = realloc(naja->stack, sp + STACK_INC); + if (!p) { + scf_loge("\n"); + return -ENOMEM; + } + + naja->stack = p; + naja->size = sp + STACK_INC; + } + + printf("ret, %#lx, sp: %ld, stack->size: %ld\n", naja->ip, sp, naja->size); + return 0; +} + +static int __naja_setcc(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + int cc = (inst >> 17) & 0xf; + + naja->regs[rd] = 0 == (cc & naja->flags); + + if (SCF_VM_Z == cc) + printf("setz r%d\n", rd); + + else if (SCF_VM_NZ == cc) + printf("setnz r%d\n", rd); + + else if (SCF_VM_GE == cc) + printf("setge r%d\n", rd); + + else if (SCF_VM_GT == cc) + printf("setgt r%d\n", rd); + + else if (SCF_VM_LT == cc) + printf("setlt r%d\n", rd); + + else if (SCF_VM_LE == cc) + printf("setle r%d\n", rd); + else { + scf_loge("inst: %#x\n", inst); + return -EINVAL; + } + + naja->ip += 4; + return 0; +} + +static int __naja_mov(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + int X = (inst >> 19) & 0x1; + int opt = (inst >> 16) & 0x7; + + if (I) { + if (0 == opt) { + naja->regs[rd] = inst & 0xffff; + + if (X && (inst & 0x8000)) { + naja->regs[rd] |= ~0xffffULL; + printf("movsb r%d, %d\n", rd, inst & 0xffff); + } else { + printf("mov r%d, %d\n", rd, inst & 0xffff); + } + + } else if (1 == opt) { + naja->regs[rd] |= (inst & 0xffffULL) << 16; + + printf("mov r%d, %d << 16\n", rd, inst & 0xffff); + + } else if (2 == opt) { + naja->regs[rd] |= (inst & 0xffffULL) << 32; + + printf("mov r%d, %d << 32\n", rd, inst & 0xffff); + + } else if (3 == opt) { + naja->regs[rd] |= (inst & 0xffffULL) << 48; + + printf("mov r%d, %d << 48\n", rd, inst & 0xffff); + + } else if (7 == opt) { + naja->regs[rd] = ~(inst & 0xffffULL); + + printf("mvn r%d, %d\n", rd, inst & 0xffff); + } + + } else { + int rs = inst & 0x1f; + int rs1 = (inst >> 5) & 0x1f; + int u11 = (inst >> 5) & 0x7ff; + + if (0 == opt) { + if (X) { + printf("mov r%d, r%d LSL r%d\n", rd, rs, rs1); + + naja->regs[rd] = naja->regs[rs] << naja->regs[rs1]; + } else { + naja->regs[rd] = naja->regs[rs] << u11; + + if (0 == u11) + printf("mov r%d, r%d\n", rd, rs); + else + printf("mov r%d, r%d LSL %d\n", rd, rs, u11); + } + + } else if (1 == opt) { + if (X) { + printf("mov r%d, r%d LSR r%d\n", rd, rs, rs1); + + naja->regs[rd] = naja->regs[rs] >> naja->regs[rs1]; + } else { + naja->regs[rd] = naja->regs[rs] >> u11; + + if (0 == u11) + printf("mov r%d, r%d\n", rd, rs); + else + printf("mov r%d, r%d LSR %d\n", rd, rs, u11); + } + } else if (2 == opt) { + if (X) { + printf("mov r%d, r%d ASR r%d\n", rd, rs, rs1); + + naja->regs[rd] = (int64_t)naja->regs[rs] >> naja->regs[rs1]; + } else { + naja->regs[rd] = (int64_t)naja->regs[rs] >> u11; + + if (0 == u11) + printf("mov r%d, r%d\n", rd, rs); + else + printf("mov r%d, r%d ASR %d\n", rd, rs, u11); + } + } else if (3 == opt) { + printf("NOT r%d, r%d\n", rd, rs); + + naja->regs[rd] = ~naja->regs[rs]; + } else if (4 == opt) { + naja->regs[rd] = -naja->regs[rs]; + + printf("NEG r%d, r%d\n", rd, rs); + + } else if (5 == opt) { + if (X) { + printf("movsb r%d, r%d\n", rd, rs); + + naja->regs[rd] = (int8_t)naja->regs[rs]; + } else { + naja->regs[rd] = (uint8_t)naja->regs[rs]; + + printf("movzb r%d, r%d\n", rd, rs); + } + } else if (6 == opt) { + if (X) { + printf("movsw r%d, r%d\n", rd, rs); + + naja->regs[rd] = (int16_t)naja->regs[rs]; + } else { + naja->regs[rd] = (uint16_t)naja->regs[rs]; + + printf("movzw r%d, r%d\n", rd, rs); + } + } else if (7 == opt) { + if (X) { + printf("movsl r%d, r%d\n", rd, rs); + + naja->regs[rd] = (int32_t)naja->regs[rs]; + } else { + naja->regs[rd] = (uint32_t)naja->regs[rs]; + + printf("movzl r%d, r%d\n", rd, rs); + } + } + } + + naja->ip += 4; + return 0; +} + +static naja_opcode_pt naja_opcodes[64] = +{ + __naja_add, // 0 + __naja_sub, // 1 + __naja_mul, // 2 + __naja_div, // 3 + __naja_ldr_disp, // 4 + __naja_str_disp, // 5 + __naja_and, // 6 + __naja_or, // 7 + __naja_jmp_disp, // 8 + __naja_cmp, // 9 + __naja_jmp_reg, //10 + __naja_setcc, //11 + __naja_ldr_sib, //12 + __naja_str_sib, //13 + __naja_teq, //14 + __naja_mov, //15 + + NULL, //16 + NULL, //17 + NULL, //18 + NULL, //19 + NULL, //20 + NULL, //21 + NULL, //22 + NULL, //23 + __naja_call_disp,//24 + NULL, //25 + __naja_call_reg, //26 + NULL, //27 + NULL, //28 + NULL, //29 + NULL, //30 + NULL, //31 + + NULL, //32 + NULL, //33 + NULL, //34 + NULL, //35 + NULL, //36 + NULL, //37 + NULL, //38 + NULL, //39 + NULL, //40 + NULL, //41 + __naja_adrp, //42 + NULL, //43 + NULL, //44 + NULL, //45 + NULL, //46 + NULL, //47 + + NULL, //48 + NULL, //49 + NULL, //50 + NULL, //51 + NULL, //52 + NULL, //53 + NULL, //54 + NULL, //55 + __naja_ret, //56 + NULL, //57 + NULL, //58 + NULL, //59 + NULL, //60 + NULL, //61 + NULL, //62 + NULL, //63 +}; + +static void __naja_vm_exit() +{ +} + +static int __naja_vm_run(scf_vm_t* vm, const char* path, const char* sys) +{ + scf_vm_naja_t* naja = vm->priv; + Elf64_Ehdr eh; + Elf64_Shdr sh; + + fseek(vm->elf->fp, 0, SEEK_SET); + + int ret = fread(&eh, sizeof(Elf64_Ehdr), 1, vm->elf->fp); + if (ret != 1) + return -1; + + if (vm->jmprel) { + fseek(vm->elf->fp, eh.e_shoff, SEEK_SET); + + int i; + for (i = 0; i < eh.e_shnum; i++) { + + ret = fread(&sh, sizeof(Elf64_Shdr), 1, vm->elf->fp); + if (ret != 1) + return -1; + + if (vm->jmprel_addr == sh.sh_addr) { + vm->jmprel_size = sh.sh_size; + break; + } + } + + if (i == eh.e_shnum) { + scf_loge("\n"); + return -1; + } + } + + naja->stack = calloc(STACK_INC, sizeof(uint64_t)); + if (!naja->stack) + return -ENOMEM; + + naja->size = STACK_INC; + naja->_start = eh.e_entry; + naja->ip = eh.e_entry; + + naja->regs[NAJA_REG_LR] = (uint64_t)__naja_vm_exit; + + int n = 0; + while ((uint64_t)__naja_vm_exit != naja->ip) { + + int64_t offset = naja->ip - vm->text->addr; + + if (offset >= vm->text->len) { + scf_loge("naja->ip: %#lx, %p\n", naja->ip, __naja_vm_exit); + return -1; + } + + uint32_t inst = *(uint32_t*)(vm->text->data + offset); + + naja_opcode_pt pt = naja_opcodes[(inst >> 26) & 0x3f]; + + if (!pt) { + scf_loge("inst: %d, %#x\n", (inst >> 26) & 0x3f, inst); + return -EINVAL; + } + + printf("%4d, %#lx: ", n++, naja->ip); + ret = pt(vm, inst); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + + usleep(50 * 1000); + } + + scf_logw("r0: %ld\n", naja->regs[0]); + return naja->regs[0]; +} + +static int naja_vm_run(scf_vm_t* vm, const char* path, const char* sys) +{ + int ret = naja_vm_init(vm, path, sys); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + + return __naja_vm_run(vm, path, sys); +} + +scf_vm_ops_t vm_ops_naja = +{ + .name = "naja", + .open = naja_vm_open, + .close = naja_vm_close, + .run = naja_vm_run, +}; + diff --git a/vm/scf_vm_naja_asm.c b/vm/scf_vm_naja_asm.c new file mode 100644 index 0000000..828096e --- /dev/null +++ b/vm/scf_vm_naja_asm.c @@ -0,0 +1,808 @@ +#include"scf_vm.h" + +#define NAJA_REG_FP 29 +#define NAJA_REG_LR 30 +#define NAJA_REG_SP 31 + +static int __naja_add(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + printf("add r%d, r%d, %lu\n", rd, rs0, uimm15); + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + printf("add r%d, r%d, r%d LSL %lu\n", rd, rs0, rs1, uimm8); + else if (1 == sh) + printf("add r%d, r%d, r%d LSR %lu\n", rd, rs0, rs1, uimm8); + else + printf("add r%d, r%d, r%d ASR %lu\n", rd, rs0, rs1, uimm8); + } + + return 0; +} + +static int __naja_sub(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + printf("sub r%d, r%d, %lu\n", rd, rs0, uimm15); + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + printf("sub r%d, r%d, r%d << %lu\n", rd, rs0, rs1, uimm8); + else if (1 == sh) + printf("sub r%d, r%d, r%d LSR %lu\n", rd, rs0, rs1, uimm8); + else + printf("sub r%d, r%d, r%d ASR %lu\n", rd, rs0, rs1, uimm8); + } + + return 0; +} + +static int __naja_cmp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + int ret = 0; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + printf("cmp r%d, %ld, rs0: %lx, ret: %d\n", rs0, uimm15, naja->regs[rs0], ret); + } else { + uint64_t sh = (inst >> 18) & 0x3; + uint64_t uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + printf("cmp r%d, r%d LSL %ld, rs0: %#lx, rs1: %#lx, ret: %d\n", rs0, rs1, uimm8, naja->regs[rs0], naja->regs[rs1], ret); + else if (1 == sh) + printf("cmp r%d, r%d LSR %ld, rs0: %#lx, rs1: %#lx, ret: %d\n", rs0, rs1, uimm8, naja->regs[rs0], naja->regs[rs1], ret); + else + printf("cmp r%d, r%d ASR %ld, rs0: %#lx, rs1: %ld, ret: %d\n", rs0, rs1, uimm8, naja->regs[rs0], naja->regs[rs1], ret); + } + + return 0; +} + +static int __naja_mul(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rs1 = (inst >> 5) & 0x1f; + int rs2 = (inst >> 10) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int S = (inst >> 20) & 0x1; + int opt = (inst >> 15) & 0x3; + + if (S) { + if (0 == opt) + printf("smadd r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else if (1 == opt) + printf("smsub r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else + printf("smul r%d, r%d, r%d\n", rd, rs0, rs1); + } else { + if (0 == opt) + printf("madd r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else if (1 == opt) + printf("msub r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else + printf("mul r%d, r%d, r%d\n", rd, rs0, rs1); + } + + return 0; +} + +static int __naja_div(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rs1 = (inst >> 5) & 0x1f; + int rs2 = (inst >> 10) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int S = (inst >> 20) & 0x1; + int opt = (inst >> 15) & 0x3; + + if (S) { + if (0 == opt) + printf("sdadd r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else if (1 == opt) + printf("sdsub r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else + printf("sdiv r%d, r%d, r%d\n", rd, rs0, rs1); + } else { + if (0 == opt) + printf("dadd r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else if (1 == opt) + printf("dsub r%d, r%d, r%d, r%d\n", rd, rs2, rs0, rs1); + else + printf("div r%d, r%d, r%d\n", rd, rs0, rs1); + } + + return 0; +} + +static int __naja_ldr_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int A = (inst >> 20) & 0x1; + int ext = (inst >> 17) & 0x7; + int s12 = (inst >> 5) & 0xfff; + + if (s12 & 0x800) + s12 |= 0xfffff000; + + switch (ext) { + case 0: + if (A) + printf("ldrb r%d, [r%d, %d]!\n", rd, rb, s12); + else + printf("ldrb r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 1: + if (A) + printf("ldrw r%d, [r%d, %d]!\n", rd, rb, s12 << 1); + else + printf("ldrw r%d, [r%d, %d]\n", rd, rb, s12 << 1); + break; + + case 2: + if (A) + printf("ldrl r%d, [r%d, %d]!\n", rd, rb, s12 << 2); + else + printf("ldrl r%d, [r%d, %d]\n", rd, rb, s12 << 2); + break; + + case 3: + if (A) + printf("ldr r%d, [r%d, %d]!\n", rd, rb, s12 << 3); + else + printf("ldr r%d, [r%d, %d]\n", rd, rb, s12 << 3); + break; + + case 4: + if (A) + printf("ldrsb r%d, [r%d, %d]!\n", rd, rb, s12); + else + printf("ldrsb r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 5: + if (A) + printf("ldrsw r%d, [r%d, %d]!\n", rd, rb, s12 << 1); + else + printf("ldrsw r%d, [r%d, %d]\n", rd, rb, s12 << 1); + break; + + case 6: + if (A) + printf("ldrsl r%d, [r%d, %d]!\n", rd, rb, s12 << 2); + else + printf("ldrsl r%d, [r%d, %d]\n", rd, rb, s12 << 2); + break; + default: + scf_loge("\n"); + return -1; + break; + }; + + return 0; +} + +static int __naja_ldr_sib(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int ri = (inst >> 5) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int ext = (inst >> 17) & 0x7; + int u7 = (inst >> 10) & 0x7f; + + switch (ext) { + case 0: + printf("ldrb r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 1: + printf("ldrw r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 2: + printf("ldrl r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 3: + printf("ldr r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 4: + printf("ldrsb r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 5: + printf("ldrsw r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 6: + printf("ldrsl r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + default: + scf_loge("\n"); + return -1; + break; + }; + + return 0; +} + +static int __naja_str_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int A = (inst >> 20) & 0x1; + int ext = (inst >> 17) & 0x3; + int s12 = (inst >> 5) & 0xfff; + + if (s12 & 0x800) + s12 |= 0xfffff000; + + switch (ext) { + case 0: + if (A) + printf("strb r%d, [r%d, %d]!\n", rd, rb, s12); + else + printf("strb r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 1: + if (A) + printf("strw r%d, [r%d, %d]!\n", rd, rb, s12); + else + printf("strw r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 2: + if (A) + printf("strl r%d, [r%d, %d]!\n", rd, rb, s12); + else + printf("strl r%d, [r%d, %d]\n", rd, rb, s12); + break; + + case 3: + if (A) + printf("str r%d, [r%d, %d]!\n", rd, rb, s12 << 3); + else + printf("str r%d, [r%d, %d]\n", rd, rb, s12 << 3); + break; + + default: + scf_loge("\n"); + return -1; + break; + }; + + return 0; +} + +static int __naja_str_sib(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rb = inst & 0x1f; + int ri = (inst >> 5) & 0x1f; + int rd = (inst >> 21) & 0x1f; + int ext = (inst >> 17) & 0x7; + int u7 = (inst >> 10) & 0x7f; + + switch (ext) { + case 0: + printf("strb r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 1: + printf("strw r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 2: + printf("strl r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + case 3: + printf("str r%d, [r%d, r%d, %d]\n", rd, rb, ri, u7); + break; + + default: + scf_loge("\n"); + return -1; + break; + }; + + return 0; +} + +static int __naja_and(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + printf("and r%d, r%d, %#lx\n", rd, rs0, uimm15); + } else { + int sh = (inst >> 18) & 0x3; + int uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + printf("and r%d, r%d, r%d LSL %#x\n", rd, rs0, rs1, uimm8); + else if (1 == sh) + printf("and r%d, r%d, r%d LSR %#x\n", rd, rs0, rs1, uimm8); + else + printf("and r%d, r%d, r%d ASR %#x\n", rd, rs0, rs1, uimm8); + } + + return 0; +} + +static int __naja_teq(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + printf("teq r%d, %#lx\n", rs0, uimm15); + } else { + int sh = (inst >> 18) & 0x3; + int uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + printf("teq r%d, r%d LSL %#x\n", rs0, rs1, uimm8); + else if (1 == sh) + printf("teq r%d, r%d LSR %#x\n", rs0, rs1, uimm8); + else + printf("teq r%d, r%d ASR %#x\n", rs0, rs1, uimm8); + } + + return 0; +} + +static int __naja_or(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rs0 = inst & 0x1f; + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + + if (I) { + uint64_t uimm15 = (inst >> 5) & 0x7fff; + + printf("or r%d, r%d, %#lx\n", rd, rs0, uimm15); + } else { + int sh = (inst >> 18) & 0x3; + int uimm8 = (inst >> 10) & 0xff; + int rs1 = (inst >> 5) & 0x1f; + + if (0 == sh) + printf("or r%d, r%d, r%d LSL %#x\n", rd, rs0, rs1, uimm8); + else if (1 == sh) + printf("or r%d, r%d, r%d LSR %#x\n", rd, rs0, rs1, uimm8); + else + printf("or r%d, r%d, r%d ASR %#x\n", rd, rs0, rs1, uimm8); + } + + return 0; +} + +static int __naja_jmp_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int simm26 = inst & 0x3ffffff; + + if (simm26 & 0x2000000) + simm26 |= 0xfc000000; + + uint64_t ip = naja->ip + (simm26 << 2); + printf("jmp %#lx\n", ip); + return 0; +} + +static int __naja_call_disp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int simm26 = inst & 0x3ffffff; + + if (simm26 & 0x2000000) + simm26 |= 0xfc000000; + + uint64_t ip = naja->ip + (simm26 << 2); + printf("call %#lx\n", ip); + return 0; +} + +static int __naja_jmp_reg(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + if (inst & 0x1) { + + int cc = (inst >> 1) & 0xf; + int s21 = (inst >> 5) & 0x1fffff; + + if (s21 & 0x100000) + s21 |= 0xffe00000; + + s21 <<= 2; + + uint64_t ip = naja->ip + s21; + + if (0 == cc) + printf("jz %#lx\n", ip); + + else if (1 == cc) + printf("jnz %#lx\n", ip); + + else if (2 == cc) + printf("jge %#lx\n", ip); + + else if (3 == cc) + printf("jgt %#lx\n", ip); + + else if (4 == cc) + printf("jle %#lx\n", ip); + + else if (5 == cc) + printf("jlt %#lx\n", ip); + else { + scf_loge("\n"); + return -EINVAL; + } + + } else { + int rd = (inst >> 21) & 0x1f; + + printf("jmp *r%d\n", rd); + } + return 0; +} + + +static int __naja_call_reg(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + + printf("call r%d\n", rd); + + return 0; +} + +static int __naja_adrp(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + int s21 = inst & 0x1fffff; + + if (s21 & 0x100000) + s21 |= ~0x1fffff; + + printf("adrp r%d, [rip, %d]\n", rd, s21); + + return 0; +} + +static int __naja_ret(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + printf("ret\n"); + return 0; +} + +static int __naja_setcc(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + int cc = (inst >> 17) & 0xf; + + if (SCF_VM_Z == cc) + printf("setz r%d\n", rd); + + else if (SCF_VM_NZ == cc) + printf("setnz r%d\n", rd); + + else if (SCF_VM_GE == cc) + printf("setge r%d\n", rd); + + else if (SCF_VM_GT == cc) + printf("setgt r%d\n", rd); + + else if (SCF_VM_LT == cc) + printf("setlt r%d\n", rd); + + else if (SCF_VM_LE == cc) + printf("setle r%d\n", rd); + else { + scf_loge("inst: %#x\n", inst); + return -EINVAL; + } + + return 0; +} + +static int __naja_mov(scf_vm_t* vm, uint32_t inst) +{ + scf_vm_naja_t* naja = vm->priv; + + int rd = (inst >> 21) & 0x1f; + int I = (inst >> 20) & 0x1; + int X = (inst >> 19) & 0x1; + int opt = (inst >> 16) & 0x7; + + if (I) { + if (0 == opt) { + if (X && (inst & 0x8000)) + printf("movsb r%d, %d\n", rd, inst & 0xffff); + else + printf("mov r%d, %d\n", rd, inst & 0xffff); + + } else if (1 == opt) + printf("mov r%d, %d << 16\n", rd, inst & 0xffff); + else if (2 == opt) + printf("mov r%d, %d << 32\n", rd, inst & 0xffff); + else if (3 == opt) + printf("mov r%d, %d << 48\n", rd, inst & 0xffff); + else if (7 == opt) + printf("mvn r%d, %d\n", rd, inst & 0xffff); + + } else { + int rs = inst & 0x1f; + int rs1 = (inst >> 5) & 0x1f; + int u11 = (inst >> 5) & 0x7ff; + + if (0 == opt) { + if (X) + printf("mov r%d, r%d LSL r%d\n", rd, rs, rs1); + else { + if (0 == u11) + printf("mov r%d, r%d\n", rd, rs); + else + printf("mov r%d, r%d LSL %d\n", rd, rs, u11); + } + } else if (1 == opt) { + if (X) + printf("mov r%d, r%d LSR r%d\n", rd, rs, rs1); + else { + if (0 == u11) + printf("mov r%d, r%d\n", rd, rs); + else + printf("mov r%d, r%d LSR %d\n", rd, rs, u11); + } + + } else if (2 == opt) { + if (X) + printf("mov r%d, r%d ASR r%d\n", rd, rs, rs1); + else { + if (0 == u11) + printf("mov r%d, r%d\n", rd, rs); + else + printf("mov r%d, r%d ASR %d\n", rd, rs, u11); + } + + } else if (3 == opt) + printf("NOT r%d, r%d\n", rd, rs); + else if (4 == opt) + printf("NEG r%d, r%d\n", rd, rs); + + else if (5 == opt) { + if (X) + printf("movsb r%d, r%d\n", rd, rs); + else + printf("movzb r%d, r%d\n", rd, rs); + + } else if (6 == opt) { + if (X) + printf("movsw r%d, r%d\n", rd, rs); + else + printf("movzw r%d, r%d\n", rd, rs); + + } else if (7 == opt) { + if (X) + printf("movsl r%d, r%d\n", rd, rs); + else + printf("movzl r%d, r%d\n", rd, rs); + } + } + + return 0; +} + +static naja_opcode_pt naja_opcodes[64] = +{ + __naja_add, // 0 + __naja_sub, // 1 + __naja_mul, // 2 + __naja_div, // 3 + __naja_ldr_disp, // 4 + __naja_str_disp, // 5 + __naja_and, // 6 + __naja_or, // 7 + __naja_jmp_disp, // 8 + __naja_cmp, // 9 + __naja_jmp_reg, //10 + __naja_setcc, //11 + __naja_ldr_sib, //12 + __naja_str_sib, //13 + __naja_teq, //14 + __naja_mov, //15 + + NULL, //16 + NULL, //17 + NULL, //18 + NULL, //19 + NULL, //20 + NULL, //21 + NULL, //22 + NULL, //23 + __naja_call_disp,//24 + NULL, //25 + __naja_call_reg, //26 + NULL, //27 + NULL, //28 + NULL, //29 + NULL, //30 + NULL, //31 + + NULL, //32 + NULL, //33 + NULL, //34 + NULL, //35 + NULL, //36 + NULL, //37 + NULL, //38 + NULL, //39 + NULL, //40 + NULL, //41 + __naja_adrp, //42 + NULL, //43 + NULL, //44 + NULL, //45 + NULL, //46 + NULL, //47 + + NULL, //48 + NULL, //49 + NULL, //50 + NULL, //51 + NULL, //52 + NULL, //53 + NULL, //54 + NULL, //55 + __naja_ret, //56 + NULL, //57 + NULL, //58 + NULL, //59 + NULL, //60 + NULL, //61 + NULL, //62 + NULL, //63 +}; + +static int __naja_vm_run(scf_vm_t* vm, const char* path, const char* sys) +{ + scf_elf_sym_t* s; + scf_vm_naja_t* naja = vm->priv; + scf_vector_t* syms = scf_vector_alloc(); + if (!syms) + return -ENOMEM; + + int ret = scf_elf_read_syms(vm->elf, syms, ".symtab"); + if (ret < 0) + return ret; + + int i; + for (i = 0; i < syms->size; i++) { + s = syms->data[i]; + + if (ELF64_ST_TYPE(s->st_info) != STT_FUNC) + continue; + + int64_t offset = s->st_value - vm->text->addr; + + if (offset >= vm->text->len) + return -1; + + printf("\n%s: \n", s->name); + int j; + for (j = 0; j < s->st_size; j+= 4) { + + uint32_t inst = *(uint32_t*)(vm->text->data + offset + j); + + naja_opcode_pt pt = naja_opcodes[(inst >> 26) & 0x3f]; + + if (!pt) { + scf_loge("inst: %d, %#x\n", (inst >> 26) & 0x3f, inst); + continue; + } + + naja->ip = vm->text->addr + offset + j; + + printf("%4d, %#lx: ", j, naja->ip); + + ret = pt(vm, inst); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + } + } + + return 0; +} + +static int naja_vm_run(scf_vm_t* vm, const char* path, const char* sys) +{ + int ret = naja_vm_init(vm, path, sys); + if (ret < 0) { + scf_loge("\n"); + return ret; + } + + return __naja_vm_run(vm, path, sys); +} + +scf_vm_ops_t vm_ops_naja_asm = +{ + .name = "naja_asm", + .open = naja_vm_open, + .close = naja_vm_close, + .run = naja_vm_run, +}; + diff --git a/vm/scf_vm_test.c b/vm/scf_vm_test.c new file mode 100644 index 0000000..d9c02b0 --- /dev/null +++ b/vm/scf_vm_test.c @@ -0,0 +1,22 @@ +#include"scf_vm.h" + +int main() +{ + scf_vm_t* vm = NULL; + + int ret = scf_vm_open(&vm, "naja"); + if (ret < 0) { + scf_loge("\n"); + return -1; + } + + ret = scf_vm_run(vm, "../parse/1.out", "x64"); + if (ret < 0) { + scf_loge("\n"); + return -1; + } + + printf("main ok\n"); + return 0; +} + -- 2.25.1