Newer
Older
Import / research / other / simpVM / src / vm.c
/*
#define exit	EXIT
#define printf	PRINTF
#define main	MAIN
#define O_RDONLY	0
#define	STDOUT_FILENO	1
#define PROT_READ	1
#define MAP_PRIVATE	2
#define SYS_CALL(r,a,a1,a2,a3) \
int res; __asm__ __volatile__ ( "int $0x80" : "=a"(res) \
: "0"(a),"b"((long)(a1)),"c"((long)(a2)),"d"((long)(a3)) ); \
return (((unsigned)(res) >= (unsigned)(-125)) ? (r)-1 : (r)res);
#define SYS_CALL3(r,n,x,t1,t2,t3) r n(t1 a1, t2 a2, t3 a3) { SYS_CALL(r,x,a1,a2,a3); }
#define SYS_CALL2(r,n,x,t1,t2)	  r n(t1 a1, t2 a2)	   { SYS_CALL(r,x,a1,a2, 0); }
#define SYS_CALL1(r,n,x,t1)	  r n(t1 a1)		   { SYS_CALL(r,x,a1, 0, 0); }
SYS_CALL1(void,exit,0x01,int)
SYS_CALL1(int,close,0x06,int)
SYS_CALL2(int,open,0x05,const char*,int)
SYS_CALL3(int,read,0x03,int,void*,int)
SYS_CALL3(int,write,0x04,int,const void*,int)
void *mmap(void *a, int b, int c, int d, int e, int f)
{
    unsigned buf[6] = { (unsigned)a, (unsigned)b, (unsigned)c, (unsigned)d, (unsigned)e, (unsigned)f };
    SYS_CALL(void*, 0x5A, buf, 0, 0);
}
void printf(const char *str, ...);
char **environ;
extern int main(int argc, char *argv[]);
void _start(int a, int b, int c, int d, int argc, char *argv0) {
    environ = (char**)&argv0 + argc + 1;
    printf("argc = %i\n", argc);
    exit(main(argc, &argv0));
}
// GCC code
unsigned __udivmodsi4(unsigned num, unsigned den, unsigned *rem_p)
{
    unsigned quot = 0, qbit = 1;

    if ( den == 0 ) {
	printf("Divide by 0\n");
	//__divide_error();
	return 0;
    }

    while ( (int)den >= 0 ) {
	den <<= 1;
	qbit <<= 1;
    }

    while ( qbit ) {
	if ( den <= num ) {
	    num -= den;
	    quot += qbit;
	}
	den >>= 1;
	qbit >>= 1;
    }

    if ( rem_p )
	*rem_p = num;

    return quot;
}


// GCC code
unsigned __udivsi3(unsigned num, unsigned den)
{
    return __udivmodsi4(num, den, 0);
}


// GCC code
unsigned __umodsi3(unsigned num, unsigned den)
{
    unsigned v;
    (void) __udivmodsi4(num, den, &v);
    return v;
}


char strTmpBuf[64];
char *strInteger(unsigned num, unsigned base)
{
    const char *lookup = "0123456789ABCDEF";
    int i = 1;
    strTmpBuf[63] = 0;
    do {
	strTmpBuf[63-i] = lookup[num % base];
	num /= base;
	i++;
    } while (num);
    return &(strTmpBuf[63-i+1]);
}

#define PRINTF_BUF_SIZE	    2048
void printf(const char *str, ...)
{
    int ap = (int)&str + sizeof(str);
    char outputBuffer[PRINTF_BUF_SIZE];
    int i = 0, x = 0;

    while (str[i]) {
	if (str[i] == '%') {
	    i++;
	    if (str[i] == '%') {
		outputBuffer[x] = str[i];
		x++;
	    } else if (str[i] == 'i' || str[i] == 'd' || str[i] == 'u' || str[i] == 'o' ||
		    str[i] == 'x' || str[i] == 'X' || str[i] == 'p' || str[i] == 'n' ||
		    str[i] == 's') {
		int num, base = 10, t = 0;
		char *tmp;
		if (str[i] != 's') {
		    if (str[i] == 'n')
			num = x;
		    else {
			num = *(int*)ap;
			ap += sizeof(int);
		    }
		    if (str[i] == 'o') {
			outputBuffer[x] = '0'; x++;
			base = 8;
		    }
		    if (str[i] == 'x' || str[i] == 'X') {
			outputBuffer[x] = '0'; x++;
			outputBuffer[x] = str[i]; x++;
			base = 16;
		    }
		    if (str[i] == 'p') {
			outputBuffer[x] = '('; x++;
			outputBuffer[x] = '0'; x++;
			outputBuffer[x] = 'X'; x++;
			base = 16;
		    }
		    tmp = strInteger(num, base);
		} else {
		    tmp = *(char**)ap;
		    ap += sizeof(char*);
		}
		while (tmp[t]) {
		    outputBuffer[x] = tmp[t];
		    t++;
		    x++;
		}
		if (str[i] == 'p') {
		    outputBuffer[x] = ')'; x++;
		}
	    } else if (str[i] == 'c') {
		int ch = *(int*)ap;
		ap += sizeof(int);
		outputBuffer[x] = (char)ch;
		x++;
	    } else {
		// unrecognized / unsupported format identifier
	    }
	} else {
	    outputBuffer[x] = str[i];
	    x++;
	}

	if ( x >= (PRINTF_BUF_SIZE / 2) ) {
            write(STDOUT_FILENO, outputBuffer, x);
	    x = 0;
	}

	i++;
    }

    write(STDOUT_FILENO, outputBuffer, x);
}

*/

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>


int verbose = 0;
unsigned char *sectionData[4];
unsigned int sectionSize[4];


int init(char *file)
{
    int fd = open(file, O_RDONLY);
    read(fd, sectionSize, 16);

    int total = 0;
    int i;
    for (i = 0; i < 4; i++) {
	total += sectionSize[i];

	// debug
	if (verbose)
            printf("size[%i] = %i\n", i, sectionSize[i]);
    }

    unsigned char *data = (unsigned char *)mmap(0, total+16, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    int runningTotal = 0;
    for (i = 0; i < 4; i++) {
	sectionData[i] = data + runningTotal + 16;
	runningTotal += sectionSize[i];
    }

    // debug
    int j;
    if (verbose)
	for (i = 0; i < 4; i++)
	    for (j = 0; j < sectionSize[i]; j++)
		printf("data[%i][%i] = %i\n", i, j, sectionData[i][j]);

    return 1;
}


void done()
{
    printf("got nop, will exit now\n");
    exit(0);
}

void call()
{
    printf("got call inst\n");
}


void pnum(int i)
{
    printf("debug %i\n", i);
}


void lineByte(int i, int b)
{
    printf("debug: line %i  byte: %i\n", i, b);
}


unsigned char *code;
unsigned char *data;
unsigned codeSize;
unsigned char *codeEnd;


int run(char *file)
{
    if (!init(file))
	return -1;

    code = sectionData[0];
    data = sectionData[1];

    codeSize = sectionSize[0];
    codeEnd = &code[codeSize];
//    codeEnd[0] = -1;
//    codeEnd[1] = -1;

    __asm__ __volatile__ (
	"	movl code,%esi\n"
	"	movl data,%edi\n"


	"again:\n"
	"	xorl %ecx,%ecx\n"
	"	mov (%esi),%cl\n"

	// Debugging
	"	movl %esi,%eax\n"
	"	sub code,%eax\n"
	"	push %ecx\n"
	"	push %eax\n"
	"	push %ecx\n"
	"	push %eax\n"
	"	call lineByte\n"
	"	pop  %eax\n"
	"	pop  %ecx\n"

	"	addl $1,%esi\n"

//	"	cmpl codeEnd,%esi\n" // Can avoid if can cause
//	"	jle over1\n"	     // the end of the mapped
//	"	call exit\n"	     // code to call 'done' or nop etc.
//	"over1:\n"


	"	movl %ecx,%ebx\n"
	"	andl $15,%ebx\n"
	"	jmpl *tab1(,%ebx,4)\n"


	"next_nibble:\n"
	"	shrl $4,%ecx\n"
	"	andl $15,%ecx\n"
	"	jmpl *tab2(,%ecx,4)\n"


	"tab1:\n"
	"	.long PUSH1a,ADDa,SUBa,MULa,DIVa,ANDa,ORa,XORa,RETa\n"
	"	.long SHIFT,CALL,JMP,POP,PUSHval,PUSHref,NOP1\n"
	"tab2:\n"
	"	.long PUSH1b,ADDb,SUBb,MULb,DIVb,ANDb,ORb,XORb,RETb\n"
	"	.long SHIFT,CALL,JMP,POP,PUSHval,PUSHref,NOP1\n"


	"PUSH1a:\n" "	pushl $1\n"	                        "\tjmp next_nibble\n"
	"ADDa:\n" "	popl %eax\n"	"\taddl %eax,(%esp)\n"	"\tjmp next_nibble\n"
	"SUBa:\n" "	popl %eax\n"	"\tsubl %eax,(%esp)\n"	"\tjmp next_nibble\n"
	"MULa:\n" "	popl %eax\n"	"\timull (%esp)\n"
					"\tmovl %eax,(%esp)\n"	"\tjmp next_nibble\n"
	"DIVa:\n" "	popl %eax\n"	"\tidivl (%esp)\n"
					"\tmovl %eax,(%esp)\n"	"\tjmp next_nibble\n"
	"ANDa:\n" "	popl %eax\n"	"\tandl %eax,(%esp)\n"	"\tjmp next_nibble\n"
	"ORa:\n" "	popl %eax\n"	"\torl %eax,(%esp)\n"	"\tjmp next_nibble\n"
	"XORa:\n" "	popl %eax\n"	"\txorl %eax,(%esp)\n"	"\tjmp next_nibble\n"
	"RETa:\n" "	popl %esi\n"	                        "\tjmp next_nibble\n"


	"PUSH1b:\n" "	pushl $1\n"	                        "\tjmp again\n"
	"ADDb:\n" "	popl %eax\n"	"\taddl %eax,(%esp)\n"	"\tjmp again\n"
	"SUBb:\n" "	popl %eax\n"	"\tsubl %eax,(%esp)\n"	"\tjmp again\n"
	"MULb:\n" "	popl %eax\n"	"\timull (%esp)\n"
					"\tmovl %eax,(%esp)\n"	"\tjmp again\n"
	"DIVb:\n" "	popl %eax\n"	"\tidivl (%esp)\n"
					"\tmovl %eax,(%esp)\n"	"\tjmp again\n"
	"ANDb:\n" "	popl %eax\n"	"\tandl %eax,(%esp)\n"	"\tjmp again\n"
	"ORb:\n" "	popl %eax\n"	"\torl %eax,(%esp)\n"	"\tjmp again\n"
	"XORb:\n" "	popl %eax\n"	"\txorl %eax,(%esp)\n"	"\tjmp again\n"
	"RETb:\n" "	popl %esi\n"	                        "\tjmp again\n"


	"JMP:\n"		    // TODO - seems to work
//	    "\taddl $4,%esi\n"
	    "\tmovl (%esi),%eax\n"
	    "\tmovl code,%esi\n"
	    "\taddl %eax,%esi\n"

//	    "\taddl $4,%esi\n"
	    "\tjmp again\n"
	"SHIFT:\n"		    // TODO
	    "\taddl $4,%esi\n"
	    "\tjmp again\n"
	"CALL:\n"		    // TODO
	    "\tcall call\n"
	    // "\tcall printf\n"
	    "\taddl $4,%esi\n"
	    "\tjmp again\n"
	"POP:\n"
	    "\tmovl (%esi),%eax\n"
	    "\tpopl (%edi,%eax,)\n"
	    "\taddl $4,%esi\n"
	    "\tjmp again\n"
	"PUSHval:\n"
	    "\tmovl (%esi),%eax\n"
	    "\tpushl (%edi,%eax,)\n"
	    "\taddl $4,%esi\n"
	    "\tjmp again\n"
	"PUSHref:\n"
	    "\tmovl (%esi),%eax\n"
	    "\tleal (%edi,%eax,),%eax\n"
	    "\tpushl %eax\n"
	    "\taddl $4,%esi\n"
	    "\tjmp again\n"
	"NOP1:\n"
	    "\tcall done\n"
	    "\tjmp again\n"
    );
}


int main(int argc, char *argv[])
{
    int i;
    char *input = 0;
    for (i = 1; i < argc; i++) {
	if (argv[i][0] == '-' && argv[i][1] == 'v')
	    verbose = 1;
	else
	    input = argv[i];
    }
    if (input)
	return run(input);
    printf("No input files.\n");
    return -1;
}