Simples VM ( Virtual Machine ) - PARTE 1

1. Simples VM ( Virtual Machine ) - PARTE 1

???
gokernel

(usa Linux Mint)

Enviado em 18/02/2016 - 20:08h

Olá !!!
Para quem está interessado em VM, um pequeno exemplo:

Implementei somente 8 OPCODES para melhor entender:

OP_HALT
OP_NOP
OP_PUSH_LONG
OP_PUSH_FLOAT
OP_PUSH_VAR
OP_SET_VAR
OP_INC
OP_PRINT


Depois implementarei: COMPARAÇÃO e LOOPS

OBS: tentei postar no ( codepad.org ) mas falhou ... depois tentarei e REeditarei este tópico.

/*
**-------------------------------------------------------------------
**
** Simples VM:
**
** COMPILE:
** gcc vm.c -o vm -O2 -Wall
** ou
** g++ vm.c -o vm -O2 -Wall
**
**-------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>

#define NEXT goto *(++vm->ip)->jmp
#define GTABLE_SIZE 255
#define GVAR_SIZE 255
#define STACK_SIZE 1024

typedef struct VM VM;
typedef union VALUE VALUE;
typedef struct VAR VAR;
typedef struct OPCODE OPCODE;
typedef struct LABEL LABEL;

struct VM {
OPCODE *ip;
OPCODE *code;
LABEL *label;
int pos;
};
union VALUE {
long l;
float f;
char *s;
void *p;
};
struct VAR {
char *name;
int type;
VALUE value;
};
struct OPCODE {
void *jmp;
VALUE arg; // argumento 1
};
struct LABEL {
char *text;
int pos;
LABEL *next;
};
enum { // opcodes:

OP_HALT = 0, // para sair da VM
OP_NOP, // no opcode

OP_PUSH_LONG, // da um "push" ... e seta o topo da pilha ( *sp ) com um valor long
OP_PUSH_FLOAT, // da um "push" ... e seta o topo da pilha ( *sp ) com um valor float
OP_PUSH_VAR, // da um "push" ... e seta o topo da pilha ( *sp ) com uma variavel

//-------------------------------------------
// OBS: Essa instrucao utiliza 2 argumentos:
// 1: short = o index de Gvar [ ]
// 2: long = o valor da variavel
//-------------------------------------------
OP_SET_VAR, // seta um valor de uma variavel ... somente tipo long

OP_INC, // incrementa uma variavel ( Gvar[] )
OP_PRINT // imprime o valor de uma variavel

};

void *Gtable [ GTABLE_SIZE ];
VAR Gvar [ GVAR_SIZE ];
VALUE stack [ STACK_SIZE ]; // a pilha base
VALUE *sp; // o topo da pilha
int flag_long;
float flag_float;

void vm_run (VM *vm)
{
if (Gtable[0] == NULL) {

Gtable [ OP_HALT ] = && op_halt;
Gtable [ OP_NOP ] = && op_nop;

Gtable [ OP_PUSH_LONG ] = && op_push_long;
Gtable [ OP_PUSH_FLOAT ] = && op_push_float;
Gtable [ OP_PUSH_VAR ] = && op_push_var;

Gtable [ OP_SET_VAR ] = && op_set_var;

Gtable [ OP_INC ] = && op_inc;
Gtable [ OP_PRINT ] = && op_print;

sp = stack;

return;
}

if (!vm)
return;

vm->ip = vm->code;

goto *vm->ip->jmp; // pula para a primeira "inctrucao"

//---------------------------------------------
//########## OPCODES implementacao ##########
//---------------------------------------------
//
op_halt:
printf ("Instrucao OP_HALT ... saindo da VM\n");
return;

op_nop:
// sem opcode ...
NEXT;

op_push_long: {
sp++;
sp->l = vm->ip->arg.l;
} NEXT;

op_push_float: {
sp++;
sp->f = vm->ip->arg.f;
} NEXT;

op_push_var: {
sp++;
// somente tipo long por enquanto
sp->l = Gvar [ vm->ip->arg.l ].value.l;
} NEXT;

op_set_var: {
// somente tipo long por enquanto
Gvar [ *(short*)vm->ip->arg.s ].value.l = *(long*)(vm->ip->arg.s+2);
} NEXT;

op_inc: {
// somente tipo long por enquanto
Gvar [ vm->ip->arg.l ].value.l++;
} NEXT;

op_print: {
// somente tipo long por enquanto
printf ("Gvar[ %ld ] = %ld\n", vm->ip->arg.l, Gvar [ vm->ip->arg.l ].value.l);
} NEXT;
}

VM *vm_new (int size)
{
VM *vm = (VM*) malloc (sizeof(VM));

if (vm) {
if ( (vm->code = (OPCODE*) malloc (sizeof(OPCODE)*size)) == NULL)
return NULL;

vm->ip = vm->code;
vm->label = NULL;
vm->pos = 0;
}
return vm;
}

//-------------------------------------------------------------------
//########################### gen/emit ############################
//-------------------------------------------------------------------
//
void g_halt (VM *vm)
{
vm->code[vm->pos++].jmp = Gtable [ OP_HALT ];
}
void g_nop (VM *vm)
{
vm->code[vm->pos++].jmp = Gtable [ OP_NOP ];
}
void g_set_var (VM *vm, short index, long value)
{
vm->code[vm->pos].jmp = Gtable [ OP_SET_VAR ];
vm->code[vm->pos].arg.s = (char*)malloc ((sizeof(short)+sizeof(long))+1);
*(short*)(vm->code[vm->pos].arg.s) = index;
*(long*)(vm->code[vm->pos].arg.s+2) = value;
vm->pos++;
}
void g_inc (VM *vm, int index)
{
vm->code[vm->pos].jmp = Gtable [ OP_INC ];
vm->code[vm->pos].arg.l = index;
vm->pos++;
}
void g_print (VM *vm, int index)
{
vm->code[vm->pos].jmp = Gtable [ OP_PRINT ];
vm->code[vm->pos].arg.l = index;
vm->pos++;
}

int main (int argc, char *argv[])
{
VM *vm;

//-----------------------------------------
// cria uma VM com maximo de 100 instrucoes
//-----------------------------------------
//
if ((vm = vm_new(100)) != NULL) {

vm_run (NULL); // setup Gtable [ ]

//-------------------------
//******* gen/emit *******
//-------------------------
//
g_set_var (vm, 10, 1500); // seta ( Gvar[10].arg.l ) com o valor 1500
g_inc (vm, 10); // incrementa ( Gvar[10].arg.l )
g_print (vm, 10); // imprime ( Gvar[10].arg.l ) ... 1501
g_halt (vm); // o OPCODE mais importante para sair da VM

vm_run (vm); // agora executa a VM

// aqui: falta liberar memoria ... fica para a proxima
// ...
}
printf ("Saindo Com Sucesso !!!\n");
return 0;
}



Lembrando que a VM funciona somente com 1 argumento para cada instrução ( OPCODE ) mas é possível funcionar com vários argumentos por instrução veja a instrução ( OP_SET_VAR ) .

T++.


  


2. Re: Simples VM ( Virtual Machine ) - PARTE 1

???
gokernel

(usa Linux Mint)

Enviado em 19/02/2016 - 20:29h


Agora um exemplo com loop:

tipo isso:

for (i = 100; i < 150; i++) printf("i: %d\n", i);


implementado 2 jumps:
OP_JMP = pulo incondicional
OP_JG = pula se for menor.

Veja aqui:
http://codepad.org/eVkCpQkC






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts