Skip to content

Instantly share code, notes, and snippets.

@wsuzume
Last active April 8, 2016 17:11
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/2b8a189df5a4aabfc5b30c16ad81e4d5 to your computer and use it in GitHub Desktop.
Save wsuzume/2b8a189df5a4aabfc5b30c16ad81e4d5 to your computer and use it in GitHub Desktop.
procyon virtual machine
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "type.h"
#include "rgsmap.h"
#define OPRND1(var) ((var>>8)&0x0000000f)
#define OPRND2(var) (var&0x0000000f)
//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+((inst>>8)&0x0000000f)) op *(type *)(rgs+(inst&0x0000000f))
#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 BASICOPENUMERATOR(tnum) \
ADD_##tnum, \
SUB_##tnum, \
MUL_##tnum, \
DIV_##tnum, \
EQ_##tnum, \
NEQ_##tnum, \
LT_##tnum, \
GT_##tnum, \
LTEQ_##tnum, \
GTEQ_##tnum
#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+((inst>>8)&0x0000000f)) = !(*(type *)(rgs+((inst>>8)&0x0000000f))); tracer += 4; continue; \
case INV##tnum: *(type *)(rgs+((inst>>8)&0x0000000f)) = ~(*(type *)(rgs+((inst>>8)&0x0000000f))); tracer += 4; continue
#define BASICBITOPENUMERATOR(tnum) \
OR##tnum, \
XOR##tnum, \
AND##tnum, \
NOT##tnum, \
INV##tnum
enum OPSDOUBLE {
END = 0,
BASICOPENUMERATOR(NAT),
MOD_NAT,
BASICOPENUMERATOR(INT),
MOD_INT,
BASICOPENUMERATOR(NAT8),
MOD_NAT8,
BASICOPENUMERATOR(NAT16),
MOD_NAT16,
BASICOPENUMERATOR(NAT32),
MOD_NAT32,
BASICOPENUMERATOR(NAT64),
MOD_NAT64,
BASICOPENUMERATOR(INT8),
MOD_INT8,
BASICOPENUMERATOR(INT16),
MOD_INT16,
BASICOPENUMERATOR(INT32),
MOD_INT32,
BASICOPENUMERATOR(INT64),
MOD_INT64,
BASICOPENUMERATOR(BYTE),
MOD_BYTE,
BASICOPENUMERATOR(WORD),
MOD_WORD,
BASICOPENUMERATOR(CHAR),
MOD_CHAR,
BASICOPENUMERATOR(INDEX),
MOD_INDEX,
BASICOPENUMERATOR(ADDRESS),
MOD_ADDRESS,
BASICOPENUMERATOR(FLOAT),
//MOD_FLOAT,
BASICOPENUMERATOR(DOUBLE),
//MOD_DOUBLE,
OR, XOR, AND, NOT, INV,
BASICBITOPENUMERATOR(8),
BASICBITOPENUMERATOR(16),
BASICBITOPENUMERATOR(32),
BASICBITOPENUMERATOR(64),
BASICBITOPENUMERATOR(BOOL),
SLA, SRA,
SLL, SRL,
MOV, MOV8, MOV16, MOV32, MOV64,
ASN, ASN8, ASN16, ASN32, ASN64,
LD, LD8, LD16, LD32, LD64,
LAD, LAD8, LAD16, LAD32, LAD64,
FLAG,
FLGSET,
PUSH,
POP,
//PUSHN,
//POPN,
ATASN, ATASN8, ATASN16, ATASN32, ATASN64,
ATLAD, ATLAD8, ATLAD16, ATLAD32, ATLAD64,
JMP, JTF, JNT,
FPTR,
CALL,
RET,
CALLC,
};
#define NOP 0x60
#define PRTRGS 0xff
//mmapに切り替えるかもしれないのでオーバーラップしておく
void *vmap(size_t size)
{
return malloc(size);
}
int prvm(int argc, char *argv[], void *code)
{
intptr_t rgs = (intptr_t)calloc(256, 1); //仮想レジスタ
intptr_t stk = (intptr_t)vmap(8 * 1024 * 1024); //コールスタック
uint8_t *opcode = (uint8_t *)code;
uint32_t inst;
//条件分岐用フラグレジスタ
//仮想レジスタのEFLAGSレジスタが使いにくいため。
//EFLAGSレジスタは仮想レジスタ末尾に配置するが、その保証はしない。
int flag = 0;
//レジスタのBPとSPを初期化
*(intptr_t *)(rgs+RBP) = (intptr_t)sizeof(intptr_t);
*(intptr_t *)(rgs+RSP) = (intptr_t)sizeof(intptr_t);
while(1) {
//まずは4byte命令と仮定して読み取り
//メモリIOの回数は極力減らす設計に(命令と引数はシフト演算で分解)
inst = *(uint32_t *)opcode;
//1byte命令はすべて0x0fより大きい自然数が割り当てられている
if ((inst >> 24) <= 0x0f) {
//2byte命令
switch (inst >> 16) {
case END: 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: *(Nat *)(rgs+OPRND1(inst)) = *(Nat *)(opcode+4);
opcode += 4+sizeof(Nat); continue;
case ASN8: *(Nat8 *)(rgs+OPRND1(inst)) = (Nat8)(rgs+OPRND2(inst));
opcode += 4; continue;
case ASN16: *(Nat16 *)(rgs+OPRND1(inst)) = *(Nat16 *)(opcode+4);
opcode += 8; continue;
case ASN32: *(Nat32 *)(rgs+OPRND1(inst)) = *(Nat32 *)(opcode+4);
opcode += 8; continue;
case ASN64: *(Nat64 *)(rgs+OPRND1(inst)) = *(Nat64 *)(opcode+4);
opcode += 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 FLAG: *(int *)(rgs+OPRND1(inst)) = flag; opcode += 4; continue;
//レジスタから分岐用フラグへコピー
case FLGSET: flag = *(int *)(rgs+OPRND1(inst)); opcode += 4; continue;
//コールスタックの操作
case PUSH: *(intptr_t *)GETCURSOL(stk,rgs) = *(intptr_t *)(rgs+OPRND1(inst));
*(intptr_t *)(rgs+RSP) += sizeof(intptr_t); opcode += 4; continue;
case POP: *(intptr_t *)(rgs+RSP) -= sizeof(intptr_t);
*(intptr_t *)(rgs+OPRND1(inst)) = *(intptr_t *)GETCURSOL(stk,rgs);
opcode += 4; continue;
//オペランド1の値を相対アドレスからオート変数に代入
case ATASN: *(Nat *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4)) = *(Nat *)(rgs+OPRND1(inst));
opcode += 4+sizeof(intptr_t); continue;
case ATASN8: *(Nat8 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4)) = *(Nat8 *)(rgs+OPRND1(inst));
opcode += 4+sizeof(intptr_t); continue;
case ATASN16: *(Nat16 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4)) = *(Nat16 *)(rgs+OPRND1(inst));
opcode += 4+sizeof(intptr_t); continue;
case ATASN32: *(Nat32 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4)) = *(Nat32 *)(rgs+OPRND1(inst));
opcode += 4+sizeof(intptr_t); continue;
case ATASN64: *(Nat64 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4)) = *(Nat64 *)(rgs+OPRND1(inst));
opcode += 4+sizeof(intptr_t); continue;
//相対アドレスからオート変数を読み取り
case ATLAD: *(Nat *)(rgs+OPRND1(inst)) = *(Nat *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4));
opcode += 4+sizeof(intptr_t); continue;
case ATLAD8: *(Nat8 *)(rgs+OPRND1(inst)) = *(Nat8 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4));
opcode += 4+sizeof(intptr_t); continue;
case ATLAD16: *(Nat16 *)(rgs+OPRND1(inst)) = *(Nat16 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4));
opcode += 4+sizeof(intptr_t); continue;
case ATLAD32: *(Nat32 *)(rgs+OPRND1(inst)) = *(Nat32 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4));
opcode += 4+sizeof(intptr_t); continue;
case ATLAD64: *(Nat64 *)(rgs+OPRND1(inst)) = *(Nat64 *)GETATVAR(stk, rgs, *(intptr_t *)(opcode+4));
opcode += 4+sizeof(intptr_t); continue;
//無条件ジャンプ
case JMP: opcode = (uint8_t *)(*(intptr_t *)(opcode+4)); continue;
//フラグがtrue(0以外)ならジャンプ
case JTF: opcode = flag ? (uint8_t *)(*(intptr_t *)(opcode+4)) : opcode+8; continue;
//フラグがfalse(0)ならジャンプ
case JNT: opcode = flag ? opcode+8 : (uint8_t *)(*(intptr_t *)(opcode+4)); continue;
//現在のスタックフレームが実行している関数のポインタを取得
case FPTR: *(intptr_t *)(rgs+OPRND1(inst)) = *(intptr_t *)GETBASE(stk,rgs); opcode += 4; continue;
case CALL:
intptr_t oldframe = GETBASE(stk, rgs);
intptr_t function = *(intptr_t *)(opcode+4);
intptr_t retaddr = (intptr_t)(opcode+4+sizeof(intptr_t *));
intptr_t cursol = GETCURSOL(stk,rgs);
*(intptr_t *)cursol = oldframe;
*(intptr_t *)(rgs+RBP) = cursol+sizeof(intptr_t);
*(intptr_t *)(cursol+sizeof(intptr_t)) = function;
*(intptr_t *)(rgs+RSP) = cursol+sizeof(intptr_t)*2;
*(intptr_t *)(cursol+sizeof(intptr_t)*3) = retaddr;
opcode = (uint8_t *)function;
continue;
case RET:
intptr_t curbase = GETBASE(stk,rgs);
intptr_t retaddr = *(intptr_t *)(curbase+sizeof(intptr_t));
*(intptr_t *)(rgs+RBP) = *(intptr_t *)(curbase-sizeof(intptr_t));
opcode = (uint8_t *)retaddr;
continue;
default: break;
}
} else {
//1byte命令(0x0f以上)
switch (inst >> 24) {
case NOP: opcode += 1; continue; //下手に詰めるとアラインメントが崩れる
//レジスタをプリント
case PRTRGS: continue;
default: break;
}
}
}
PRVMEND:
free((void *)rgs);
free((void *)stk);
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
void *code = NULL;
return prvm(argc, argv, code);
}
#define RAX 0x00
#define EAX 0x00
#define AX 0x00
#define AH 0x01
#define AL 0x00
#define RBX 0x08
#define EBX 0x08
#define BX 0x08
#define BH 0x09
#define BL 0x08
#define RCX 0x10
#define ECX 0x10
#define CX 0x10
#define CH 0x11
#define CL 0x10
#define RDX 0x18
#define EDX 0x18
#define DX 0x18
#define DH 0x19
#define DL 0x18
#define RSI 0x20
#define ESI 0x20
#define SI 0x20
#define SIL 0x20
#define RDI 0x28
#define EDI 0x28
#define DI 0x28
#define DIL 0x28
#define RBP 0x30
#define EBP 0x30
#define BP 0x30
#define BPL 0x30
#define RSP 0x38
#define ESP 0x38
#define SP 0x38
#define SPL 0x38
#define R8 0x40
#define R8D 0x40
#define R8W 0x40
#define R8B 0x40
#define R9 0x48
#define R9D 0x48
#define R9W 0x48
#define R9B 0x48
#define R10 0x50
#define R10D 0x50
#define R10W 0x50
#define R10B 0x50
#define R11 0x58
#define R11D 0x58
#define R11W 0x58
#define R11B 0x58
#define R12 0x60
#define R12D 0x60
#define R12W 0x60
#define R12B 0x60
#define R13 0x68
#define R13D 0x68
#define R13W 0x68
#define R13B 0x68
#define R14 0x70
#define R14D 0x70
#define R14W 0x70
#define R14B 0x70
#define R15 0x78
#define R15D 0x78
#define R15W 0x78
#define R15B 0x78
#define RFLAGS 0xf8
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstdbool>
#include <uchar.h>
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
#ifdef ENVIRONMENT64
typedef int64_t Int;
typedef uint64_t Nat;
typedef int32_t HalfInt;
typedef uint32_t HalfNat;
#endif
#ifdef ENVIRONMENT32
typedef int32_t Int;
typedef uint32_t Nat;
typedef int16_t HalfInt;
typedef uint16_t HalfNat;
#endif
typedef uint8_t Nat8;
typedef uint16_t Nat16;
typedef uint32_t Nat32;
typedef uint64_t Nat64;
typedef int8_t Int8;
typedef int16_t Int16;
typedef int32_t Int32;
typedef int64_t Int64;
typedef char Byte;
typedef char16_t Word;
typedef char32_t Char;
typedef size_t Index;
typedef intptr_t Address;
typedef void * Pointer;
typedef float Float;
typedef double Double;
typedef bool Bool;
typedef int TypeNum;
enum TYPENUM {
UNDEFINED = 0,
VOID,
NAT,
INT,
NAT8,
NAT16,
NAT32,
NAT64,
INT8,
INT16,
INT32,
INT64,
BYTE,
WORD,
CHAR,
INDEX,
ADDRESS,
POINTER,
FLOAT,
DOUBLE,
BOOL,
INVALID,
};
enum Ord { LT = -1, EQ = 0, GT = 1 };
@wsuzume
Copy link
Author

wsuzume commented Apr 8, 2016

レジスタの初期化いらないから消す

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment