343 lines
5.5 KiB
NASM
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
|