Created
April 28, 2016 11:12
-
-
Save wsuzume/6bd7b1358c7cb0af0cdc30439e76120e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include "type.h" | |
#include "rgsmap.h" | |
#include "instmake.h" | |
#define INST1(var) (var&0x000000ff) | |
#define INST2(var) (((var&0x0000ff00)>>8)|((var&0x000000ff)<<8)) | |
#define OPRND1(var) ((var>>16)&0x000000ff) | |
#define OPRND2(var) ((var>>24)&0x000000ff) | |
//intptr_t型でスタックポインタを取得 | |
#define GETCURSOL(stk,rgs) (stk+(intptr_t)(*(intptr_t *)(rgs+RSP))) | |
//intptr_t型でベースポインタを取得 | |
#define GETBASE(stk,rgs) (stk+(intptr_t)(*(intptr_t *)(rgs+RBP))) | |
//相対アドレスからオート変数のアドレスをintptr_t型で取得 | |
#define GETATVAR(stk,rgs,ptr) (intptr_t)((*(intptr_t *)(rgs+RBP))+ptr+stk) | |
#define BINARYOPERATOR(inst,rgs,type,op) \ | |
*(type *)(rgs+OPRND1(inst)) op *(type *)(rgs+OPRND2(inst)) | |
#define BASICOPERATOR(tnum,type,inst,rgs,flag,tracer) \ | |
case ADD_##tnum: BINARYOPERATOR(inst, rgs, type, +=); tracer += 4; continue; \ | |
case SUB_##tnum: BINARYOPERATOR(inst, rgs, type, -=); tracer += 4; continue; \ | |
case MUL_##tnum: BINARYOPERATOR(inst, rgs, type, *=); tracer += 4; continue; \ | |
case DIV_##tnum: BINARYOPERATOR(inst, rgs, type, /=); tracer += 4; continue; \ | |
case EQ_##tnum: flag = BINARYOPERATOR(inst, rgs, type, ==); tracer += 4; continue; \ | |
case NEQ_##tnum: flag = BINARYOPERATOR(inst, rgs, type, !=); tracer += 4; continue; \ | |
case LT_##tnum: flag = BINARYOPERATOR(inst, rgs, type, <); tracer += 4; continue; \ | |
case GT_##tnum: flag = BINARYOPERATOR(inst, rgs, type, >); tracer += 4; continue; \ | |
case LTEQ_##tnum: flag = BINARYOPERATOR(inst, rgs, type, <=); tracer += 4; continue; \ | |
case GTEQ_##tnum: flag = BINARYOPERATOR(inst, rgs, type, >=); tracer += 4; continue | |
#define BASICBITOPERATOR(tnum,type,inst,rgs,flag,tracer) \ | |
case OR##tnum: BINARYOPERATOR(inst, rgs, type, |=); tracer += 4; continue; \ | |
case XOR##tnum: BINARYOPERATOR(inst, rgs, type, ^=); tracer += 4; continue; \ | |
case AND##tnum: BINARYOPERATOR(inst, rgs, type, &=); tracer += 4; continue; \ | |
case NOT##tnum: *(type *)(rgs+OPRND1(inst)) = !(*(type *)(rgs+OPRND1(inst))); tracer += 4; continue; \ | |
case INV##tnum: *(type *)(rgs+OPRND1(inst)) = ~(*(type *)(rgs+OPRND1(inst))); tracer += 4; continue | |
#define ASSIGNOPERATOR(inst,rgs,type,op,shift) \ | |
*(type *)(rgs+OPRND1(inst)) op *(type *)(opcode+4); opcode += shift | |
#define BASICASNOPERATOR(tnum,type,inst,rgs,tracer,shift) \ | |
case ADDI_##tnum: ASSIGNOPERATOR(inst, rgs, type, +=, shift); continue; \ | |
case SUBI_##tnum: ASSIGNOPERATOR(inst, rgs, type, -=, shift); continue; \ | |
case MULI_##tnum: ASSIGNOPERATOR(inst, rgs, type, *=, shift); continue; \ | |
case DIVI_##tnum: ASSIGNOPERATOR(inst, rgs, type, /=, shift); continue | |
#define BITASNOPERATOR(tnum,type,inst,rgs,tracer,shift) \ | |
case ANDI_##tnum: ASSIGNOPERATOR(inst, rgs, type, &=, shift); continue; \ | |
case ORI_##tnum: ASSIGNOPERATOR(inst, rgs, type, |=, shift); continue; \ | |
case XORI_##tnum: ASSIGNOPERATOR(inst, rgs, type, ^=, shift); continue | |
//mmapに切り替えるかもしれないのでオーバーラップしておく | |
void *vmap(size_t size) | |
{ | |
return malloc(size); | |
} | |
int prvm(int argc, char *argv[], void *code, void *regist, void *stack) | |
{ | |
intptr_t rgs; //仮想レジスタ | |
intptr_t stk; //コールスタック | |
if (regist != NULL) { | |
rgs = (intptr_t)regist; | |
} else { | |
rgs = (intptr_t)calloc(256, 1); | |
} | |
if (stack != NULL) { | |
stk = (intptr_t)stack; | |
} else { | |
stk = (intptr_t)vmap(8 * 1024 * 1024); | |
} | |
//CALLで使う変数(oldflameとretaddrはRETでも使う) | |
intptr_t oldframe; | |
intptr_t function; | |
intptr_t retaddr; | |
intptr_t cursol; | |
uint8_t *opcode = (uint8_t *)code; | |
uint32_t inst; | |
//条件分岐用フラグレジスタ | |
//仮想レジスタのEFLAGSレジスタが使いにくいため。 | |
//EFLAGSレジスタは仮想レジスタ末尾に配置するが、その保証はしない。 | |
int flag = 0; | |
int ret = EXIT_SUCCESS; | |
//レジスタのBPとSPを初期化 | |
*(intptr_t *)(rgs+RBP) = (intptr_t)sizeof(intptr_t); | |
*(intptr_t *)(rgs+RSP) = (intptr_t)sizeof(intptr_t); | |
//puts("PRVM\n"); | |
while(1) { | |
//まずは4byte命令と仮定して読み取り | |
//メモリIOの回数は極力減らす設計に(命令と引数はシフト演算で分解) | |
inst = *(uint32_t *)opcode; | |
//1byte命令はすべて0x0fより大きい自然数が割り当てられている | |
if (INST1(inst) <= 0x0f) { | |
//2byte命令 | |
switch (INST2(inst)) { | |
case END: ret = *(int *)(opcode + 4); goto PRVMEND; | |
BASICOPERATOR(NAT, Nat, inst, rgs, flag, opcode); | |
case MOD_NAT: BINARYOPERATOR(inst, rgs, Nat, %=); opcode += 4; continue; | |
BASICOPERATOR(INT, Int, inst, rgs, flag, opcode); | |
case MOD_INT: BINARYOPERATOR(inst, rgs, Int, %=); opcode += 4; continue; | |
BASICOPERATOR(NAT8, Nat8, inst, rgs, flag, opcode); | |
case MOD_NAT8: BINARYOPERATOR(inst, rgs, Nat8, %=); opcode += 4; continue; | |
BASICOPERATOR(NAT16, Nat16, inst, rgs, flag, opcode); | |
case MOD_NAT16: BINARYOPERATOR(inst, rgs, Nat16, %=); opcode += 4; continue; | |
BASICOPERATOR(NAT32, Nat32, inst, rgs, flag, opcode); | |
case MOD_NAT32: BINARYOPERATOR(inst, rgs, Nat32, %=); opcode += 4; continue; | |
BASICOPERATOR(NAT64, Nat64, inst, rgs, flag, opcode); | |
case MOD_NAT64: BINARYOPERATOR(inst, rgs, Nat64, %=); opcode += 4; continue; | |
BASICOPERATOR(INT8, Int8, inst, rgs, flag, opcode); | |
case MOD_INT8: BINARYOPERATOR(inst, rgs, Int8, %=); opcode += 4; continue; | |
BASICOPERATOR(INT16, Int16, inst, rgs, flag, opcode); | |
case MOD_INT16: BINARYOPERATOR(inst, rgs, Int16, %=); opcode += 4; continue; | |
BASICOPERATOR(INT32, Int32, inst, rgs, flag, opcode); | |
case MOD_INT32: BINARYOPERATOR(inst, rgs, Int32, %=); opcode += 4; continue; | |
BASICOPERATOR(INT64, Int64, inst, rgs, flag, opcode); | |
case MOD_INT64: BINARYOPERATOR(inst, rgs, Int64, %=); opcode += 4; continue; | |
BASICOPERATOR(BYTE, Byte, inst, rgs, flag, opcode); | |
case MOD_BYTE: BINARYOPERATOR(inst, rgs, Byte, %=); opcode += 4; continue; | |
BASICOPERATOR(WORD, Word, inst, rgs, flag, opcode); | |
case MOD_WORD: BINARYOPERATOR(inst, rgs, Word, %=); opcode += 4; continue; | |
BASICOPERATOR(CHAR, Char, inst, rgs, flag, opcode); | |
case MOD_CHAR: BINARYOPERATOR(inst, rgs, Char, %=); opcode += 4; continue; | |
BASICOPERATOR(INDEX, Index, inst, rgs, flag, opcode); | |
case MOD_INDEX: BINARYOPERATOR(inst, rgs, Index, %=); opcode += 4; continue; | |
BASICOPERATOR(ADDRESS, Address, inst, rgs, flag, opcode); | |
case MOD_ADDRESS: BINARYOPERATOR(inst, rgs, Address, %=); opcode += 4; continue; | |
BASICOPERATOR(FLOAT, Float, inst, rgs, flag, opcode); | |
BASICOPERATOR(DOUBLE, Double, inst, rgs, flag, opcode); | |
case OR: BINARYOPERATOR(inst, rgs, Nat, |=); opcode += 4; continue; | |
case XOR: BINARYOPERATOR(inst, rgs, Nat, ^=); opcode += 4; continue; | |
case AND: BINARYOPERATOR(inst, rgs, Nat, &=); opcode += 4; continue; | |
//この演算は2つ目のオペランドを無視する | |
case NOT: *(Nat *)(rgs+OPRND1(inst)) = !(*(Nat *)(rgs+OPRND1(inst))); opcode += 4; continue; | |
case INV: *(Nat *)(rgs+OPRND1(inst)) = ~(*(Nat *)(rgs+OPRND1(inst))); opcode += 4; continue; | |
BASICBITOPERATOR(8, Nat8, inst, rgs, flag, opcode); | |
BASICBITOPERATOR(16, Nat16, inst, rgs, flag, opcode); | |
BASICBITOPERATOR(32, Nat32, inst, rgs, flag, opcode); | |
BASICBITOPERATOR(64, Nat64, inst, rgs, flag, opcode); | |
BASICBITOPERATOR(BOOL, Bool, inst, rgs, flag, opcode); | |
//この演算は2つ目のオペランドが即値なので注意 | |
case SLA: *(Int *)(rgs+OPRND1(inst)) <<= rgs+OPRND2(inst); opcode += 4; continue; | |
case SRA: *(Int *)(rgs+OPRND1(inst)) >>= rgs+OPRND2(inst); opcode += 4; continue; | |
case SLL: *(Nat *)(rgs+OPRND1(inst)) <<= rgs+OPRND2(inst); opcode += 4; continue; | |
case SRL: *(Nat *)(rgs+OPRND1(inst)) >>= rgs+OPRND2(inst); opcode += 4; continue; | |
//レジスタ間コピー | |
case MOV: BINARYOPERATOR(inst, rgs, Nat, =); opcode += 4; continue; | |
case MOV8: BINARYOPERATOR(inst, rgs, Nat8, =); opcode += 4; continue; | |
case MOV16: BINARYOPERATOR(inst, rgs, Nat16, =); opcode += 4; continue; | |
case MOV32: BINARYOPERATOR(inst, rgs, Nat32, =); opcode += 4; continue; | |
case MOV64: BINARYOPERATOR(inst, rgs, Nat64, =); opcode += 4; continue; | |
//即値をレジスタにコピー | |
case ASN: ASSIGNOPERATOR(inst, rgs, Nat, =, 4+sizeof(Nat)); continue; | |
case ASN8: *(Nat8 *)(rgs+OPRND1(inst)) = (Nat8)(OPRND2(inst)); opcode += 4; continue; | |
case ASN16: ASSIGNOPERATOR(inst, rgs, Nat16, =, 8); continue; | |
case ASN32: ASSIGNOPERATOR(inst, rgs, Nat32, =, 8); continue; | |
case ASN64: ASSIGNOPERATOR(inst, rgs, Nat64, =, 12); continue; | |
//オペランド1のレジスタへオペランド2のレジスタのアドレスからロード | |
case LD: *(Nat *)(rgs+OPRND1(inst)) = *(Nat *)(rgs+OPRND2(inst)); opcode += 4; continue; | |
case LD8: *(Nat8 *)(rgs+OPRND1(inst)) = *(Nat8 *)(rgs+OPRND2(inst)); opcode += 4; continue; | |
case LD16: *(Nat16 *)(rgs+OPRND1(inst)) = *(Nat16 *)(rgs+OPRND2(inst)); opcode += 4; continue; | |
case LD32: *(Nat32 *)(rgs+OPRND1(inst)) = *(Nat32 *)(rgs+OPRND2(inst)); opcode += 4; continue; | |
case LD64: *(Nat64 *)(rgs+OPRND1(inst)) = *(Nat64 *)(rgs+OPRND2(inst)); opcode += 4; continue; | |
//即値のアドレスからレジスタへロード | |
case LAD: *(Nat *)(rgs+OPRND1(inst)) = *(Nat *)(opcode+4); opcode += 4+sizeof(Nat *); continue; | |
case LAD8: *(Nat8 *)(rgs+OPRND1(inst)) = *(Nat8 *)(opcode+4); opcode += 4+sizeof(Nat8 *); continue; | |
case LAD16: *(Nat16 *)(rgs+OPRND1(inst)) = *(Nat16 *)(opcode+4); opcode += 4+sizeof(Nat16 *); continue; | |
case LAD32: *(Nat32 *)(rgs+OPRND1(inst)) = *(Nat32 *)(opcode+4); opcode += 4+sizeof(Nat32 *); continue; | |
case LAD64: *(Nat64 *)(rgs+OPRND1(inst)) = *(Nat64 *)(opcode+4); opcode += 4+sizeof(Nat64 *); continue; | |
//分岐用フラグをレジスタにコピー | |
case FLGGET: *(int *)(rgs+OPRND1(inst)) = flag; opcode += 4; continue; | |
//レジスタから分岐用フラグへコピー | |
case FLGSET: flag = *(int *)(rgs+OPRND1(inst)); opcode += 4; continue; | |
#define GETJMPPTR(head,tracer) ((uint8_t *)((intptr_t)head+*(intptr_t *)(tracer+4))) | |
//無条件ジャンプ | |
case JMP: opcode = GETJMPPTR(code, opcode); continue; | |
//フラグがtrue(0以外)ならジャンプ | |
case JTF: opcode = flag ? GETJMPPTR(code, opcode) : opcode+4+sizeof(intptr_t); continue; | |
//フラグがfalse(0)ならジャンプ | |
case JNT: opcode = flag ? opcode+4+sizeof(intptr_t) : GETJMPPTR(code, opcode); continue; | |
default: goto PRVMERROR; | |
} | |
} else { | |
//1byte命令(0x0f以上) | |
switch (inst & 0x000000ff) { | |
case NOP: opcode += 1; continue; //下手に詰めるとアラインメントが崩れる | |
case CSLDMP: | |
puts("__CSLDMP_______________________________________"); | |
printf("%p\n", opcode); | |
puts("-----------------------------------------------"); | |
opcode += 4; | |
continue; | |
case FLGDMP: | |
puts("__FLGDMP_______________________________________"); | |
printf("0x%08x\n", flag); | |
puts("-----------------------------------------------"); | |
opcode += 4; | |
continue; | |
//レジスタをプリント | |
case RGSDMP: | |
puts("__RGSDMP_______________________________________"); | |
for (cursol = 0; cursol < 256; cursol++) { | |
printf("%02x ", *(uint8_t *)(rgs+cursol)); | |
if (cursol % 16 == 15) printf("\n"); | |
} | |
puts("-----------------------------------------------"); | |
opcode += 4; | |
continue; | |
default: goto PRVMERROR; | |
} | |
} | |
} | |
PRVMEND: | |
free((void *)rgs); | |
free((void *)stk); | |
return ret; | |
PRVMERROR: | |
free((void *)rgs); | |
free((void *)stk); | |
printf("Code: 0x%04x\n", inst); | |
perror("Undefined Operation."); | |
return EXIT_FAILURE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment