Skip to content

Instantly share code, notes, and snippets.

@Xvezda
Last active July 28, 2017 00:47
Show Gist options
  • Save Xvezda/730841ab76c25e2ac77e99c8482bcc57 to your computer and use it in GitHub Desktop.
Save Xvezda/730841ab76c25e2ac77e99c8482bcc57 to your computer and use it in GitHub Desktop.
Pseudo x86 Assembly Interpreter
/*
* Pseudo Assembly interpreter
* by. Xvezda (xvezda@naver.com)
*
* < The MIT License >
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MEM_SIZE 1024 // 0x400
#define BUF_SIZE 256 // 0x100
#define STR2(x) #x
#define STR(x) STR2(x)
#define CMP_STR(t, s) \
(!memcmp((t), (s), sizeof(s) - 1))
#define CMP_SUB \
if (0) {}
#define CMP_END \
else { \
printf("Error: Bad register name.\n"); \
status = 1; \
break; \
};
#define CMP_REG(t, n, exp) \
else if (CMP_STR((t), #n)) { \
exp; \
}
#define GEN_REG(n) \
union { \
int e##n##x; \
short n##x; \
struct { \
char n##l; \
char n##h; \
}; \
};
#define TRW_ERR(e, m) \
if ((e)) { \
printf(m); \
status = 1; \
break; \
}
#define _TRW_ERR(x, f, m) \
if ((f(*x))) { \
printf(m); \
status = 1; \
break; \
}
#define INS_TMP(mp, dst, src, exp) \
do { \
int data; \
_TRW_ERR(dst, isdigit, "Error: Dest cannot be a number.\n"); \
if (isdigit(*src)) { \
data = atoi(src); \
} else { \
CMP_SUB \
CMP_REG(src, eax, data = mp->reg.eax) \
CMP_REG(src, ebx, data = mp->reg.ebx) \
CMP_REG(src, ecx, data = mp->reg.ecx) \
CMP_REG(src, edx, data = mp->reg.edx) \
CMP_REG(src, esp, data = mp->reg.esp) \
CMP_REG(src, ebp, data = mp->reg.ebp) \
CMP_END \
} \
CMP_SUB \
CMP_REG(dst, eax, mp->reg.eax exp data) \
CMP_REG(dst, ebx, mp->reg.ebx exp data) \
CMP_REG(dst, ecx, mp->reg.ecx exp data) \
CMP_REG(dst, edx, mp->reg.edx exp data) \
CMP_REG(dst, esp, mp->reg.esp exp data) \
CMP_REG(dst, ebp, mp->reg.ebp exp data) \
CMP_END \
} while (0);
#define _INS_TMP(mp, trg, exp) \
TRW_ERR(isdigit(*trg), "Error: Bad register.\n"); \
CMP_SUB \
CMP_REG(trg, eax, mp->reg.eax = exp mp->reg.eax) \
CMP_REG(trg, ebx, mp->reg.ebx = exp mp->reg.ebx) \
CMP_REG(trg, ecx, mp->reg.ecx = exp mp->reg.ecx) \
CMP_REG(trg, edx, mp->reg.edx = exp mp->reg.edx) \
CMP_REG(trg, esp, mp->reg.esp = exp mp->reg.esp) \
CMP_REG(trg, ebp, mp->reg.ebp = exp mp->reg.ebp) \
CMP_END
typedef struct REGISTERS
{
GEN_REG(a);
GEN_REG(b);
GEN_REG(c);
GEN_REG(d);
int esp;
int ebp;
int esi;
int edi;
} reg_t;
typedef struct MEMORY
{
int block[MEM_SIZE];
reg_t reg;
} mem_t;
void showm(void);
void showc(void);
void showe(const char *msg);
void showr(mem_t *mp);
void showi(void);
int execi(char *ins);
int main(int argc, char *argv[])
{
mem_t* mp = malloc(sizeof(mem_t));
char ins[BUF_SIZE] = { 0, };
showm();
for (int status = 0; !status; /* NULL */) {
showc();
scanf("%" STR(BUF_SIZE) "[^\n]s", ins);
switch (execi(ins)) {
case -1:
status = 1;
break;
case 1:
showr(mp);
break;
default: {
char *i = strtok(ins, ", ");
char *a = strtok(NULL, ", ");
char *b = strtok(NULL, ", ");
//char *c = strtok(NULL, ", ");
if (CMP_STR(i, "mov")) {
INS_TMP(mp, a, b, =);
break;
} else if (CMP_STR(i, "add")) {
INS_TMP(mp, a, b, +=);
break;
} else if (CMP_STR(i, "sub")) {
INS_TMP(mp, a, b, -=);
break;
} else if (CMP_STR(i, "xor")) {
INS_TMP(mp, a, b, ^=);
break;
} else if (CMP_STR(i, "or")) {
INS_TMP(mp, a, b, |=);
break;
} else if (CMP_STR(i, "and")) {
INS_TMP(mp, a, b, &=);
break;
} else if (CMP_STR(i, "inc")) {
_INS_TMP(mp, a, 1+);
break;
} else if (CMP_STR(i, "dec")) {
_INS_TMP(mp, a, -1+);
break;
} else if (CMP_STR(i, "not")) {
_INS_TMP(mp, a, ~);
break;
} else if (CMP_STR(i, "push")) {
TRW_ERR(mp->reg.esp >= MEM_SIZE, "Error: Stack overflow!\n");
int data;
if (isdigit(*a)) {
data = atoi(a);
} else {
CMP_SUB
CMP_REG(a, eax, data = mp->reg.eax)
CMP_REG(a, ebx, data = mp->reg.ebx)
CMP_REG(a, ecx, data = mp->reg.ecx)
CMP_REG(a, edx, data = mp->reg.edx)
CMP_REG(a, esp, data = mp->reg.esp)
CMP_REG(a, ebp, data = mp->reg.ebp)
CMP_END
}
mp->block[mp->reg.esp] = data;
mp->reg.esp++;
break;
} else if (CMP_STR(i, "pop")) {
mp->reg.esp--;
TRW_ERR(mp->reg.esp < 0, "Error: Stack underflow!\n");
int data = mp->block[mp->reg.esp];
CMP_SUB
CMP_REG(a, eax, mp->reg.eax = data)
CMP_REG(a, ebx, mp->reg.ebx = data)
CMP_REG(a, ecx, mp->reg.ecx = data)
CMP_REG(a, edx, mp->reg.edx = data)
CMP_REG(a, esp, mp->reg.esp = data)
CMP_REG(a, ebp, mp->reg.ebp = data)
CMP_END
break;
} else if (CMP_STR(i, "leave")) {
mp->reg.esp = mp->reg.ebp;
mp->reg.esp--;
TRW_ERR(mp->reg.esp < 0, "Error: Stack underflow!\n");
mp->reg.ebp = mp->block[mp->reg.esp];
break;
} else if (CMP_STR(i, "nop")) {
__asm ("nop;"); // do nothing
break;
} else if (CMP_STR(i, "help")) {
showi();
break;
}
showe(ins);
} break;
}
getchar(); // clear stdin
}
printf("[Exit code - %d]\n", mp->reg.eax);
free(mp);
return EXIT_SUCCESS;
}
void showm(void)
{
printf("PSEUDO ASSEMBLY INTERPRETER v1.0b\n"
"by. Xvezda\n\n"
"Type \"exit\" to quit, \"help\" for more informations\n");
}
void showc(void)
{
printf(">>>\x20");
}
void showe(const char *msg)
{
printf("Error: There is no such instruction like \"%s\"\n", msg);
}
void showr(mem_t *mp)
{
printf("[REGISTERS]\n"
"EAX: %d\n"
"EBX: %d\n"
"ECX: %d\n"
"EDX: %d\n"
"ESI: %d\n"
"EDI: %d\n"
"ESP: %d\n"
"EBP: %d\n",
mp->reg.eax,
mp->reg.ebx,
mp->reg.ecx,
mp->reg.edx,
mp->reg.esi,
mp->reg.edi,
mp->reg.esp,
mp->reg.ebp);
}
void showi(void)
{
printf("[HELP]\n"
"show - show list of registers.\n"
"exit - quit program.\n"
"[SUPPORT]\n"
"mov, add, sub, xor, or, and, inc, dec, not, push, pop\n");
}
int execi(char *ins)
{
if (CMP_STR(ins, "exit") || CMP_STR(ins, "quit")) {
return -1;
} else if (CMP_STR(ins, "show")
|| CMP_STR(ins, "info")
|| CMP_STR(ins, "view")) {
return 1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment