From 3afec4b3b76bf994b581b28c3a9aeba6bcef0bf7 Mon Sep 17 00:00:00 2001 From: jakob Date: Thu, 16 Mar 2017 20:02:38 -0400 Subject: Implemented support for i686 compilation. --- skullfuck.c | 132 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 45 deletions(-) (limited to 'skullfuck.c') diff --git a/skullfuck.c b/skullfuck.c index e98ea56..0f58198 100644 --- a/skullfuck.c +++ b/skullfuck.c @@ -25,32 +25,80 @@ #include -/* Constants specific to the target architecture. */ -#ifndef MAX_CELLS -#define MAX_CELLS 30000 +#ifdef x86_64 +#define INC_DATA_PTR "\tincq %rsi\n" +#define DEC_DATA_PTR "\tdecq %rsi\n" +#define INC_DATA "\tincb (%rsi)\n" +#define DEC_DATA "\tdecb (%rsi)\n" +#define PRINT_DATA "\tmovq $0x01, %rax\n" \ + "\tmovq $0x01, %rdi\n" \ + "\tsyscall\n" +#define READ_DATA "\tmovq $0x00, %rax\n" \ + "\tmovq $0x00, %rdi\n" \ + "\tsyscall\n" +#define DATA_IS_ZERO "\tmovb (%rsi), %cl\n" \ + "\ttestb %cl, %cl\n" +#define JMP_END "\tjz E%d\n" +#define JMP_START "\tjnz S%d\n" + +#define PRELUDE "\t.section .bss\n" \ + "\t.comm mem, %d\n" \ + "\t.section .text\n" \ + "\t.globl _start\n" \ + "_start:\n" \ + "\tmovq $mem, %%rsi\n" \ + "\tmovq $0x01, %%rdx\n" + +#define EXIT "\tmovq $0x3c, %rax\n" \ + "\tmovq $0x00, %rdi\n" \ + "\tsyscall\n" #endif -#ifndef MAX_LOOP_DEPTH -#define MAX_LOOP_DEPTH 64 + +#ifdef i686 +#define INC_DATA_PTR "\tincl %ecx\n" +#define DEC_DATA_PTR "\tdecl %ecx\n" +#define INC_DATA "\tincb (%ecx)\n" +#define DEC_DATA "\tdecb (%ecx)\n" +#define PRINT_DATA "\tmovl $0x04, %eax\n" \ + "\tmovl $0x01, %ebx\n" \ + "\tint $0x80\n" +#define READ_DATA "\tmovl $0x03, %eax\n" \ + "\tmovl $0x00, %ebx\n" \ + "\tint $0x80\n" +#define DATA_IS_ZERO "\tmovb (%ecx), %al\n" \ + "\ttestb %al, %al\n" +#define JMP_END "\tjz E%d\n" +#define JMP_START "\tjnz S%d\n" + +#define PRELUDE "\t.section .bss\n" \ + "\t.comm mem, %d\n" \ + "\t.section .text\n" \ + "\t.globl _start\n" \ + "_start:\n" \ + "\tmovl $mem, %%ecx\n" \ + "\tmovl $0x01, %%edx\n" + +#define EXIT "\tmovl $0x01, %eax\n" \ + "\tmovl $0x00, %ebx\n" \ + "\tint $0x80\n" #endif +#ifndef AS +#define AS /bin/as +#endif -/* Constants for general usage. */ -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 +#ifndef LD +#define LD /bin/ld +#endif -#define VERSION "0.1.0" +#define MAX_CELLS 30000 +#define MAX_LOOP_DEPTH 64 +#define SKULLFUCK_VERSION "0.2.0" -/* Boilerplate assembly to initialize a memory region on the .bss - segment, and load registers with some constant values. */ -#define PRELUDE "\t.section .bss\n" \ - "\t.comm mem, %d\n" \ - "\t.section .text\n" \ - "\t.globl _start\n" \ - "_start:\n" \ - "\tmovq $mem, %%rsi\n" \ - "\tmovq $0x01, %%rdx\n" +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 @@ -90,48 +138,40 @@ static void write_instructions(FILE *out, char *in) { for (int i = 0; in[i] != '\0'; i++) { switch (in[i]) { case '>': - fputs("\tincq %rsi\n", out); + fputs(INC_DATA_PTR, out); break; case '<': - fputs("\tdecq %rsi\n", out); + fputs(DEC_DATA_PTR, out); break; case '+': - fputs("\tincb (%rsi)\n", out); + fputs(INC_DATA, out); break; case '-': - fputs("\tdecb (%rsi)\n", out); + fputs(DEC_DATA, out); break; case '.': - fputs("\tmovq $0x01, %rax\n", out); - fputs("\tmovq $0x01, %rdi\n", out); - fputs("\tsyscall\n", out); + fputs(PRINT_DATA, out); break; case ',': - fputs("\tmovq $0x00, %rax\n", out); - fputs("\tmovq $0x00, %rdi\n", out); - fputs("\tsyscall\n", out); + fputs(READ_DATA, out); break; case '[': cur_loop = next_loop; push_loop_index(loops, next_loop++); fprintf(out, "S%d:\n", cur_loop); - fputs("\tmovb (%rsi), %cl\n", out); - fputs("\tcmpb $0x00, %cl\n", out); - fprintf(out, "\tje E%d\n", cur_loop); + fputs(DATA_IS_ZERO, out); + fprintf(out, JMP_END, cur_loop); break; case ']': cur_loop = pop_loop_index(loops); fprintf(out, "E%d:\n", cur_loop); - fputs("\tmovb (%rsi), %cl\n", out); - fputs("\tcmpb $0x00, %cl\n", out); - fprintf(out, "\tjne S%d\n", cur_loop); + fputs(DATA_IS_ZERO, out); + fprintf(out, JMP_START, cur_loop); break; } } - fputs("\tmovq $0x3c, %rax\n", out); - fputs("\tmovq $0x00, %rdi\n", out); - fputs("\tsyscall\n", out); + fputs(EXIT, out); free(loops); } @@ -144,12 +184,12 @@ static void panic(char *msg) { } -/* Attempts to create a new file at `path`, and writes a generic prelude - to initialize memory sections. If `path` is NULL, a temporary file - will be created. A FILE pointer will be returned, or NULL if the file +/* Attempts to create a new file at `path`, and writes a boilerplate + prelude to initialize memory segments and load some registers with + constant values. A FILE pointer will be returned, or NULL if the file could not be created. */ static FILE *out_init(char *path) { - FILE *fp = path == NULL ? tmpfile() : fopen(path, "w+"); + FILE *fp = fopen(path, "w+"); if (fp == NULL) return fp; fprintf(fp, PRELUDE, MAX_CELLS); return fp; @@ -179,13 +219,15 @@ static void create_binary(struct params p) { if ((pid = fork()) == -1) { panic("fork"); } else if (pid == 0) { - execv("/bin/as", as_argv); + execv(AS, as_argv); } else { wait(NULL); if ((pid = fork()) == -1) { panic("fork"); } else if (pid == 0) { - execv("/bin/ld", ld_argv); + execv(LD, ld_argv); + } else { + wait(NULL); } } } @@ -221,8 +263,8 @@ static struct params parse_args(int argc, char **argv) { "\t-o file\t\tPlace the output in file.\n"); exit(EXIT_SUCCESS); case 'v': - printf("Skullfuck compiler version %s\nProgrammed by Jakob " - "\n", VERSION); + printf("Skullfuck compiler for Brainfuck, version %s.\nMade " + "by Jakob. \n", SKULLFUCK_VERSION); exit(EXIT_SUCCESS); case 'S': p.compile_only = true; -- cgit v1.3