fix so nasm can compile for testing

This commit is contained in:
janis 2026-06-05 01:24:51 +02:00
parent 44d5e95970
commit 7472eb1279
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8

View file

@ -12,6 +12,10 @@
;; +0x6000 num_labels: u32 ;; +0x6000 num_labels: u32
;; +0x6004 scratch space ;; +0x6004 scratch space
section .data
_start_lbl db "_start", 0
section .text
;; exits the program ;; exits the program
panic: panic:
mov rax, 60 ; syscall: exit mov rax, 60 ; syscall: exit
@ -25,20 +29,21 @@ die:
syscall syscall
;; calculates a quick hash of a byte sequence given by rdi (pointer) and rsi (length) ;; calculates a quick hash of a byte sequence given by rdi (pointer) and rsi (length)
.fashhash_exit:
ret
fasthash: fasthash:
mov eax, 0x811c9dc5 ; FNV offset basis mov eax, 0x811c9dc5 ; FNV offset basis
.fashhash_loop: .fashhash_loop:
test rsi, rsi test rsi, rsi
jz .fashhash_done jz .fashhash_exit
movzx ecx, byte ptr [rdi] ; get next byte movzx ecx, byte [rdi] ; get next byte
xor eax, ecx xor eax, ecx
imul eax, 0x1000193 ; FNV prime imul eax, 0x1000193 ; FNV prime
inc rdi inc rdi
dec rsi dec rsi
jmp .fashhash_loop jmp .fashhash_loop
.fashhash_exit:
ret
;; push the label pointed at by rdi with length rsi, and the current file offset onto the labels array. ;; push the label pointed at by rdi with length rsi, and the current file offset onto the labels array.
push_lbl: push_lbl:
mov eax, dword [r15 + 0x6000] mov eax, dword [r15 + 0x6000]
@ -53,19 +58,14 @@ push_lbl:
mov qword [rdi + rdx], rax ; store hash in labels array mov qword [rdi + rdx], rax ; store hash in labels array
mov eax, dword [r15 + 0x500c] ; get current file offset mov eax, dword [r15 + 0x500c] ; get current file offset
mov dword [rdi + rdx + 8], eax ; store file offset in labels array mov dword [rdi + rdx + 8], eax ; store file offset in labels array
inc dword ptr [r15 + 0x6000] inc dword [r15 + 0x6000]
ret ret
;; searches for the offset of the label with the name pointed at by rdi with length rsi, and returns it in rax. If the label is not found, dies. ;; searches for the offset of the label with the name pointed at by rdi with length rsi, and returns it in rax. If the label is not found, dies.
.find_lbl_not_found:
call panic
.find_lbl_found:
mov eax, dword ptr [rdx + 8] ; get file offset of label
ret
find_lbl: find_lbl:
call fasthash call fasthash
lea rdx, [r15 + 0x5010] ; rdx = pointer to start of labels array lea rdx, [r15 + 0x5010] ; rdx = pointer to start of labels array
mov ebx, dword ptr [r15 + 0x6000] mov ebx, dword [r15 + 0x6000]
.find_lbl_loop: .find_lbl_loop:
test rbx, rbx test rbx, rbx
jz .find_lbl_not_found jz .find_lbl_not_found
@ -75,18 +75,25 @@ find_lbl:
add rdx, 12 ; move to next label entry add rdx, 12 ; move to next label entry
jmp .find_lbl_loop jmp .find_lbl_loop
.find_lbl_not_found:
call panic
.find_lbl_found:
mov eax, dword [rdx + 8] ; get file offset of label
ret
die_jmp_start: die_jmp_start:
;; @_start_lbl: 5F 73 74 61 72 74 00 00 ;; @_start_lbl: 5F 73 74 61 72 74 00 00
lea rdi, [@_start_lbl] ;; lea rdi, [@_start_lbl]
mov rdi, _start_lbl
mov rsi, 6 mov rsi, 6
call find_lbl call find_lbl
add dword [r15 + 0x500c], 5 ; advance the file offset by 5 add dword [r15 + 0x500c], 5 ; advance the file offset by 5
sub eax, dword [r15 + 0x500c] ; add current file offset sub eax, dword [r15 + 0x500c] ; add current file offset
mov edi, dword [r15 + 0x5004] ; get current write cursor mov edi, dword [r15 + 0x5004] ; get current write cursor
lea rdi, [r15 + edi + 0x1000] ; rdi = pointer to write location in write_buf lea rdi, [r15 + rdi + 0x1000] ; rdi = pointer to write location in write_buf
mov byte ptr [rdi], 0xe9 ; write the opcode for jmp rel32 mov byte [rdi], 0xe9 ; write the opcode for jmp rel32
mov dword ptr [rdi + 1], eax ; write the offset of the label reference mov dword [rdi + 1], eax ; write the offset of the label reference
add dword ptr [r15 + 0x5004], 5 ; advance the write cursor by 5 add dword [r15 + 0x5004], 5 ; advance the write cursor by 5
call die call die
;; reads up to 0x1000 bytes from stdin into buf, and sets read_end to the number of bytes read, and resets read_cursor to 0 ;; reads up to 0x1000 bytes from stdin into buf, and sets read_end to the number of bytes read, and resets read_cursor to 0
@ -108,27 +115,28 @@ wrt_stdout:
mov rax, 1 ; syscall: write mov rax, 1 ; syscall: write
mov rdi, 1 ; fd: stdout mov rdi, 1 ; fd: stdout
lea rsi, [r15 + 0x1000] ; buf: pointer to write_buf lea rsi, [r15 + 0x1000] ; buf: pointer to write_buf
mov rdx, dword [r15 + 0x5004] ; count: write_cursor mov edx, dword [r15 + 0x5004] ; count: write_cursor
syscall syscall
mov dword ptr [r15 + 0x5004], 0 mov dword [r15 + 0x5004], 0
ret ret
;; return the next byte from the input ;; return the next byte from the input
;; automatically writes to stdout and reads from stdin if we are at the end of the buffer ;; automatically writes to stdout and reads from stdin if we are at the end of the buffer
.rd_buf_end:
mov eax, dword ptr [r15 + 0x5000] ; get read_cursor
xor rax, rax
mov al, byte ptr [r15 + rax] ; get next byte from buf
inc dword ptr [r15 + 0x5000] ; advance read_cursor
ret
rd_buf: rd_buf:
mov eax, dword ptr [r15 + 0x5000] ; get read_cursor mov eax, dword [r15 + 0x5000] ; get read_cursor
cmp eax, dword ptr [r15 + 0x5008] ; compare to read_end cmp eax, dword [r15 + 0x5008] ; compare to read_end
jl .rd_buf_end jl .rd_buf_end
call wrt_stdout call wrt_stdout
call rd_stdin call rd_stdin
jmp .rd_buf_end jmp .rd_buf_end
.rd_buf_end:
mov edx, dword [r15 + 0x5000] ; get read_cursor
xor rax, rax
mov al, byte [r15 + rdx] ; get next byte from buf
inc dword [r15 + 0x5000] ; advance read_cursor
ret
;; The grammar is slightly updated from hex0, as follows: ;; The grammar is slightly updated from hex0, as follows:
;; program = (label-def / instruction-seq / comment)* ;; program = (label-def / instruction-seq / comment)*
;; comment = ";" [^\n]* "\n" ;; comment = ";" [^\n]* "\n"
@ -144,98 +152,106 @@ rd_buf:
;; whitespace = [ \t\n]+ ;; whitespace = [ \t\n]+
.skip_line_read:
call rd_buf
skip_line: skip_line:
cmp al, '\n' cmp al, `\n`
jne .skip_line_read jne .skip_line_read
call rd_buf call rd_buf
ret ret
.skip_whitespace_read: .skip_line_read:
call rd_buf call rd_buf
jmp skip_line
skip_whitespaces: skip_whitespaces:
cmp al, ' ' cmp al, ' '
je .skip_whitespace_read je .skip_whitespace_read
cmp al, '\t' cmp al, `\t`
je .skip_whitespace_read je .skip_whitespace_read
cmp al, '\n' cmp al, `\n`
je .skip_whitespace_read je .skip_whitespace_read
ret ret
.skip_comment_ret: .skip_whitespace_read:
ret
.skip_comment_read:
call rd_buf call rd_buf
jmp skip_whitespaces
skip_comment: skip_comment:
cmp al, '\;' cmp al, ";"
jne .skip_comment_ret jne .skip_comment_ret
call skip_line call skip_line
ret ret
.skip_comment_ret:
ret
get_next_token:
cmp al, ";"
je .get_next_token_skip
cmp al, ' '
je .get_next_token_skip
cmp al, `\t`
je .get_next_token_skip
cmp al, `\n`
je .get_next_token_skip
ret
.get_next_token_skip: .get_next_token_skip:
call skip_whitespaces call skip_whitespaces
call skip_comment call skip_comment
get_next_token: jmp get_next_token
cmp al, '\;'
je .get_next_token_skip
cmp al, ' '
je .get_next_token_skip
cmp al, '\t'
je .get_next_token_skip
cmp al, '\n'
je .get_next_token_skip
ret
;; read the label into scratch, call push_lbl ;; read the label into scratch, call push_lbl
.label_ret
lea rdi, [r15 + 0x6004] ; rdi = pointer to scratch
call push_lbl
ret
label: label:
lea rdi, [r15 + 0x6004] ; rdi = pointer to scratch cmp al, '@'
jne .not_label
xor rsi, rsi ; rsi = length of label xor rsi, rsi ; rsi = length of label
.label_loop:
push rsi
call rd_buf
pop rsi
lea rdi, [r15 + 0x6004] ; rdi = pointer to scratch
cmp al, ':' cmp al, ':'
je .label_ret je .label_ret
mov byte ptr [rdi + rsi], al mov byte [rdi + rsi], al
inc rsi inc rsi
jmp .label_loop
.label_ret:
lea rdi, [r15 + 0x6004] ; rdi = pointer to scratch
call push_lbl
.not_label:
ret
label_ref:
cmp al, "'"
jne .not_label_ref
call rd_buf call rd_buf
jmp label xor rsi, rsi ; rsi = length of label
.label_ref_loop:
push rsi
call rd_buf
pop rsi
lea rdi, [r15 + 0x6004] ; rdi = pointer to scratch
cmp al, ' '
je .label_ref_ret
cmp al, `\t`
je .label_ref_ret
cmp al, `\n`
je .label_ref_ret
mov byte [rdi + rsi], al
inc rsi
jmp .label_ref_loop
.label_ref_ret: .label_ref_ret:
lea rdi, [r15 + 0x6004] lea rdi, [r15 + 0x6004]
call find_lbl call find_lbl
add dword ptr [r15 + 0x500c], 4 ; advance the file offset by 4 add dword [r15 + 0x500c], 4 ; advance the file offset by 4
sub eax, dword ptr [r15 + 0x500c] ; add current file offset sub eax, dword [r15 + 0x500c] ; add current file offset
mov edi, dword ptr [r15 + 0x5004] ; get current write cursor mov edi, dword [r15 + 0x5004] ; get current write cursor
mov dword ptr [r15 + 0x1000 + rdi], eax ; write the opcode for jmp rel32 mov dword [r15 + 0x1000 + rdi], eax ; write the opcode for jmp rel32
add dword ptr [r15 + 0x5004], 4 ; advance the write cursor by 4 add dword [r15 + 0x5004], 4 ; advance the write cursor by 4
.not_label_ref:
ret ret
label_ref:
lea rdi, [r15 + 0x6004] ; rdi = pointer to scratch
xor rsi, rsi
call rd_buf
cmp al, ' '
je .label_ref_ret
cmp al, '\t'
je .label_ref_ret
cmp al, '\n'
je .label_ref_ret
mov byte ptr [rdi + rsi], al
inc rsi
jmp label_ref
.invalid_hex:
call panic
.is_digit:
sub al, '0'
ret
.is_lower_hex:
sub al, 'a' - 10
ret
.is_upper_hex:
sub al, 'A' - 10
ret
char_to_u4: char_to_u4:
cmp al, '0' cmp al, '0'
jb .invalid_hex jb .invalid_hex
@ -251,35 +267,52 @@ char_to_u4:
jbe .is_upper_hex jbe .is_upper_hex
jmp .invalid_hex jmp .invalid_hex
.invalid_hex:
call panic
.is_digit:
sub al, '0'
ret
.is_lower_hex:
sub al, 'a' - 10
ret
.is_upper_hex:
sub al, 'A' - 10
ret
octet: octet:
sub rsp, 8 sub rsp, 8
call char_to_u4 call char_to_u4
shl rax, 4 mov byte [rsp], al
mov byte ptr [rsp], al
call rd_buf call rd_buf
call char_to_u4 call char_to_u4
or byte ptr [rsp], al mov bl, byte [rsp]
mov al, byte ptr [rsp] shl bl, 4
or al, bl
mov edi, dword [r15 + 0x5004] ; get current write cursor
lea rdx, [r15 + 0x1000]
mov byte [rdi + rdx], al ; write the byte to the write_buf
inc dword [r15 + 0x5004] ; advance the write cursor by 1
inc dword [r15 + 0x500c] ; advance file offset by 1
add rsp, 8 add rsp, 8
inc file_offset
ret ret
global _start
_start: _start:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
sub rsp, 0x8000 ; allocate space for our variables + some scratch space sub rsp, 0x8000 ; allocate space for our variables + some scratch space
mov r15, rsp ; r15 will point to the start of our variables mov r15, rsp ; r15 will point to the start of our variables
mov dword [r15 + 0x6000], 0 ; num_labels = 0
mov dword [r15 + 0x500c], 0 ; file_offset = 0
mov dword [r15 + 0x5008], 0 ; read_end = 0
mov dword [r15 + 0x5004], 0 ; write_cursor = 0
mov dword [r15 + 0x5000], 0 ; read_cursor = 0
call rd_buf
.loop: .loop:
call rd_buf
call get_next_token call get_next_token
cmp al, '@'
;; label
call label call label
cmp al, '\''
;; label-ref
call label_ref call label_ref
;; else opcode
call octet call octet
jmp .loop jmp .loop