Created
August 21, 2023 09:26
-
-
Save Hachem-H/d553bd5bcb97181e31b969f139c4eac4 to your computer and use it in GitHub Desktop.
A Brainf**ck compiler written x64 NASM assembly.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; The BrainCell Brainf**k Compiler | |
; -------------------------------- | |
; | |
; BrainCell is a basic brainf**k compiler written in an evening, | |
; It contains a basic transpiler which translates brainf**k code, | |
; into the equivalent C code. Then uses `gcc` to compile the | |
; generated output. Though I do recognize the fact that this | |
; is not an optimized approach in any way, shape or form, | |
; but this is a rather fun and simple project, not designed to | |
; be serious. | |
; | |
; The following is the equivalent C code: | |
; ```c | |
; #include <stdio.h> | |
; #include <stdlib.h> | |
; | |
; char* ReadFile(const char* filepath) | |
; { | |
; FILE* file = fopen(filepath, "r"); | |
; if (!file) | |
; { | |
; puts("[ERR]: Could not read file."); | |
; return NULL; | |
; } | |
; | |
; fseek(file, 0, SEEK_END); | |
; size_t size = ftell(file); | |
; rewind(file); | |
; | |
; char* buffer = (char*) malloc(size); | |
; fread(buffer, size, 1, file); | |
; buffer[size] = 0; | |
; | |
; fclose(file); | |
; return buffer; | |
; } | |
; | |
; void Compile(const char* sourceCode) | |
; { | |
; char* header = "#include <stdio.h>\n" | |
; "static char stack[3000];" | |
; "static int pointer;" | |
; "int main(void) {"; | |
; | |
; FILE* transpiled = fopen("tmp.c", "w"); | |
; if (!transpiled) | |
; { | |
; puts("[ERR]: Could not generate output file."); | |
; return NULL; | |
; } | |
; | |
; fputs(header, transpiled); | |
; | |
; for (size_t i = 0; i < strlen(sourceCode); i++) | |
; { | |
; char character = sourceCode[i]; | |
; switch (character) | |
; { | |
; case '>': fputs("if (pointer+1>2999) pointer=0; else pointer++;", transpiled); break; | |
; case '<': fputs("if (pointer-1<0) pointer=2999; else pointer--;", transpiled); break; | |
; case '+': fputs("stack[pointer]++;", transpiled); break; | |
; case '-': fputs("stack[pointer]--;", transpiled); break; | |
; | |
; case '[': fputs("while (stack[pointer]) {", transpiled); break; | |
; case ']': fputs("}", transpiled); | |
; | |
; case '.': fputs("putchar(stack[pointer]);", transpiled); break; | |
; case ',': fputs("stack[pointer] = getchar();", transpiled); break; | |
; default: break; | |
; } | |
; } | |
; | |
; fputs('}', transpiled); | |
; fclose(transpiled); | |
; | |
; system("gcc -o output temp.c -O2"); | |
; system("rm temp.c"); | |
; } | |
; | |
; int main(int argc, char* argv[]) | |
; { | |
; if (argc < 2) | |
; { | |
; puts("Usage: BrainCell [source]"); | |
; return 0; | |
; } | |
; | |
; char* sourceCode = ReadFile(argv[1]); | |
; Compile(sourceCode); | |
; free(sourceCode); | |
; } | |
; ``` | |
; To assemble and link, simply use nasm and gcc like so: | |
; ```sh | |
; $ nasm -felf64 BrainCell.asm | |
; $ gcc -no-pie BrainCell.o -o BrainCell -lc | |
; ``` | |
global main | |
extern fopen | |
extern fputs | |
extern fseek | |
extern ftell | |
extern rewind | |
extern fread | |
extern fclose | |
extern puts | |
extern system | |
extern malloc | |
extern free | |
section .rodata | |
readError db "[ERR]: Could not read file.", 0x00 | |
readMode db "r", 0x00 | |
writeError db "[ERR]: Could not generate output file.", 0x00 | |
writeMode db "w", 0x00 | |
header db "#include <stdio.h>", 0x0A | |
db "static char stack[3000];", | |
db "static int pointer;", | |
db "int main(void) {", 0x0A, 0x00 | |
footer db "}", 0x0A, 0x0A, 0x00 | |
SHIFT_RIGHT db "if (pointer+1>2999) pointer = 0; else pointer++;", 0x00 | |
SHIFT_LEFT db "if (pointer-1<0) pointer=2999; else pointer--;", 0x00 | |
INCREMENT db "stack[pointer]++;", 0x00 | |
DECREMENT db "stack[pointer]--;", 0x00 | |
LOOP_START db "while (stack[pointer]) {", 0x00 | |
LOOP_END db "}", 0x00 | |
PRINT db "putchar(stack[pointer]);", 0x00 | |
READ db "stack[pointer]=getchar();", 0x00 | |
compileCommand db "gcc -o output.o tmp.c -O2", 0x00 | |
removeCommand db "rm tmp.c", 0x00 | |
tempPath db "tmp.c", 0x00 | |
usage db "Usage: BrainCell [source]", 0x00 | |
section .bss | |
originalRSP resq 0x1 | |
originalRSI resq 0x1 | |
sourceFile resq 0x1 | |
outputFile resq 0x1 | |
sourceCodeBuffer resq 0x1 | |
sourceCodeSize resq 0x1 | |
iterator resq 0x1 | |
section .text | |
ReadFile: | |
push rbp | |
mov rbp, rsp | |
mov rsi, readMode | |
call fopen | |
mov QWORD [sourceFile], rax | |
test rax, rax | |
jz ReadFileError | |
mov rdi, QWORD [sourceFile] | |
xor rsi, 0x00 | |
mov rdx, 0x02 | |
call fseek | |
mov rdi, QWORD [sourceFile] | |
call ftell | |
mov QWORD [sourceCodeSize], rax | |
mov rdi, [sourceFile] | |
call rewind | |
mov rdi, QWORD [sourceCodeSize] | |
call malloc | |
mov QWORD [sourceCodeBuffer], rax | |
mov rdi, QWORD [sourceCodeBuffer] | |
mov rsi, QWORD [sourceCodeSize] | |
mov rdx, 0x1 | |
mov rcx, QWORD [sourceFile] | |
call fread | |
mov rax, QWORD [sourceCodeSize] | |
mov rsi, QWORD [sourceCodeBuffer] | |
add rsi, rax | |
mov BYTE [rsi], 0x00 | |
jmp ReadFileEnd | |
ReadFileError: | |
lea rdi, [rel readError] | |
call puts | |
jmp ReadFileEnd | |
ReadFileEnd: | |
pop rbp | |
ret | |
Compile: | |
push rbp | |
mov rbp, rsp | |
mov rdi, tempPath | |
mov rsi, writeMode | |
call fopen | |
mov QWORD [outputFile], rax | |
test rax, rax | |
jz CompileError | |
mov rdi, header | |
mov rsi, QWORD [outputFile] | |
call fputs | |
mov rsi, [sourceCodeBuffer] | |
CompileLoopStart: | |
mov al, BYTE [rsi] | |
cmp al, 0x00 | |
je CompileLoopEnd | |
push rsi | |
cmp al, "+" | |
je AppendInc | |
cmp al, "-" | |
je AppendDec | |
cmp al, "<" | |
je AppendShiftR | |
cmp al, ">" | |
je AppendShiftL | |
cmp al, "[" | |
je AppendLoopStart | |
cmp al, "]" | |
je AppendLoopEnd | |
cmp al, "." | |
je AppendPrint | |
cmp al, "," | |
je AppendPrint | |
jmp EndCase | |
AppendInc: | |
mov rdi, INCREMENT | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
AppendDec: | |
mov rdi, DECREMENT | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
AppendShiftR: | |
mov rdi, SHIFT_RIGHT | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
AppendShiftL: | |
mov rdi, SHIFT_LEFT | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
AppendLoopStart: | |
mov rdi, LOOP_START | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
AppendLoopEnd: | |
mov rdi, LOOP_END | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
AppendPrint: | |
mov rdi, PRINT | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
AppendRead: | |
mov rdi, READ | |
mov rsi, QWORD [outputFile] | |
call fputs | |
jmp EndCase | |
EndCase: | |
pop rsi | |
inc rsi | |
jmp CompileLoopStart | |
CompileLoopEnd: | |
mov rdi, footer | |
mov rsi, QWORD [outputFile] | |
call fputs | |
mov rdi, QWORD [outputFile] | |
call fclose | |
mov QWORD [originalRSP], rsp | |
mov QWORD [originalRSI], rsi | |
mov rsi, rsp | |
sub rsp, 0x8 | |
mov rdi, compileCommand | |
call system | |
mov rdi, removeCommand | |
call system | |
mov rsp, QWORD [originalRSP] | |
mov rsi, QWORD [originalRSI] | |
jmp CompileEnd | |
CompileError: | |
lea rdi, [rel writeError] | |
call puts | |
jmp CompileEnd | |
CompileEnd: | |
pop rbp | |
ret | |
main: | |
cmp rdi, 0x2 | |
jl PrintUsage | |
mov rdi, [rsi+0x8] | |
call ReadFile | |
call Compile | |
mov rdi, [sourceCodeBuffer] | |
call free | |
jmp ProgramEnd | |
PrintUsage: | |
mov rdi, usage | |
call puts | |
ProgramEnd: | |
ret |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment