Skip to content

Instantly share code, notes, and snippets.

@wsuzume
Created April 28, 2016 11:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wsuzume/6bd7b1358c7cb0af0cdc30439e76120e to your computer and use it in GitHub Desktop.
Save wsuzume/6bd7b1358c7cb0af0cdc30439e76120e to your computer and use it in GitHub Desktop.
#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