diff --git a/code/asm/hello_files.asm b/code/asm/hello_files.asm index 1a9caf1..fc74901 100644 --- a/code/asm/hello_files.asm +++ b/code/asm/hello_files.asm @@ -3,11 +3,12 @@ BITS 64 ; Explicitly specify 64-bit mode DEFAULT REL ; Use RIP-relative addressing by default +%define BUILD_DEBUG 1 + ;region DSL %define marg -%define rcounter_32 ecx - +%define rcounter_32 ecx %define r8_32 r8d %define raccumulator rax @@ -15,26 +16,80 @@ DEFAULT REL ; Use RIP-relative addressing by default %define rdata rdx %define rstack_ptr rsp %define rstack_base_ptr rbp +;endregion DSL -%define reg9 r9 -;endregion +;region Registers -;region debug +; Wipes all 64-bit general-purpose registers except for the stack pointer (RSP). +; Zeroing RSP would corrupt the stack and crash the program. +; Zeroing RBP will break the stack frame chain used by debuggers. +%macro wipe_gprs 0 + xor rax, rax + xor rbx, rbx + xor rcx, rcx + xor rdx, rdx + xor rsi, rsi + xor rdi, rdi + ; xor rbp, rbp + xor r8, r8 + xor r9, r9 + xor r10, r10 + xor r11, r11 + xor r12, r12 + xor r13, r13 + xor r14, r14 + xor r15, r15 +%endmacro +;endregion Registers + +;region Debug %define debug_trap 3 -;endregion + +%ifidn BUILD_DEBUG, 1 + %macro assert_not_null 1 + cmp %1, nullptr + jnz %%.passed + int debug_trap + %%.passed: ; macro-unique-prefix (%%) .passed is the label name + %endmacro + %macro slice_assert 1 + cmp qword [%1 + Slice.ptr], 0 + jnz %%.ptr_passed + int debug_trap + %%.ptr_passed: + cmp qword [%1 + Slice.len] + jg %%.len_passed + int debug_trap + %%.len_passed: + %endmacro + %define dbg_wipe_gprs wipe_gprs +%else + %macro assert_not_null 1 + %endmacro + %macro slice_assert 1 + %endmacro + %define dbg_wipe_gprs +%endif ; BUILD_DEBUG +;endregion Debug ;region Memory +%define nullptr 0 %define kilo 1024 -%define nullptr 0 - -%macro assert_not_null 1 - cmp %1, nullptr - jnz %%+.passed - int debug_trap -%%+.passed ; macro-unique-prefix (%%) + internal expansion .passed is the label name +; Usage: def_array +%macro def_farray 2+ + struc %1 + .ptr: resb %2 + endstruc %endmacro +def_farray Mem_128k, 128 * kilo + +struc Slice + .ptr: resq 1 + .len: resq 1 +endstruc + ; Usage: def_Slice %1: %macro def_Slice 1 struc Slice_ %+ %1 @@ -44,26 +99,36 @@ DEFAULT REL ; Use RIP-relative addressing by default %endmacro def_Slice Byte -def_Slice Str8 ;endregion Memory -;region Str8 Table +;region Strings +def_Slice Str8 + ; Usage: lit %1: , %2: +; Both the struct and the string data are emitted into the current section. %macro lit 2 - lit_ %+ %1: db %2 - lit_ %+ %1 %+ _len: equ $ - (lit_ %+ %1) + %%str_data: db %2 + %%str_len: equ $ - %%str_data + %1: + istruc Slice_Str8 + ; Store the ADDRESS of the string data in the ptr field. + at Slice_Str8.ptr, dq %%str_data + ; Store the pre-calculated LENGTH in the len field. + at Slice_Str8.len, dq %%str_len + iend %endmacro ; Usage: stack_slice %1: , %2 -%macro stack_slice %2 - +%macro stack_slice 2 +; Gemini finish this definition for me %endmacro section .lits progbits noexec nowrite lit path_hello_files_asm, `./code/asm/hello_files.asm` -;endregion Str8 Table +;endregion Strings ;region WinAPI + ; kernel32.lib ; Console IO extern GetStdHandle @@ -85,52 +150,105 @@ extern ReadFile %define wapi_arg4_offset 28 %define wapi_arg5_offset 32 -%define wapi_write_console_written_chars reg9 +%define wapi_write_console_written_chars r9 %macro wapi_write_console 2 mov rcounter,[%1] ; Console Handle lea rdata, [%2] ; Slice_Str8.Ptr mov r8_32, %2 %+ _len ; Slice_Str8.Len - lea reg9, [rstack_ptr + wapi_arg4_offset] ; Written chars + lea r9, [rstack_ptr + wapi_arg4_offset] ; Written chars mov qword [rstack_ptr + wapi_arg5_offset], 0 ; Reserved (must be 0) call WriteConsoleA %endmacro section .data std_out_hndl dq 0 -;endregion +;endregion WinAPI -api_file_read_contents: - section .text - %define result ;TODO(Ed): figure out the convention - %define path ;TODO(Ed): figure out the convention - %define backing ;TODO(Ed): figure out the convention +struc FileOpInfo + .content: resb Slice_Byte_size ; gemini is this allowed? +endstruc - assert_not_null result - slice_assert path - slice_assert backing - ; local_persist scratch_kilo: [64 * kilo]U8; (api_file_read_contents.scratch_kilo) - - %define slice_fmem_scratch ;TODO(Ed): figure this out - call str8_to_cstr_capped path_c_str, path, slice_fmem_scratch - - ; TODO(Ed): Form-fill - call CreateFileA - - leave - ret - - section .bss - api_file_read_contents.scratch_kilo: resb 64 * kilo - api_file_read_contents.path_cstr: resq 1 +;region api_file_read_contents +; Reg allocation: +; result: rcounter = [FileOpInfo] +; path: Slice_Str8 = { .ptr = rdata, .len = r8 } +; backing: r9 = [Slice_Byte] +%push api_file_read_contents +%define result rcounter +%define path_ptr rdata +%define path_len r8 +%define backing r9 section .text -global main +api_file_read_contents: + assert_not_null result + ; slice_assert path + ; slice_assert backing + ; local_persist scratch_kilo: [64 * kilo]U8; (api_file_read_contents.scratch_kilo) -main: - wapi_shadow_space + ; %define slice_fmem_scratch ;TODO(Ed): figure this out + ; call str8_to_cstr_capped path_c_str, path, slice_fmem_scratch ; TODO(Ed): Form-fill - call api_file_read_contents + ; call CreateFileA leave ret + +section .bss + api_file_read_contents.scratch_kilo: resb 64 * kilo + api_file_read_contents.path_cstr: resq 1 +%pop api_file_read_contents +;endregion api_file_read_contents + +; Args: result: [FileOpInfo], path: Slice_Str8, backing: [Slice_Byte] +%macro file_read_contents 3 + %push rcounter + %push rdata + %push r8 + %push r9 + lea rcounter, %1 + lea rdata, [%2 + Slice.ptr] + mov r8, %2 + Slice.len + lea r9, %3 + call api_file_read_contents + %pop r9 + %pop r8 + %pop rdata + %pop rcounter +%endmacro + + +section .text +global main + main: + ; dbg_wipe_gprs + + %push calling + %define stack_alloc (Slice_Byte_size) + push rstack_base_ptr + mov rstack_base_ptr, rstack_ptr + sub rstack_ptr, -stack_alloc + + %define local_backing (rstack_base_ptr - stack_alloc) + + mov qword [local_backing + Slice_Byte.ptr], read_mem + mov qword [local_backing + Slice_Byte.len], Mem_128k_size + + lea rcounter, file + lea rdata, [path_hello_files_asm + Slice.ptr] + mov r8, path_hello_files_asm + Slice.len + lea r9, [local_backing] + call api_file_read_contents + %pop calling + + ; file_read_contents file, path_hello_files_asm, read_mem + + mov rstack_ptr, rstack_base_ptr + pop rstack_base_ptr + ret + +section .bss +read_mem: resb Mem_128k_size + +file: resb FileOpInfo_size diff --git a/scripts/build_hello_files.ps1 b/scripts/build_hello_files.ps1 index c911ea8..87bb2bb 100644 --- a/scripts/build_hello_files.ps1 +++ b/scripts/build_hello_files.ps1 @@ -39,6 +39,7 @@ $args = @( $hello_nasm, $f_optimize_none, # $f_preprocess_only, + # ($f_dmacro + "BUILD_DEBUG 1"), $f_bin_fmt_win64, $f_debug_fmt_win64, ($f_listing + $listing), @@ -54,6 +55,7 @@ $link = 'link.exe' $link_debug = '/DEBUG:' $link_entrypoint = '/ENTRY:' $link_library = '/' +$link_large_address_aware = '/LARGEADDRESSAWARE:NO' $link_outfile = '/OUT:' $link_win_machine_64 = '/MACHINE:X64' $link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' @@ -62,8 +64,10 @@ $rad_debug = '/RAD_DEBUG' $rad_debug_name = '/RAD_DEBUG_NAME:' $rad_large_pages = '/RAD_LARGE_PAGES:' $args = @( - $rad_debug, + $link_debug, + # $rad_debug, # ($link_debug + 'FULL'), + $link_large_address_aware, $link_win_machine_64, $link_win_subsystem_console, $lib_kernel32,