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 byte [r14-7],al shr rax,8 mov byte [r14-6],al 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 byte [r14-7],al shr rax,8 mov byte [r14-6],al 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