Files
jitfuck/jitfuck.asm
2026-03-12 18:43:24 +00:00

343 lines
5.5 KiB
NASM

format ELF64 executable
RIGHT = 0x3E
LEFT = 0x3C
PLUS = 0x2B
MINUS = 0x2D
DOT = 0x2E
COMMA = 0x2C
LBRAC = 0x5B
RBRAC = 0x5D
CHUNK_MAX = 0x40
CHUNK_SIZE = (CHUNK_MAX * 2)
CHUNK_MASK = (CHUNK_SIZE - 1)
MAX_CHUNKS = 0x20
MEM = 0x100
entry $
mov rdi,0
mov rsi,(CHUNK_SIZE * MAX_CHUNKS)
mov rdx,0x07 ; PROT_READ | PROT_WRITE | PROT_EXEC
mov r10,0x22 ; MAP_PRIVATE | MAP_ANONYMOUS
mov r8,-1
mov r9,0
mov rax,9 ; mmap
syscall
cmp rax,-1
je fail
mov [translations],rax
xor rbx,rbx
.kekw:
cmp rbx,(CHUNK_SIZE * MAX_CHUNKS)
jge .kekwdone
mov byte [rax+rbx],0
inc rbx
jmp .kekw
.kekwdone:
xor r12,r12 ; Initialize chunk start
.next_chunk:
xor r13,r13 ; Initialize chunk offset
.skip:
call key
.next_run:
cmp rax,0
je execute ; EOF -> finished loading chunks
;; Dispatch on command
cmp rax,RIGHT
je .run_init
cmp rax,LEFT
je .run_init
cmp rax,PLUS
je .run_init
cmp rax,MINUS
je .run_init
cmp rax,DOT
je .run_init
cmp rax,COMMA
je .run_init
cmp rax,LBRAC
je .lbrac
cmp rax,RBRAC
je .rbrac
jmp .skip ; Skip non-command characters
.run_init:
mov r14,rax ; Save rax as run command
mov r15,1 ; Initialize run count to 1
.run:
call key
cmp rax,r14
jne .run_write ; Write run if different command
inc r15 ; Increment run count
jmp .run
.run_write:
mov rbx,r12
add rbx,r13
mov byte [chunks+rbx],r14b ; Write command
mov byte [chunks+rbx+1],r15b ; Write run count
add r13,2 ; Increment chunk offset
jmp .next_run
.lbrac:
mov rbx,r12
add rbx,CHUNK_SIZE
push rbx ; Push start of next chunk
mov rax,r12
add rax,r13
mov byte [chunks+rax],LBRAC ; Write command
mov byte [chunks+rax+1],0 ; Zero run count field
lea rbx,[chunks+rax+2]
push rbx ; Push address of dest field
jmp .end_chunk
.rbrac:
pop rax ; Pop address of lbrac's dest field
mov rbx,r12
add rbx,CHUNK_SIZE
mov word [rax],bx ; Write start of next chunk to lbrac's dest
mov rax,r12
add rax,r13
mov byte [chunks+rax],RBRAC ; Write command
mov byte [chunks+rax+1],0 ; Zero run count field
pop rbx ; Pop start of chunk after lbrac
mov word [chunks+rax+2],bx ; Write to dest field
jmp .end_chunk
.end_chunk:
add r12,CHUNK_SIZE ; Bump chunk start to next chunk
jmp .next_chunk
execute:
mov rax,r12
add rax,r13
mov word [chunks+rax+4],0 ; Terminate last chunk
add r12,CHUNK_SIZE
xor rax,rax
mov rbx,[translations]
.init_translations:
cmp rax,r12
je .begin
mov word [rbx+rax],0x0B0F ; Write UD2 to start
add rax,CHUNK_SIZE
jmp .init_translations
.begin:
mov r15,r12 ; Save end point
xor r12,r12 ; Initialize code offset
mov r13,mem ; Initialize head
.check:
cmp r12,r15
je dump
mov rbx,[translations]
mov word ax,[rbx+r12]
cmp ax,0x0B0F
je translate
.run:
;jmp .next_chunk
mov r14,.check
mov rbx,[translations]
add rbx,r12
jmp rbx
.next_chunk:
and r12,(not CHUNK_MASK)
add r12,CHUNK_SIZE
jmp .check
translate:
mov r14,[translations]
add r14,r12 ; Initialize translation write offset
.opcode:
mov word ax,[chunks+r12]
movzx ebx,ah
cmp al,RIGHT
je right
cmp al,LEFT
je left
cmp al,PLUS
je plus
cmp al,MINUS
je minus
cmp al,DOT
je dot
cmp al,COMMA
je comma
cmp al,LBRAC
je lbrac
cmp al,RBRAC
je rbrac
cmp al,0
je term
jmp fail
.next:
add r12,2
jmp .opcode
write:
cmp rdi,rsi
je .done
mov byte dl,[rdi]
mov byte [r14],dl
inc rdi
inc r14
jmp write
.done:
ret
right:
mov rdi,.translation_start
mov rsi,.translation_end
call write
mov byte [r14-4],bl
jmp translate.next
.translation_start:
add r13,0xFF
.translation_end:
left:
mov rdi,.translation_start
mov rsi,.translation_end
call write
mov byte [r14-4],bl
jmp translate.next
.translation_start:
sub r13,0xFF
.translation_end:
plus:
mov rdi,.translation_start
mov rsi,.translation_end
call write
mov byte [r14-1],bl
jmp translate.next
.translation_start:
add byte [r13],0xFF
.translation_end:
minus:
mov rdi,.translation_start
mov rsi,.translation_end
call write
mov byte [r14-1],bl
jmp translate.next
.translation_start:
sub byte [r13],0xFF
.translation_end:
dot:
mov rsi,.translation_end
.loop:
cmp rbx,0
je translate.next
mov rdi,.translation_start
call write
dec rbx
jmp .loop
.rt_impl:
mov rdi,1
mov rsi,r13
mov rdx,1
mov rax,1
syscall
ret
.translation_start:
mov rax,.rt_impl
call rax
.translation_end:
comma: ; TODO
int3
jmp translate.next
lbrac:
mov rdi,.translation_start
mov rsi,.translation_end
call write
mov word ax,[chunks+r12+2]
mov word [r14-7],ax
and r12,(not CHUNK_MASK)
jmp execute.run
.translation_start:
cmp byte [r13],0
je .jump
add r12,(CHUNK_SIZE)
jmp r14
.jump:
mov r12,0xFFFF
jmp r14
.translation_end:
rbrac:
mov rdi,.translation_start
mov rsi,.translation_end
call write
mov word ax,[chunks+r12+2]
mov word [r14-7],ax
and r12,(not CHUNK_MASK)
jmp execute.run
.translation_start:
cmp byte [r13],0
jne .jump
add r12,(CHUNK_SIZE)
jmp r14
.jump:
mov r12,0xFFFF
jmp r14
.translation_end:
term:
mov rdi,.translation_start
mov rsi,.translation_end
call write
and r12,(not CHUNK_MASK)
jmp execute.run
.translation_start:
mov rdi,0
mov rax,60
syscall
.translation_end:
fail:
mov rdi,1
mov rax,60
syscall
dump:
mov rdi,1
mov rsi,[translations]
mov rdx,(CHUNK_SIZE * MAX_CHUNKS)
mov rax,1
syscall
mov rdi,0
mov rax,60
syscall
key:
mov rdi,0
mov rsi,.ch
mov rdx,1
mov rax,0
syscall
cmp rax,0
je .eof
mov byte al,[.ch]
ret
.eof:
ret
.ch: rb 1
chunks: rw (CHUNK_MAX * MAX_CHUNKS)
mem: db MEM dup 0
translations: rq 1