246 lines
4.1 KiB
NASM
246 lines
4.1 KiB
NASM
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 esi, $$
|
|
mov ecx, headers_length
|
|
rep movsb
|
|
|
|
.copy_init:
|
|
mov esi, init_code
|
|
mov ecx, init_code_length
|
|
rep movsb
|
|
|
|
mov rbp, rdi
|
|
|
|
mainloop:
|
|
; Read one byte
|
|
xor eax, eax
|
|
xor edi, edi
|
|
mov rsi, rbp
|
|
xor edx, edx
|
|
inc edx
|
|
syscall
|
|
|
|
.was_eof:
|
|
test eax, eax
|
|
jz end
|
|
|
|
mov al, [rbp]
|
|
|
|
mov ecx, 8
|
|
mov ebx, command_table
|
|
xor edx, edx
|
|
|
|
.table_find:
|
|
mov dl, [ebx+1]
|
|
cmp al, [ebx]
|
|
je .table_found
|
|
add dl, 2
|
|
add ebx, edx
|
|
loop .table_find
|
|
xor edx, edx
|
|
|
|
.table_found:
|
|
lea esi, [ebx + 2]
|
|
|
|
mov rdi, rbp
|
|
mov ecx, edx
|
|
rep movsb
|
|
mov rbp, rdi
|
|
|
|
jmp mainloop
|
|
|
|
end:
|
|
.copy_end_code:
|
|
mov esi, end_code
|
|
mov rdi, rbp
|
|
mov ecx, 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 eax
|
|
xor ebx, ebx
|
|
mov byte bl, [while_length]
|
|
sub eax, ebx
|
|
|
|
; Store in our displacement field
|
|
mov rdi, rsi
|
|
dec rdi
|
|
stosd
|
|
|
|
; Move to next instruction
|
|
mov rsi, rdi
|
|
jmp .fixup_loop
|
|
|
|
.fixup_done:
|
|
|
|
xor ebx, ebx
|
|
.output_loop:
|
|
mov rsi, rsp
|
|
add rsi, rbx
|
|
cmp rsi, rbp
|
|
|
|
je .exit
|
|
xor eax, eax
|
|
inc eax
|
|
mov edi, eax
|
|
mov edx, eax
|
|
syscall
|
|
|
|
inc ebx
|
|
jmp .output_loop
|
|
|
|
.exit:
|
|
mov eax, 60
|
|
xor edi, edi
|
|
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
|
|
xor eax, eax
|
|
xor edi, edi
|
|
mov rsi, rbx
|
|
xor edx, edx
|
|
inc edx
|
|
syscall
|
|
putc: db '.', ._end - $ - 2
|
|
xor eax, eax
|
|
inc eax
|
|
mov edi, eax
|
|
mov rsi, rbx
|
|
mov edx, eax
|
|
syscall
|
|
._end:
|
|
|
|
init_code:
|
|
mov ecx, 0x10000 ; 64KiB of memory
|
|
|
|
; Clear out the memory
|
|
sub rsp, rcx
|
|
mov rdi, rsp
|
|
xor al, al
|
|
rep stosb
|
|
|
|
; Initialize tape head
|
|
mov rbx, rsp
|
|
|
|
init_code_length equ $ - init_code
|
|
|
|
end_code:
|
|
mov rax, 60
|
|
xor edi, edi
|
|
syscall
|
|
|
|
end_code_length equ $ - end_code
|
|
|
|
_end:
|