summaryrefslogtreecommitdiff
path: root/skullfuck.c
diff options
context:
space:
mode:
authorjakob <jakob@memeware.net>2017-03-16 20:02:38 -0400
committerjakob <jakob@memeware.net>2017-03-16 20:02:38 -0400
commit3afec4b3b76bf994b581b28c3a9aeba6bcef0bf7 (patch)
tree50719717e96c006d959df1b1e90b3095a73c4b0c /skullfuck.c
parent27574819b5886dd44231a25e4add9471fa9efcb0 (diff)
Implemented support for i686 compilation.
Diffstat (limited to 'skullfuck.c')
-rw-r--r--skullfuck.c132
1 files changed, 87 insertions, 45 deletions
diff --git a/skullfuck.c b/skullfuck.c
index e98ea56..0f58198 100644
--- a/skullfuck.c
+++ b/skullfuck.c
@@ -25,32 +25,80 @@
#include <getopt.h>
-/* 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 "
- "<http://jakob.space>\n", VERSION);
+ printf("Skullfuck compiler for Brainfuck, version %s.\nMade "
+ "by Jakob. <http://jakob.space>\n", SKULLFUCK_VERSION);
exit(EXIT_SUCCESS);
case 'S':
p.compile_only = true;