Execute Brain****/x86 Assembly: Difference between revisions
Content added Content deleted
(Made x86 page) |
(No difference)
|
Revision as of 06:02, 13 February 2016
x86_64 Assembly
GAS Syntax for Linux. Called it "Brainkrieg" after Teen Girl Squad. Operating principle is a little like a multi-cycle processor.
Implementation:
<lang>// Assembly brainf*** interpreter // Alternative name: "ASSembly brainF*** interpretER" // Compiles with `gcc -nostdlib brainkrieg.sx -o brainkrieg` // Usage: ./brainkrieg "filename" // Return 0 if normal exit
- define SYS_READ $0
- define SYS_WRITE $1
- define SYS_OPEN $2
- define SYS_CLOSE $3
- define SYS_FSTAT $5
- define SYS_MMAP $9
- define SYS_MUNMAP $11
- define SYS_EXIT $60
// From experiments:
- define FSIZEOFF 48
- define STATSIZE 144
// From Linux source:
- define RDONLY $00
- define PROT_READ $0x1
- define MAP_PRIVATE $0x02
- define STDIN $0
- define STDOUT $1
.global _start .text
.macro ERRCHECK code
cmpq $\code, %rax je fs_error
.endm
/* Local stack notes:
0: int fd
- /
- define STACKSIZE $4
_start:
/* Entry Point: */ // Open: movq RDONLY, %rsi // Filename ptr is on stack currently as argv[1]: cmpq $1, (%rsp) // if argc is 1, error jnz open_file jmp fs_error open_file: movq 16(%rsp), %rdi // argc(8), argv0(8) => rsp+16. filename movq SYS_OPEN, %rax syscall ERRCHECK -1 subq STACKSIZE, %rsp // local stack movl %eax, (%rsp) // int fd = open(argv[1], RDONLY) // fstat to get filesize fstat: movq $statstruct, %rsi movl (%rsp), %edi // fd movq SYS_FSTAT, %rax syscall // fstat(fd, statstruct) ERRCHECK -1 // mmap - don't forget to munmap. mmap: movq $0, %r9 // offset movq (%rsp), %r8 // fd movq MAP_PRIVATE, %r10 movq PROT_READ, %rdx movq filesize, %rsi movq (%rsp), %rdi // vmemptr movq SYS_MMAP, %rax syscall ERRCHECK -1 // Set up machine: boot: movq %rax, head // head = mmap'd file start movq %rax, inst_ptr // inst_ptr = head addq filesize, %rax movq %rax, end // end = head+filesize movq $tape, data_ptr // data_ptr = tape xorq %rax, %rax /* Magic happens here: - Fetch symbol - Decode symbol - Execute opcode - Instruction out of range = halt - Data out of range = halt */ OS_start: fetch: movq inst_ptr, %rbx cmpq end, %rbx ja shutdown // End of code movb (%rbx), %al incq %rbx movq %rbx, inst_ptr decode: cmpb $'+, %al je inc_data cmpb $'-, %al je dec_data cmpb $'>, %al je dp_right cmpb $'<, %al je dp_left cmpb $'[, %al je brf cmpb $'], %al je brb cmpb $'., %al je out_data cmpb $',, %al je in_data jmp fetch // execute: dp_left: cmpq $tape, data_ptr jz scram decq data_ptr jmp fetch dp_right: cmpq $endtape, data_ptr jz scram incq data_ptr jmp fetch dec_data: movq data_ptr, %rbx decq (%rbx) jmp fetch inc_data: movq data_ptr, %rbx incq (%rbx) jmp fetch out_data: movq $1, %rdx movq data_ptr, %rsi movq STDOUT, %rdi movq SYS_WRITE, %rax syscall ERRCHECK -1 jmp fetch in_data: movq $1, %rdx movq data_ptr, %rsi movq STDIN, %rdi movq SYS_READ, %rax syscall ERRCHECK -1 cmpb $'\n, (%rsi) je fetch movq %rax, junkChar jmp fetch brf: // branch if *dp=0 movq data_ptr, %rbx cmpb $0, (%rbx) jnz fetch matchfwd: movq inst_ptr, %rbx movb (%rbx), %al cmpb $'[, %al jne no_smph incq brack_smph cmpq end, %rbx je scram incq inst_ptr jmp matchfwd no_smph: // no semaphore needed cmpb $'], %al je check_smph cmpq end, %rbx je scram incq inst_ptr jmp matchfwd check_smph: // check if semaphore set cmpq $0, brack_smph jz donematch decq brack_smph cmpq end, %rbx je scram incq inst_ptr jmp matchfwd brb: // branch if *dp!=0 movq data_ptr, %rbx cmpb $0, (%rbx) jz fetch subq $2, inst_ptr // Branch taken, scan back. matchbwd: movq inst_ptr, %rbx movb (%rbx), %al cmpb $'], %al jne no_smph2 incq brack_smph cmpq head, %rbx je scram decq inst_ptr jmp matchbwd no_smph2: // no semaphore needed cmpb $'[, %al je check_smph2 cmpq head, %rbx je scram decq inst_ptr jmp matchbwd check_smph2: // check if semaphore set cmpq $0, brack_smph jz donematch2 decq brack_smph cmpq head, %rbx je scram decq inst_ptr jmp matchbwd donematch: incq inst_ptr donematch2: jmp fetch scram: // Memory breached movq $0x7f, err_val shutdown: // Consume rest of stdin if we used it. cmpb $0, junkChar jz skip_flush flush_stdin: movq SYS_READ, %rax movq STDIN, %rdi movq $junkChar, %rsi movq $1, %rdx syscall cmpq $0, %rax // EOF jz skip_flush cmpb $'\n, junkChar jne flush_stdin // munmap skip_flush: movq filesize, %rsi movq head, %rdi movq SYS_MUNMAP, %rax syscall // munmap(vmemptr, filesize) cmpq $-1, %rax je fs_error // close movl (%rsp), %edi movq SYS_CLOSE, %rax syscall // close(fd) ERRCHECK -1
exit:
movq SYS_EXIT, %rax movzbq err_val, %rdi syscall
fs_error:
movq SYS_EXIT, %rax movq $-1, %rdi syscall // exit(-1)
.data brack_smph: // Bracket matching semaphore
.quad 0
junkChar: // Also used to check if input was used.
.byte 0
err_val:
.byte 0
statstruct: // This struct is 144 bytes. Only want size (+48)
.zero FSIZEOFF filesize: // 8 bytes. .quad 0 .zero STATSIZE-FSIZEOFF+8
// Program: head:
.quad 0
end:
.quad 0
inst_ptr:
.quad 0
// Data: data_ptr:
.quad 0
tape:
.zero 30000
endtape:
.zero 1
</lang>