BITS 64 org 0x400000 elf_header: db 0x7f, "ELF" db 2 ; 64 bit db 1 ; little-endian db 1 ; header version 1 db 0 ; SysV ABI times 8 db 0 ; padding dw 2 ; executable dw 0x3e ; amd64 dd 1 ; ELF version 1 dq _start ; entry point dq program_headers - $$ ; program header table offset dq 0 ; section header table offset, not needed in executables dd 0 ; flags, unsused on x86 dw elf_header_length ; header length dw program_header_size ; size of one entry in program header table dw 1 ; 1 entry dw 0 ; size of one entry in section header table dw 0 ; number of entries in the section header table dw 0 ; section name index in section header table elf_header_length equ $ - elf_header program_headers: dd 1 ; loadable segment dd 4 + 1 ; readable + executable dq 0 ; offset of contents dq $$ ; location in virtual memory dq 0 ; undefined fsize_offset equ $ - $$ dq _end - $$ ; size of segment in file msize_offset equ $ - $$ dq _end - $$ ; size of segment in memory dq 0x1000 ; 4KiB alignment program_header_size equ $ - program_headers headers_length equ $ - elf_header _start: sub rsp, 0x10000 ; 64KiB of scratch space mov rdi, rsp .copy_header: mov rsi, $$ mov rcx, headers_length rep movsb .copy_init: mov rsi, init_code mov rcx, init_code_length rep movsb mov rbp, rdi mainloop: ; Read one byte mov rax, 0 mov rdi, 0 mov rsi, rbp mov rdx, 1 syscall .was_eof: test rax, rax jz end mov al, [rbp] mov rcx, 8 mov rbx, command_table xor rdx, rdx .table_find: mov dl, [rbx+1] cmp al, [rbx] je .table_found add dl, 2 add rbx, rdx loop .table_find xor rdx, rdx .table_found: lea rsi, [rbx + 2] mov rdi, rbp mov rcx, rdx rep movsb mov rbp, rdi jmp mainloop end: .copy_end_code: mov rsi, end_code mov rdi, rbp mov rcx, end_code_length rep movsb mov rbp, rdi .adjust_header_sizes: mov rcx, rdi sub rcx, rsp mov [rsp + fsize_offset], rcx mov [rsp + msize_offset], rcx mov rsi, rsp add rsi, headers_length .fixup_loop: cmp rsi, rbp je .fixup_done lodsb cmp al, 0xe9 ; Relative jump jne .fixup_loop lodsb .is_forwards: test al, al jnz .is_backwards ; Push our current location (one byte after the start of the displacement) push rsi jmp .fixup_loop .is_backwards: cmp al, 1 jnz .fixup_loop ; Get matching ['s location pop rdi ; Distance between the locations = distance between jumps = displacement when jumping forwards mov rax, rsi sub rax, rdi ; Store in ['s displacement field dec rdi stosd ; Jumping backwards, we need to invert the displacement and then account for the size of the [ neg rax xor rbx, rbx mov byte bl, [while_length] sub rax, rbx ; Store in our displacement field mov rdi, rsi dec rdi stosd ; Move to next instruction mov rsi, rdi jmp .fixup_loop .fixup_done: xor rbx, rbx .output_loop: mov rsi, rsp add rsi, rbx cmp rsi, rbp je .exit mov rax, 1 mov rdi, 1 mov rdx, 1 syscall inc rbx jmp .output_loop .exit: mov rax, 60 xor rdi, rdi syscall command_table: plus: db '+', minus - $ - 2 inc byte [rbx] minus: db '-', right - $ - 2 dec byte [rbx] right: db '>', left - $ - 2 inc rbx left: db '<', while - $ - 2 dec rbx while: db '[' while_length: db wend - $ - 1 cmp byte [rbx], 0 jne .skip ; Reserve space for jump forwards, tag with 0x00000000 db 0xe9 times 4 db 0 .skip: wend: db ']', getc - $ - 2 ; Reserve space for jump backwards, tag with 0x01000000 db 0xe9 db 1 times 3 db 0 getc: db ',', putc - $ - 2 mov byte [rbx], 0 mov rax, 0 mov rdi, 0 mov rsi, rbx mov rdx, 1 syscall putc: db '.', ._end - $ - 2 mov rax, 1 mov rdi, 0 mov rsi, rbx mov rdx, 1 syscall ._end: init_code: mov rcx, 0x10000 ; 64KiB of memory sub rsp, rcx mov rdi, rsp mov rbx, rdi xor al, al rep stosb init_code_length equ $ - init_code end_code: mov rax, 60 xor rdi, rdi syscall end_code_length equ $ - end_code _end: