Compare commits
31 Commits
99e8e4072b
...
main
Author | SHA1 | Date | |
---|---|---|---|
172be7bfd8 | |||
af05912d8b | |||
f8ac822458 | |||
682401c731 | |||
a3e56b9394 | |||
62d2773e6f | |||
f35b738da2 | |||
5ea4b5426c | |||
bcbdd2c0a2 | |||
9bc1e59bdb | |||
39b4be9d7a | |||
c8f513f386 | |||
0b2ba408c7 | |||
c1b8f935e0 | |||
a56fc1a454 | |||
ec884ba88e | |||
86b964b6c5 | |||
bc0d81f9bc | |||
4654fda9f7 | |||
b1b401784a | |||
032e91a81f | |||
e49258c8c2 | |||
06212960ce | |||
a54f4b0b57 | |||
80c830b59d | |||
531daa38c1 | |||
da70d0adf9 | |||
03b272d91e | |||
dceb330571 | |||
8a974e9c89 | |||
dbfd94ea40 |
30
.editorconfig
Normal file
30
.editorconfig
Normal file
@@ -0,0 +1,30 @@
|
||||
root = true
|
||||
|
||||
[*.asm]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.refactor]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.{h, c, hpp, cpp}]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.{ps1, psm1}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.odin]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
[*.{natvis, natstepfilter}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -0,0 +1,4 @@
|
||||
build/**
|
||||
.vscode/settings.json
|
||||
code/asm/hello_files.proj
|
||||
asm_dip
|
||||
|
37
.vscode/c_cpp_propertiees.json
vendored
Normal file
37
.vscode/c_cpp_propertiees.json
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32 msvc",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/source/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
"INTELLISENSE_DIRECTIVES"
|
||||
],
|
||||
"windowsSdkVersion": "10.0.19041.0",
|
||||
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe",
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"compileCommands": "${workspaceFolder}/project/build/compile_commands.json"
|
||||
},
|
||||
{
|
||||
"name": "Win32 clang",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/source/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
"INTELLISENSE_DIRECTIVES"
|
||||
],
|
||||
"windowsSdkVersion": "10.0.19041.0",
|
||||
"compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe",
|
||||
"intelliSenseMode": "windows-clang-x64",
|
||||
"compileCommands": "${workspaceFolder}/project/build/compile_commands.json"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
3
code/asm.odin
Normal file
3
code/asm.odin
Normal file
@@ -0,0 +1,3 @@
|
||||
package asmduff // ASM Duffle
|
||||
|
||||
|
178
code/asm/asm.user
Normal file
178
code/asm/asm.user
Normal file
@@ -0,0 +1,178 @@
|
||||
// raddbg 0.9.18 user file
|
||||
|
||||
window:
|
||||
{
|
||||
size: 1536.000000 864.000000
|
||||
panels:
|
||||
{
|
||||
0.25:
|
||||
{
|
||||
0.25:
|
||||
{
|
||||
watch:
|
||||
{
|
||||
expression: ""
|
||||
selected
|
||||
}
|
||||
watch: expression: "query:types"
|
||||
}
|
||||
0.25:
|
||||
{
|
||||
watch:
|
||||
{
|
||||
expression: "query:threads"
|
||||
selected
|
||||
}
|
||||
watch: expression: "query:targets"
|
||||
watch: expression: "query:breakpoints"
|
||||
watch: expression: "query:watch_pins"
|
||||
}
|
||||
0.25:
|
||||
{
|
||||
disasm:
|
||||
{
|
||||
expression: ""
|
||||
selected
|
||||
}
|
||||
text: expression: "query:output"
|
||||
}
|
||||
0.25:
|
||||
{
|
||||
watch:
|
||||
{
|
||||
expression: "query:call_stack"
|
||||
selected
|
||||
}
|
||||
watch: expression: "query:modules"
|
||||
}
|
||||
}
|
||||
0.75:
|
||||
{
|
||||
getting_started: selected
|
||||
selected
|
||||
}
|
||||
}
|
||||
split_x
|
||||
pos: 26 26
|
||||
monitor: "\\\\.\\DISPLAY1"
|
||||
}
|
||||
keybindings:
|
||||
{
|
||||
{ kill_all f5 shift }
|
||||
{ step_into_inst f11 alt }
|
||||
{ step_over_inst f10 alt }
|
||||
{ step_out f11 shift }
|
||||
{ halt x ctrl shift }
|
||||
{ halt pause }
|
||||
{ run f5 }
|
||||
{ restart f5 ctrl shift }
|
||||
{ step_into f11 }
|
||||
{ step_over f10 }
|
||||
{ run_to_line f10 ctrl }
|
||||
{ set_next_statement f10 ctrl shift }
|
||||
{ inc_window_font_size equal alt }
|
||||
{ dec_window_font_size minus alt }
|
||||
{ window n ctrl shift }
|
||||
{ toggle_fullscreen return ctrl }
|
||||
{ new_panel_right p ctrl }
|
||||
{ new_panel_down minus ctrl }
|
||||
{ rotate_panel_columns 2 ctrl }
|
||||
{ next_panel comma ctrl }
|
||||
{ prev_panel comma ctrl shift }
|
||||
{ focus_panel_right right ctrl alt }
|
||||
{ focus_panel_left left ctrl alt }
|
||||
{ focus_panel_up up ctrl alt }
|
||||
{ focus_panel_down down ctrl alt }
|
||||
{ undo z ctrl }
|
||||
{ redo y ctrl }
|
||||
{ go_back left alt }
|
||||
{ go_forward right alt }
|
||||
{ close_panel p ctrl shift alt }
|
||||
{ next_tab page_down ctrl }
|
||||
{ prev_tab page_up ctrl }
|
||||
{ next_tab tab ctrl }
|
||||
{ prev_tab tab ctrl shift }
|
||||
{ move_tab_right page_down ctrl shift }
|
||||
{ move_tab_left page_up ctrl shift }
|
||||
{ close_tab w ctrl }
|
||||
{ tab_bar_top up ctrl shift alt }
|
||||
{ tab_bar_bottom down ctrl shift alt }
|
||||
{ open_tab t ctrl }
|
||||
{ open o ctrl }
|
||||
{ switch i ctrl }
|
||||
{ switch_to_partner_file o alt }
|
||||
{ open_user n ctrl shift alt }
|
||||
{ open_project n ctrl alt }
|
||||
{ open_user o ctrl shift alt }
|
||||
{ open_project o ctrl alt }
|
||||
{ save_user s ctrl shift alt }
|
||||
{ save_project s ctrl shift }
|
||||
{ edit f2 }
|
||||
{ accept return }
|
||||
{ accept space }
|
||||
{ cancel esc }
|
||||
{ move_left left }
|
||||
{ move_right right }
|
||||
{ move_up up }
|
||||
{ move_down down }
|
||||
{ move_left_select left shift }
|
||||
{ move_right_select right shift }
|
||||
{ move_up_select up shift }
|
||||
{ move_down_select down shift }
|
||||
{ move_left_chunk left ctrl }
|
||||
{ move_right_chunk right ctrl }
|
||||
{ move_up_chunk up ctrl }
|
||||
{ move_down_chunk down ctrl }
|
||||
{ move_up_page page_up }
|
||||
{ move_down_page page_down }
|
||||
{ move_up_whole home ctrl }
|
||||
{ move_down_whole end ctrl }
|
||||
{ move_left_chunk_select left ctrl shift }
|
||||
{ move_right_chunk_select right ctrl shift }
|
||||
{ move_up_chunk_select up ctrl shift }
|
||||
{ move_down_chunk_select down ctrl shift }
|
||||
{ move_up_page_select page_up shift }
|
||||
{ move_down_page_select page_down shift }
|
||||
{ move_up_whole_select home ctrl shift }
|
||||
{ move_down_whole_select end ctrl shift }
|
||||
{ move_up_reorder up alt }
|
||||
{ move_down_reorder down alt }
|
||||
{ move_home home }
|
||||
{ move_end end }
|
||||
{ move_home_select home shift }
|
||||
{ move_end_select end shift }
|
||||
{ select_all a ctrl }
|
||||
{ delete_single delete }
|
||||
{ delete_chunk delete ctrl }
|
||||
{ backspace_single backspace }
|
||||
{ backspace_chunk backspace ctrl }
|
||||
{ copy c ctrl }
|
||||
{ copy insert ctrl }
|
||||
{ cut x ctrl }
|
||||
{ paste v ctrl }
|
||||
{ paste insert shift }
|
||||
{ insert_text null }
|
||||
{ move_next tab }
|
||||
{ move_prev tab shift }
|
||||
{ goto_line g ctrl }
|
||||
{ goto_address g alt }
|
||||
{ search f ctrl }
|
||||
{ search_backwards r ctrl }
|
||||
{ find_next f3 }
|
||||
{ find_prev f3 ctrl }
|
||||
{ find_selected_thread f4 }
|
||||
{ goto_name j ctrl }
|
||||
{ goto_name_at_cursor f12 }
|
||||
{ toggle_watch_expr_at_cursor w alt }
|
||||
{ toggle_watch_expr_at_mouse d ctrl }
|
||||
{ toggle_watch_pin f9 ctrl }
|
||||
{ toggle_breakpoint f9 }
|
||||
{ add_address_breakpoint f9 shift }
|
||||
{ add_function_breakpoint f9 ctrl shift }
|
||||
{ attach f6 shift }
|
||||
{ open_palette f1 }
|
||||
{ open_palette p ctrl shift }
|
||||
{ log_marker m ctrl shift alt }
|
||||
{ toggle_dev_menu d ctrl shift alt }
|
||||
}
|
||||
current_path: "C:/users/ed/appdata/roaming/raddbg"
|
712
code/asm/hello_arenas.asm
Normal file
712
code/asm/hello_arenas.asm
Normal file
@@ -0,0 +1,712 @@
|
||||
; Hello Files!
|
||||
|
||||
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 rdata_32 edx
|
||||
%define r8_32 r8d
|
||||
%define r9_32 r9d
|
||||
|
||||
%define raccumulator rax
|
||||
%define rbase rbx
|
||||
%define rcounter rcx
|
||||
%define rdata rdx
|
||||
%define rdst_id rdi
|
||||
%define rsrc_id rsi
|
||||
%define rstack_ptr rsp
|
||||
%define rstack_base_ptr rbp
|
||||
|
||||
%define false 0
|
||||
%define true 1
|
||||
%define true_overflow 2
|
||||
;endregion DSL
|
||||
|
||||
;region Registers
|
||||
|
||||
; 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
|
||||
|
||||
; Resets the Floating-Point Unit (FPU), which also clears all MMX registers
|
||||
; (MM0-MM7) and FPU stack registers (ST0-ST7).
|
||||
%macro wipe_fpu_mmxs 0
|
||||
finit
|
||||
%endmacro
|
||||
|
||||
; Wipes the 128-bit XMM registers. Requires a CPU with at least SSE.
|
||||
%macro wipe_xmms 0
|
||||
vxorps xmm0, xmm0, xmm0
|
||||
vxorps xmm1, xmm1, xmm1
|
||||
vxorps xmm2, xmm2, xmm2
|
||||
vxorps xmm3, xmm3, xmm3
|
||||
vxorps xmm4, xmm4, xmm4
|
||||
vxorps xmm5, xmm5, xmm5
|
||||
vxorps xmm6, xmm6, xmm6
|
||||
vxorps xmm7, xmm7, xmm7
|
||||
vxorps xmm8, xmm8, xmm8
|
||||
vxorps xmm9, xmm9, xmm9
|
||||
vxorps xmm10, xmm10, xmm10
|
||||
vxorps xmm11, xmm11, xmm11
|
||||
vxorps xmm12, xmm12, xmm12
|
||||
vxorps xmm13, xmm13, xmm13
|
||||
vxorps xmm14, xmm14, xmm14
|
||||
vxorps xmm15, xmm15, xmm15
|
||||
%endmacro
|
||||
|
||||
; =============================================================================
|
||||
; AVX Registers (YMM0-YMM15)
|
||||
; =============================================================================
|
||||
; Wipes the 256-bit YMM registers. Requires a CPU with AVX support.
|
||||
; This also wipes the lower 128 bits (the XMM registers), so you don't
|
||||
; need to call WIPE_XMM_REGS if you call this one.
|
||||
%macro wipe_ymms 0
|
||||
vzeroupper ; Clears upper 128 bits of all YMM registers
|
||||
vxorps ymm0, ymm0, ymm0 ; Clears the full YMM0 (including lower XMM0)
|
||||
vxorps ymm1, ymm1, ymm1
|
||||
vxorps ymm2, ymm2, ymm2
|
||||
vxorps ymm3, ymm3, ymm3
|
||||
vxorps ymm4, ymm4, ymm4
|
||||
vxorps ymm5, ymm5, ymm5
|
||||
vxorps ymm6, ymm6, ymm6
|
||||
vxorps ymm7, ymm7, ymm7
|
||||
vxorps ymm8, ymm8, ymm8
|
||||
vxorps ymm9, ymm9, ymm9
|
||||
vxorps ymm10, ymm10, ymm10
|
||||
vxorps ymm11, ymm11, ymm11
|
||||
vxorps ymm12, ymm12, ymm12
|
||||
vxorps ymm13, ymm13, ymm13
|
||||
vxorps ymm14, ymm14, ymm14
|
||||
vxorps ymm15, ymm15, ymm15
|
||||
%endmacro
|
||||
|
||||
; =============================================================================
|
||||
; AVX-512 Registers (ZMM0-ZMM31 and K0-K7)
|
||||
; =============================================================================
|
||||
; Wipes the 512-bit ZMM registers and the 8 mask registers (k0-k7).
|
||||
; Requires a CPU with AVX-512F support. This is the most comprehensive
|
||||
; vector register wipe and makes WIPE_XMM_REGS and WIPE_YMM_REGS redundant.
|
||||
%macro wipe_avx512s 0
|
||||
; Wipe Mask Registers (k0-k7)
|
||||
kxorb k0, k0, k0
|
||||
kxorb k1, k1, k1
|
||||
kxorb k2, k2, k2
|
||||
kxorb k3, k3, k3
|
||||
kxorb k4, k4, k4
|
||||
kxorb k5, k5, k5
|
||||
kxorb k6, k6, k6
|
||||
kxorb k7, k7, k7
|
||||
|
||||
; Wipe ZMM registers (zmm0-zmm31)
|
||||
vpxord zmm0, zmm0, zmm0
|
||||
vpxord zmm1, zmm1, zmm1
|
||||
vpxord zmm2, zmm2, zmm2
|
||||
vpxord zmm3, zmm3, zmm3
|
||||
vpxord zmm4, zmm4, zmm4
|
||||
vpxord zmm5, zmm5, zmm5
|
||||
vpxord zmm6, zmm6, zmm6
|
||||
vpxord zmm7, zmm7, zmm7
|
||||
vpxord zmm8, zmm8, zmm8
|
||||
vpxord zmm9, zmm9, zmm9
|
||||
vpxord zmm10, zmm10, zmm10
|
||||
vpxord zmm11, zmm11, zmm11
|
||||
vpxord zmm12, zmm12, zmm12
|
||||
vpxord zmm13, zmm13, zmm13
|
||||
vpxord zmm14, zmm14, zmm14
|
||||
vpxord zmm15, zmm15, zmm15
|
||||
vpxord zmm16, zmm16, zmm16
|
||||
vpxord zmm17, zmm17, zmm17
|
||||
vpxord zmm18, zmm18, zmm18
|
||||
vpxord zmm19, zmm19, zmm19
|
||||
vpxord zmm20, zmm20, zmm20
|
||||
vpxord zmm21, zmm21, zmm21
|
||||
vpxord zmm22, zmm22, zmm22
|
||||
vpxord zmm23, zmm23, zmm23
|
||||
vpxord zmm24, zmm24, zmm24
|
||||
vpxord zmm25, zmm25, zmm25
|
||||
vpxord zmm26, zmm26, zmm26
|
||||
vpxord zmm27, zmm27, zmm27
|
||||
vpxord zmm28, zmm28, zmm28
|
||||
vpxord zmm29, zmm29, zmm29
|
||||
vpxord zmm30, zmm30, zmm30
|
||||
vpxord zmm31, zmm31, zmm31
|
||||
%endmacro
|
||||
;endregion Registers
|
||||
|
||||
;region Debug
|
||||
%define debug_trap 3
|
||||
|
||||
%ifidn BUILD_DEBUG, 1
|
||||
%macro assert_cmp 3
|
||||
cmp %2, %3
|
||||
%1 %%.passed
|
||||
int debug_trap
|
||||
%%.passed:
|
||||
%endmacro
|
||||
%macro assert_not_null 1
|
||||
cmp %1, nullptr
|
||||
jnz %%.passed
|
||||
int debug_trap
|
||||
%%.passed: ; macro-unique-prefix (%%) .passed is the label name
|
||||
%endmacro
|
||||
%define dbg_wipe_gprs wipe_gprs
|
||||
%define dbg_wipe_fpu_mmxs wipe_fpu_mmxs
|
||||
%define dbg_wipe_xmms wipe_xmms
|
||||
%define dbg_wipe_ymms wipe_ymms
|
||||
%define dbg_wipe_avx512s wipe_avx512s
|
||||
%else
|
||||
%macro assert_cmp 3
|
||||
%cmp %2, %3
|
||||
%endmacro
|
||||
%macro assert_not_null 1
|
||||
%endmacro
|
||||
%macro slice_assert 1
|
||||
%endmacro
|
||||
%define dbg_wipe_gprs
|
||||
%define dbg_wipe_fpu_mmxs
|
||||
%define dbg_wipe_xmms
|
||||
%define dbg_wipe_ymms
|
||||
%define dbg_wipe_avx512s
|
||||
%endif ; BUILD_DEBUG
|
||||
;endregion Debug
|
||||
|
||||
;region Math
|
||||
|
||||
; returns: raccumulator = U64
|
||||
; Usage
|
||||
%macro min_S64 2
|
||||
mov raccumulator, %1
|
||||
cmp raccumulator, %2
|
||||
cmovg raccumulator, %2 ; ConditionalMoveIfGreater
|
||||
%endmacro min_S64
|
||||
|
||||
;endregion Math
|
||||
|
||||
;region Memory
|
||||
%define nullptr 0
|
||||
%define kilo 1024
|
||||
|
||||
; Usage: def_array <name: %1> <size: %2>
|
||||
%macro def_farray 2+
|
||||
struc %1
|
||||
.ptr: resb %2
|
||||
endstruc
|
||||
%endmacro
|
||||
|
||||
def_farray Mem_128k, 128 * kilo
|
||||
|
||||
;region memory_copy
|
||||
|
||||
; dst = rdst_id = [Byte]
|
||||
; src = rsrc_id = [Byte]
|
||||
; rcounter = U64
|
||||
section .text
|
||||
memory_copy:
|
||||
cld
|
||||
rep movsb ; REPEAT MoveStringByte
|
||||
; 1. Copies the byte from [RSI] to [RDI].
|
||||
; 2. Increments RSI and RDI (because of CLD).
|
||||
; 3. Decrements RCX.
|
||||
; 4. Repeats until RCX is 0.
|
||||
ret
|
||||
;endregion memory_copy
|
||||
|
||||
struc Slice
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
|
||||
; Usage: def_Slice %1: <slice_label>
|
||||
%macro def_Slice 1
|
||||
struc Slice_ %+ %1
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
%endmacro
|
||||
|
||||
def_Slice Byte
|
||||
|
||||
; Usage: stack_slice %1: <type>, %2 <slice id>, %3 <stack_offset>
|
||||
%macro stack_slice 2
|
||||
call_frame_alloc %1 %+ _size
|
||||
%endmacro
|
||||
|
||||
; Usage: slice_assert %1: Slice_<type> { .ptr = Slice.ptr, .len = Slice.len }
|
||||
%macro slice_assert 1
|
||||
%ifidn BUILD_DEBUG, 1
|
||||
cmp qword [%1 + Slice.ptr], nullptr
|
||||
jnz %%.ptr_passed
|
||||
int debug_trap
|
||||
%%.ptr_passed: ; macro-unique-prefix (%%) .passed is the label name
|
||||
cmp qword [%1 + Slice.len], 0
|
||||
jg %%.len_passed
|
||||
int debug_trap
|
||||
%%.len_passed:
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; Usage slice_assert %1: ptr, %2: len
|
||||
%macro slice_assert 2
|
||||
%ifidn BUILD_DEBUG, 1
|
||||
cmp %1, nullptr
|
||||
jnz %%.ptr_passed
|
||||
int debug_trap
|
||||
%%.ptr_passed:
|
||||
cmp %2, 0
|
||||
jg %%.len_passed
|
||||
int debug_trap
|
||||
%%.len_passed:
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; Usage: cf (call-frame begin)
|
||||
; Establishes a new stack frame, saving the caller's frame.
|
||||
; This is a standard function prologue.
|
||||
%macro cf 0
|
||||
push rstack_base_ptr ; Save the caller's frame pointer (RBP)
|
||||
mov rstack_base_ptr, rstack_ptr ; Set our new frame pointer to the current stack position
|
||||
%endmacro
|
||||
; Usage: cf_alloc <size_or_symbol> (call-frame allocate)
|
||||
%macro cf_alloc 1
|
||||
sub rstack_ptr, %1 ; Allocate space by subtracting from the stack pointer (RSP)
|
||||
%endmacro
|
||||
; Usage: cf_commit (call-frame commit)
|
||||
; Finalizes the stack frame by ensuring it is correctly aligned for a function call.
|
||||
%macro cf_commit 0
|
||||
; The Windows x64 ABI requires the stack pointer (RSP) to be 16-byte
|
||||
; aligned immediately before a CALL instruction. This command ensures alignment
|
||||
; by clearing the last 4 bits of RSP, rounding it down to the nearest multiple of 16.
|
||||
and rstack_ptr, ~15
|
||||
%endmacro
|
||||
; Usage: cf_end (call-frame end)
|
||||
; Tears down the stack frame, deallocating all memory and restoring the caller's frame.
|
||||
%macro cf_end 0
|
||||
mov rstack_ptr, rstack_base_ptr ; Deallocate the entire frame at once by resetting RSP to the saved RBP
|
||||
pop rstack_base_ptr ; Restore the caller's frame pointer
|
||||
%endmacro
|
||||
; Usage: cf_ctbl <ctbl struc>
|
||||
; Meant to only be used with call-table structs: <Symbol>_ctbl naming convention
|
||||
%macro cf_ctbl 1
|
||||
push rstack_base_ptr
|
||||
mov rstack_base_ptr, rstack_ptr
|
||||
sub rstack_ptr, %1 %+ _ctbl_size
|
||||
and rstack_ptr, ~15
|
||||
%endmacro
|
||||
|
||||
; Usage stac_alloc %1: <stack_offset>
|
||||
%macro stack_push 1
|
||||
push rstack_base_ptr
|
||||
mov rstack_base_ptr, rstack_ptr
|
||||
sub rstack_ptr, %1
|
||||
%endmacro
|
||||
%macro stack_pop 0
|
||||
mov rstack_ptr, rstack_base_ptr
|
||||
pop rstack_base_ptr
|
||||
%endmacro
|
||||
|
||||
;endregion Memory
|
||||
|
||||
;region Allocator Interface
|
||||
|
||||
; TODO(Ed): Make it!
|
||||
|
||||
;endregion Allocator Interface
|
||||
|
||||
;region OS
|
||||
|
||||
; TODO(Ed): Make it!
|
||||
|
||||
;endregion OS
|
||||
|
||||
;region FArena
|
||||
|
||||
; TODO(Ed): Make it!
|
||||
|
||||
;endregion FArena
|
||||
|
||||
;region VArena
|
||||
|
||||
; TODO(Ed): Make it!
|
||||
|
||||
;endregion VArena
|
||||
|
||||
;region Arena
|
||||
|
||||
; TODO(Ed): Make it!
|
||||
|
||||
;endregion Arena
|
||||
|
||||
;region Strings
|
||||
struc Str8
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
def_Slice Slice_Str8
|
||||
|
||||
; Usage: lit %1: <slice_label>, %2: <utf-8 literal>
|
||||
%macro lit 2
|
||||
%%str_data: db %2
|
||||
%%str_len: equ $ - %%str_data
|
||||
%1:
|
||||
istruc Str8
|
||||
at Str8.ptr, dq %%str_data
|
||||
at Str8.len, dq %%str_len
|
||||
iend
|
||||
%endmacro
|
||||
|
||||
section .data
|
||||
lit path_hello_files_asm, `./code/asm/hello_files.asm`
|
||||
;endregion Strings
|
||||
|
||||
;region String Ops
|
||||
|
||||
;region str8_to_cstr_capped
|
||||
%push proc_scope
|
||||
; result: rcounter = [UTF8]
|
||||
; content: Str8 = { .ptr = rdata, .len = r8 }
|
||||
; mem: r9 = [Slice_Byte]
|
||||
%define result rcounter
|
||||
%define content_ptr rdata
|
||||
%define content_len r8
|
||||
%define mem r9
|
||||
|
||||
section .text
|
||||
str8_to_cstr_capped:
|
||||
push raccumulator
|
||||
push rdst_id
|
||||
push rsrc_id
|
||||
sub rstack_ptr, 8
|
||||
; U64 raccumulator = min(content.len, mem.len - 1);
|
||||
mov rsrc_id, qword [mem + Slice_Byte.len]
|
||||
sub rsrc_id, 1
|
||||
min_S64 content_len, rsrc_id ; raccumulator has result
|
||||
; memory_copy(mem.ptr, content.ptr, copy_len);
|
||||
mov rdst_id, qword [mem + Slice_Byte.ptr]
|
||||
mov rsrc_id, content_ptr
|
||||
mov rcounter, raccumulator
|
||||
call memory_copy
|
||||
; mem.ptr[copy_len] = '\0';
|
||||
mov rdst_id, qword [mem + Slice_Byte.ptr]
|
||||
mov byte [rdst_id + raccumulator], 0
|
||||
; return cast(char*, mem.ptr);
|
||||
mov result, qword [mem + Str8.ptr]
|
||||
add rstack_ptr, 8
|
||||
pop rsrc_id
|
||||
pop rdst_id
|
||||
pop raccumulator
|
||||
ret
|
||||
%pop proc_scope
|
||||
;endregion str8_to_cstr_capped
|
||||
|
||||
;endregion String Ops
|
||||
|
||||
;region WinAPI
|
||||
|
||||
%define MS_INVALID_HANDLE_VALUE -1
|
||||
%define MS_FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||
%define MS_FILE_SHARE_READ 0x00000001
|
||||
%define MS_GENERIC_READ 0x80000000
|
||||
%define MS_OPEN_EXISTING 3
|
||||
%define MS_STD_OUTPUT_HANDLE -11
|
||||
|
||||
%define wapi_shadow_space 32
|
||||
|
||||
; kernel32.lib
|
||||
; Process API
|
||||
extern CloseHandle
|
||||
extern ExitProcess
|
||||
extern GetLastError
|
||||
; File API
|
||||
extern CreateFileA
|
||||
extern GetFileSizeEx
|
||||
extern ReadFile
|
||||
extern WriteFileA
|
||||
; Console IO
|
||||
extern GetStdHandle
|
||||
extern WriteConsoleA
|
||||
|
||||
struc wapi_ctbl
|
||||
.shadow: resq 4 ; 32 bytes for RCX, RDX, R8, R9
|
||||
endstruc
|
||||
|
||||
; rcx: hObject
|
||||
struc CloseHandle_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: uExitCode
|
||||
struc ExitProcess_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; no args
|
||||
struc GetLastError_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: lpFileName
|
||||
; rdx: dwDesiredAccess
|
||||
; r8: dwShareMode
|
||||
; r9: lpSecurityAttributes
|
||||
; s1: dwCreationDisposition
|
||||
; s2: dwFlagsAndAttributes
|
||||
; s3: hTemplateFile
|
||||
; NOTE: Even though the first two are DWORDs, on the stack they each
|
||||
; occupy a full 8-byte slot in the x64 ABI.
|
||||
struc CreateFileA_ctbl
|
||||
.shadow: resq 4
|
||||
.dwCreationDisposition: resq 1
|
||||
.dwFlagsAndAttributes: resq 1
|
||||
.hTemplateFile: resq 1
|
||||
endstruc
|
||||
|
||||
; rcx: hFile
|
||||
; rdx: lpFileSize
|
||||
struc GetFileSizeEx_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: hFile
|
||||
; rdx: lpBuffer
|
||||
; r8: nNumberOfBytesToRead
|
||||
; r9: lpNumberOfBytesRead
|
||||
; s1: lpOverlapped
|
||||
struc ReadFile_ctbl
|
||||
.shadow: resq 4
|
||||
.lpOverlapped: resq 1
|
||||
endstruc
|
||||
|
||||
; rcx: hFile
|
||||
; rdx: lpBuffer
|
||||
; r8: nNumberOfBytesToWrite
|
||||
; r9: lpNumberOfBytesWritten
|
||||
; s1: lpOverlapped
|
||||
struc WriteFileA_ctbl
|
||||
.shadow: resq 4
|
||||
.lpOverlapped: resq 1
|
||||
endstruc
|
||||
|
||||
struc FileOpInfo
|
||||
.content: resb Slice_Byte_size
|
||||
endstruc
|
||||
|
||||
; rcx: nStdHandle
|
||||
struc GetStdHandle_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: hConsoleOutput
|
||||
; rdx: lpBuffer
|
||||
; r8: nNumberOfCharsToWrite
|
||||
; r9: lpNumberOfCharsWritten
|
||||
; s1: lpReserved
|
||||
struc WriteConsoleA_ctbl
|
||||
.shadow: resq 4
|
||||
.lpReserved: resq 1
|
||||
.lpNumberOfCharsWritten: resq 1
|
||||
endstruc
|
||||
|
||||
section .data
|
||||
std_out_hndl dq 0
|
||||
;endregion WinAPI
|
||||
|
||||
;region file_read_contents
|
||||
%push proc_scope
|
||||
; Reg allocation:
|
||||
; result: rcounter = [FileOpInfo]
|
||||
; path: Slice_Str8 = { .ptr = rdata, .len = r8 }
|
||||
; backing: r9 = [Slice_Byte]
|
||||
%define result rcounter
|
||||
%define path_ptr rdata
|
||||
%define path_len r8
|
||||
%define backing r9
|
||||
|
||||
section .text
|
||||
file_read_contents:
|
||||
; validation
|
||||
assert_not_null result
|
||||
slice_assert backing
|
||||
slice_assert path_ptr, path_len
|
||||
|
||||
; save registers
|
||||
push rbase ; id_file
|
||||
push r12 ; result
|
||||
push r13 ; backing
|
||||
push r14 ; file_size
|
||||
mov r12, result
|
||||
mov r13, backing
|
||||
%define result r12
|
||||
%define backing r13
|
||||
|
||||
; rcounter = str8_to_cstr_capped(path, slice_fmem(scratch));
|
||||
; We're using backing to store the cstr temporarily until ReadFile.
|
||||
call str8_to_cstr_capped ; (rdata, r8, r9)
|
||||
; path_cstr = rcounter; path_len has will be discarded in the CreateFileA call
|
||||
%define path_cstr rcounter
|
||||
|
||||
cf_ctbl CreateFileA ; call-frame CreateFileA {
|
||||
; rcounter = path_cstr
|
||||
mov rdata_32, MS_GENERIC_READ ; dwDesiredAccess = MS_GENERIC_READ
|
||||
mov r8_32, MS_FILE_SHARE_READ ; dwShareMode = MS_FILE_SHARE_READ
|
||||
xor r9, r9 ; lpSecurityAttributes = nullptr
|
||||
mov qword [rstack_ptr + CreateFileA_ctbl.dwCreationDisposition], MS_OPEN_EXISTING ; stack.ptr[.dwCreationDisposition] = MS_OPEN_EXISTING
|
||||
mov qword [rstack_ptr + CreateFileA_ctbl.dwFlagsAndAttributes ], MS_FILE_ATTRIBUTE_NORMAL ; stack.ptr[.dwFlagsAndAttributes ] = MS_FILE_ATTRIBUTE_NORMAL
|
||||
mov qword [rstack_ptr + CreateFileA_ctbl.hTemplateFile ], nullptr ; stack.ptr[.hTemplateFile ] = nullptr
|
||||
call CreateFileA ; CreateFileA <- rcounter, rdata, r8, r9, stack
|
||||
cf_end ; }
|
||||
|
||||
; B32 open_failed = raccumulator == MS_INVALID_HANDLE_VALUE
|
||||
; if (open_failed) goto %%.error_exit
|
||||
assert_cmp jne, raccumulator, MS_INVALID_HANDLE_VALUE
|
||||
je .error_exit
|
||||
|
||||
mov rbase, raccumulator ; rbase = id_file
|
||||
%define id_file rbase
|
||||
|
||||
cf_ctbl GetFileSizeEx ; call-frame GetFileSizeEx {
|
||||
mov rcounter, id_file ; rcounter = id_file
|
||||
lea rdata, [result + FileOpInfo.content + Slice_Byte.len] ; lpFileSize = result.content.len
|
||||
call GetFileSizeEx ; GetFileSizeEx <- rcounter, rdata, stack
|
||||
cf_end ; }
|
||||
|
||||
; B32 not_enough_backing = result.content.len > backing.len
|
||||
; if (not_enough_backing) goto .error_close_handle
|
||||
mov r8, [backing + Slice_Byte.len] ; r8 = backing.len
|
||||
mov r9, [result + FileOpInfo.content + Slice_Byte.len] ; r9 = result.content.len
|
||||
assert_cmp jle, r9, r8 ; r9 <= r8
|
||||
jg .error_close_handle ; if (flagged greater) goto .error_close_handle
|
||||
|
||||
; MS_BOOL get_size_failed = ! raccumulator
|
||||
; if (get_size_failed) goto .error_exit
|
||||
assert_cmp jne, raccumulator, false ; raccumulator != false
|
||||
je .error_close_handle ; if (flagged equal) goto .error_close_handle
|
||||
|
||||
%define file_size r14d
|
||||
mov r14d, r9d
|
||||
|
||||
cf_ctbl ReadFile ; call-frame ReadFile {
|
||||
mov rcounter, id_file ; hfile: rcounter = rbase
|
||||
mov rdata, [backing + Slice_Byte.ptr ] ; lpBuffer: rdata = backing.ptr
|
||||
mov r8_32, file_size ; nNumberOfBytesToRead: r8_32 = file_size
|
||||
lea r9, [result + FileOpInfo.content + Slice_Byte.len] ; lpNumberOfBytesRead: r9 = & result.content.len
|
||||
mov qword [rstack_ptr + ReadFile_ctbl.lpOverlapped], 0 ; lpOverlapped: nullptr
|
||||
call ReadFile ; ReadFile <- rcounter, rata, r8, r9, stack
|
||||
cf_end ; }
|
||||
|
||||
; B32 read_failed = ! read_result
|
||||
; if (read_failed) goto .error_exit
|
||||
assert_cmp jnz, raccumulator, false
|
||||
je .error_exit
|
||||
; read_failed |= amount_read != result.content.len
|
||||
; if (read_failed) goto .error_exit
|
||||
mov r9, qword [result + FileOpInfo.content + Slice_Byte.len]
|
||||
assert_cmp je, file_size, r9d
|
||||
jne .error_close_handle
|
||||
|
||||
; CloseHandle(id_file)
|
||||
cf_ctbl CloseHandle ; call-frame CloseHandle {
|
||||
mov rcounter, id_file ; rcounter = id_file (rbase)
|
||||
call CloseHandle ; CloseHandle <- rcounter, stack
|
||||
cf_end ; }
|
||||
|
||||
; reslt.content.ptr = raccumulator
|
||||
mov raccumulator, [backing + Slice_Byte.ptr] ; raccumulator = backing.ptr
|
||||
mov [result + FileOpInfo.content + Slice_Byte.ptr], raccumulator ; result.content.ptr = raccumulator
|
||||
jmp .cleanup ; goto .cleanup
|
||||
|
||||
.error_close_handle:
|
||||
cf_ctbl CloseHandle ; call-frame CloseHandle {
|
||||
mov rcounter, rbase ; rcounter = id_file (rbase)
|
||||
call CloseHandle ; CloseHandle <- rcounter, stack
|
||||
cf_end ; }
|
||||
|
||||
.error_exit:
|
||||
; result = {}
|
||||
mov qword [result + FileOpInfo.content + Slice_Byte.ptr], 0
|
||||
mov qword [result + FileOpInfo.content + Slice_Byte.len], 0
|
||||
|
||||
.cleanup:
|
||||
pop r14 ; file_size
|
||||
pop backing
|
||||
pop result
|
||||
pop id_file
|
||||
; restore registers
|
||||
ret
|
||||
|
||||
section .bss
|
||||
; local_persist raw_scratch : [64 * kilo]byte
|
||||
file_read_contents.raw_scratch: resb 64 * kilo
|
||||
file_read_contents.path_cstr: resq 1
|
||||
section .data
|
||||
; local_persist scratch = fmem_slice(raw_scratch)
|
||||
file_read_contents.scratch:
|
||||
istruc Slice_Byte
|
||||
at Slice_Byte.ptr, dq file_read_contents.raw_scratch
|
||||
at Slice_Byte.len, dq 64 * kilo
|
||||
iend
|
||||
%pop proc_scope
|
||||
;endregion file_read_contents
|
||||
|
||||
section .text
|
||||
global main
|
||||
%push proc_scope
|
||||
main:
|
||||
xor rcx, rcx
|
||||
|
||||
cf_ctbl GetStdHandle ; call-frame GetStdHandle {
|
||||
mov rcounter_32, MS_STD_OUTPUT_HANDLE ; rcounter.32 = MS_STD_OUTPUT_HANDLE
|
||||
call GetStdHandle ; GetStdHandle <- rcounter, stack
|
||||
cf_end ; }
|
||||
|
||||
mov [std_out_hndl], raccumulator ; std_out_hndl = raccumulator
|
||||
|
||||
; TODO(Ed): Setup an arena allocator for backing!
|
||||
; TODO(ED): Setup allocator info for an arena
|
||||
|
||||
%push calling
|
||||
cf ; call-frame file_read_contents {
|
||||
; Need to pass the allocator info
|
||||
; %define backing rsp + Slice_Byte_size
|
||||
cf_commit
|
||||
mov qword [backing + Slice_Byte.ptr], read_mem ; local_backing.ptr = read_mem.ptr
|
||||
mov qword [backing + Slice_Byte.len], Mem_128k_size ; local_backing.len = Mem_128k_size
|
||||
lea rcounter, file ; rcounter = file.ptr
|
||||
mov rdata, [path_hello_files_asm + Str8.ptr] ; rdata = path_hello_files.ptr
|
||||
mov r8, [path_hello_files_asm + Str8.len] ; r8 = path_hello_files.len
|
||||
lea r9, [backing] ; r9 = & local_backing
|
||||
call file_read_contents ; read_file_contents <- rcounter, rdata, r8, r9, stack
|
||||
cf_end ; }
|
||||
%pop calling
|
||||
|
||||
cf_ctbl ExitProcess ; call-frame ExitProcess {
|
||||
xor ecx, ecx ; ecx = 0
|
||||
call ExitProcess ; ExitProcess <- rcx, stack
|
||||
cf_end ; }
|
||||
ret
|
||||
%pop proc_scope
|
||||
|
||||
section .bss
|
||||
read_mem: resb Mem_128k_size ; internal global read_mem: Mem_128k
|
||||
file: resb FileOpInfo_size ; internal global file: FileOpInfo
|
688
code/asm/hello_files.asm
Normal file
688
code/asm/hello_files.asm
Normal file
@@ -0,0 +1,688 @@
|
||||
; Hello Files!
|
||||
|
||||
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 rdata_32 edx
|
||||
%define r8_32 r8d
|
||||
%define r9_32 r9d
|
||||
|
||||
%define raccumulator rax
|
||||
%define rbase rbx
|
||||
%define rcounter rcx
|
||||
%define rdata rdx
|
||||
%define rdst_id rdi
|
||||
%define rsrc_id rsi
|
||||
%define rstack_ptr rsp
|
||||
%define rstack_base_ptr rbp
|
||||
|
||||
%define false 0
|
||||
%define true 1
|
||||
%define true_overflow 2
|
||||
;endregion DSL
|
||||
|
||||
;region Registers
|
||||
|
||||
; 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
|
||||
|
||||
; Resets the Floating-Point Unit (FPU), which also clears all MMX registers
|
||||
; (MM0-MM7) and FPU stack registers (ST0-ST7).
|
||||
%macro wipe_fpu_mmxs 0
|
||||
finit
|
||||
%endmacro
|
||||
|
||||
; Wipes the 128-bit XMM registers. Requires a CPU with at least SSE.
|
||||
%macro wipe_xmms 0
|
||||
vxorps xmm0, xmm0, xmm0
|
||||
vxorps xmm1, xmm1, xmm1
|
||||
vxorps xmm2, xmm2, xmm2
|
||||
vxorps xmm3, xmm3, xmm3
|
||||
vxorps xmm4, xmm4, xmm4
|
||||
vxorps xmm5, xmm5, xmm5
|
||||
vxorps xmm6, xmm6, xmm6
|
||||
vxorps xmm7, xmm7, xmm7
|
||||
vxorps xmm8, xmm8, xmm8
|
||||
vxorps xmm9, xmm9, xmm9
|
||||
vxorps xmm10, xmm10, xmm10
|
||||
vxorps xmm11, xmm11, xmm11
|
||||
vxorps xmm12, xmm12, xmm12
|
||||
vxorps xmm13, xmm13, xmm13
|
||||
vxorps xmm14, xmm14, xmm14
|
||||
vxorps xmm15, xmm15, xmm15
|
||||
%endmacro
|
||||
|
||||
; =============================================================================
|
||||
; AVX Registers (YMM0-YMM15)
|
||||
; =============================================================================
|
||||
; Wipes the 256-bit YMM registers. Requires a CPU with AVX support.
|
||||
; This also wipes the lower 128 bits (the XMM registers), so you don't
|
||||
; need to call WIPE_XMM_REGS if you call this one.
|
||||
%macro wipe_ymms 0
|
||||
vzeroupper ; Clears upper 128 bits of all YMM registers
|
||||
vxorps ymm0, ymm0, ymm0 ; Clears the full YMM0 (including lower XMM0)
|
||||
vxorps ymm1, ymm1, ymm1
|
||||
vxorps ymm2, ymm2, ymm2
|
||||
vxorps ymm3, ymm3, ymm3
|
||||
vxorps ymm4, ymm4, ymm4
|
||||
vxorps ymm5, ymm5, ymm5
|
||||
vxorps ymm6, ymm6, ymm6
|
||||
vxorps ymm7, ymm7, ymm7
|
||||
vxorps ymm8, ymm8, ymm8
|
||||
vxorps ymm9, ymm9, ymm9
|
||||
vxorps ymm10, ymm10, ymm10
|
||||
vxorps ymm11, ymm11, ymm11
|
||||
vxorps ymm12, ymm12, ymm12
|
||||
vxorps ymm13, ymm13, ymm13
|
||||
vxorps ymm14, ymm14, ymm14
|
||||
vxorps ymm15, ymm15, ymm15
|
||||
%endmacro
|
||||
|
||||
; =============================================================================
|
||||
; AVX-512 Registers (ZMM0-ZMM31 and K0-K7)
|
||||
; =============================================================================
|
||||
; Wipes the 512-bit ZMM registers and the 8 mask registers (k0-k7).
|
||||
; Requires a CPU with AVX-512F support. This is the most comprehensive
|
||||
; vector register wipe and makes WIPE_XMM_REGS and WIPE_YMM_REGS redundant.
|
||||
%macro wipe_avx512s 0
|
||||
; Wipe Mask Registers (k0-k7)
|
||||
kxorb k0, k0, k0
|
||||
kxorb k1, k1, k1
|
||||
kxorb k2, k2, k2
|
||||
kxorb k3, k3, k3
|
||||
kxorb k4, k4, k4
|
||||
kxorb k5, k5, k5
|
||||
kxorb k6, k6, k6
|
||||
kxorb k7, k7, k7
|
||||
|
||||
; Wipe ZMM registers (zmm0-zmm31)
|
||||
vpxord zmm0, zmm0, zmm0
|
||||
vpxord zmm1, zmm1, zmm1
|
||||
vpxord zmm2, zmm2, zmm2
|
||||
vpxord zmm3, zmm3, zmm3
|
||||
vpxord zmm4, zmm4, zmm4
|
||||
vpxord zmm5, zmm5, zmm5
|
||||
vpxord zmm6, zmm6, zmm6
|
||||
vpxord zmm7, zmm7, zmm7
|
||||
vpxord zmm8, zmm8, zmm8
|
||||
vpxord zmm9, zmm9, zmm9
|
||||
vpxord zmm10, zmm10, zmm10
|
||||
vpxord zmm11, zmm11, zmm11
|
||||
vpxord zmm12, zmm12, zmm12
|
||||
vpxord zmm13, zmm13, zmm13
|
||||
vpxord zmm14, zmm14, zmm14
|
||||
vpxord zmm15, zmm15, zmm15
|
||||
vpxord zmm16, zmm16, zmm16
|
||||
vpxord zmm17, zmm17, zmm17
|
||||
vpxord zmm18, zmm18, zmm18
|
||||
vpxord zmm19, zmm19, zmm19
|
||||
vpxord zmm20, zmm20, zmm20
|
||||
vpxord zmm21, zmm21, zmm21
|
||||
vpxord zmm22, zmm22, zmm22
|
||||
vpxord zmm23, zmm23, zmm23
|
||||
vpxord zmm24, zmm24, zmm24
|
||||
vpxord zmm25, zmm25, zmm25
|
||||
vpxord zmm26, zmm26, zmm26
|
||||
vpxord zmm27, zmm27, zmm27
|
||||
vpxord zmm28, zmm28, zmm28
|
||||
vpxord zmm29, zmm29, zmm29
|
||||
vpxord zmm30, zmm30, zmm30
|
||||
vpxord zmm31, zmm31, zmm31
|
||||
%endmacro
|
||||
;endregion Registers
|
||||
|
||||
;region Debug
|
||||
%define debug_trap 3
|
||||
|
||||
%ifidn BUILD_DEBUG, 1
|
||||
%macro assert_cmp 3
|
||||
cmp %2, %3
|
||||
%1 %%.passed
|
||||
int debug_trap
|
||||
%%.passed:
|
||||
%endmacro
|
||||
%macro assert_not_null 1
|
||||
cmp %1, nullptr
|
||||
jnz %%.passed
|
||||
int debug_trap
|
||||
%%.passed: ; macro-unique-prefix (%%) .passed is the label name
|
||||
%endmacro
|
||||
%define dbg_wipe_gprs wipe_gprs
|
||||
%define dbg_wipe_fpu_mmxs wipe_fpu_mmxs
|
||||
%define dbg_wipe_xmms wipe_xmms
|
||||
%define dbg_wipe_ymms wipe_ymms
|
||||
%define dbg_wipe_avx512s wipe_avx512s
|
||||
%else
|
||||
%macro assert_cmp 3
|
||||
%cmp %2, %3
|
||||
%endmacro
|
||||
%macro assert_not_null 1
|
||||
%endmacro
|
||||
%macro slice_assert 1
|
||||
%endmacro
|
||||
%define dbg_wipe_gprs
|
||||
%define dbg_wipe_fpu_mmxs
|
||||
%define dbg_wipe_xmms
|
||||
%define dbg_wipe_ymms
|
||||
%define dbg_wipe_avx512s
|
||||
%endif ; BUILD_DEBUG
|
||||
;endregion Debug
|
||||
|
||||
;region Memory
|
||||
%define nullptr 0
|
||||
%define kilo 1024
|
||||
|
||||
; Usage: def_array <name: %1> <size: %2>
|
||||
%macro def_farray 2+
|
||||
struc %1
|
||||
.ptr: resb %2
|
||||
endstruc
|
||||
%endmacro
|
||||
|
||||
def_farray Mem_128k, 128 * kilo
|
||||
|
||||
;region memory_copy
|
||||
|
||||
; dst = rdst_id = [Byte]
|
||||
; src = rsrc_id = [Byte]
|
||||
; rcounter = U64
|
||||
section .text
|
||||
memory_copy:
|
||||
cld
|
||||
rep movsb ; REPEAT MoveStringByte
|
||||
; 1. Copies the byte from [RSI] to [RDI].
|
||||
; 2. Increments RSI and RDI (because of CLD).
|
||||
; 3. Decrements RCX.
|
||||
; 4. Repeats until RCX is 0.
|
||||
ret
|
||||
;endregion memory_copy
|
||||
|
||||
struc Slice
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
|
||||
; Usage: def_Slice %1: <slice_label>
|
||||
%macro def_Slice 1
|
||||
struc Slice_ %+ %1
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
%endmacro
|
||||
|
||||
def_Slice Byte
|
||||
|
||||
; Usage: stack_slice %1: <type>, %2 <slice id>, %3 <stack_offset>
|
||||
%macro stack_slice 2
|
||||
call_frame_alloc %1 %+ _size
|
||||
%endmacro
|
||||
|
||||
; Usage: slice_assert %1: Slice_<type> { .ptr = Slice.ptr, .len = Slice.len }
|
||||
%macro slice_assert 1
|
||||
%ifidn BUILD_DEBUG, 1
|
||||
cmp qword [%1 + Slice.ptr], nullptr
|
||||
jnz %%.ptr_passed
|
||||
int debug_trap
|
||||
%%.ptr_passed: ; macro-unique-prefix (%%) .passed is the label name
|
||||
cmp qword [%1 + Slice.len], 0
|
||||
jg %%.len_passed
|
||||
int debug_trap
|
||||
%%.len_passed:
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; Usage slice_assert %1: ptr, %2: len
|
||||
%macro slice_assert 2
|
||||
%ifidn BUILD_DEBUG, 1
|
||||
cmp %1, nullptr
|
||||
jnz %%.ptr_passed
|
||||
int debug_trap
|
||||
%%.ptr_passed:
|
||||
cmp %2, 0
|
||||
jg %%.len_passed
|
||||
int debug_trap
|
||||
%%.len_passed:
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; Usage: cf (call-frame begin)
|
||||
; Establishes a new stack frame, saving the caller's frame.
|
||||
; This is a standard function prologue.
|
||||
%macro cf 0
|
||||
push rstack_base_ptr ; Save the caller's frame pointer (RBP)
|
||||
mov rstack_base_ptr, rstack_ptr ; Set our new frame pointer to the current stack position
|
||||
%endmacro
|
||||
; Usage: cf_alloc <size_or_symbol> (call-frame allocate)
|
||||
%macro cf_alloc 1
|
||||
sub rstack_ptr, %1 ; Allocate space by subtracting from the stack pointer (RSP)
|
||||
%endmacro
|
||||
; Usage: cf_commit (call-frame commit)
|
||||
; Finalizes the stack frame by ensuring it is correctly aligned for a function call.
|
||||
%macro cf_commit 0
|
||||
; The Windows x64 ABI requires the stack pointer (RSP) to be 16-byte
|
||||
; aligned immediately before a CALL instruction. This command ensures alignment
|
||||
; by clearing the last 4 bits of RSP, rounding it down to the nearest multiple of 16.
|
||||
and rstack_ptr, ~15
|
||||
%endmacro
|
||||
; Usage: cf_end (call-frame end)
|
||||
; Tears down the stack frame, deallocating all memory and restoring the caller's frame.
|
||||
%macro cf_end 0
|
||||
mov rstack_ptr, rstack_base_ptr ; Deallocate the entire frame at once by resetting RSP to the saved RBP
|
||||
pop rstack_base_ptr ; Restore the caller's frame pointer
|
||||
%endmacro
|
||||
; Usage: cf_ctbl <ctbl struc>
|
||||
; Meant to only be used with call-table structs: <Symbol>_ctbl naming convention
|
||||
%macro cf_ctbl 1
|
||||
push rstack_base_ptr
|
||||
mov rstack_base_ptr, rstack_ptr
|
||||
sub rstack_ptr, %1 %+ _ctbl_size
|
||||
and rstack_ptr, ~15
|
||||
%endmacro
|
||||
|
||||
; Usage stac_alloc %1: <stack_offset>
|
||||
%macro stack_push 1
|
||||
push rstack_base_ptr
|
||||
mov rstack_base_ptr, rstack_ptr
|
||||
sub rstack_ptr, %1
|
||||
%endmacro
|
||||
%macro stack_pop 0
|
||||
mov rstack_ptr, rstack_base_ptr
|
||||
pop rstack_base_ptr
|
||||
%endmacro
|
||||
|
||||
;endregion Memory
|
||||
|
||||
;region Math
|
||||
|
||||
; returns: raccumulator = U64
|
||||
; Usage
|
||||
%macro min_S64 2
|
||||
mov raccumulator, %1
|
||||
cmp raccumulator, %2
|
||||
cmovg raccumulator, %2 ; ConditionalMoveIfGreater
|
||||
%endmacro min_S64
|
||||
|
||||
;endregion Math
|
||||
|
||||
;region Strings
|
||||
struc Str8
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
def_Slice Slice_Str8
|
||||
|
||||
; Usage: lit %1: <slice_label>, %2: <utf-8 literal>
|
||||
%macro lit 2
|
||||
%%str_data: db %2
|
||||
%%str_len: equ $ - %%str_data
|
||||
%1:
|
||||
istruc Str8
|
||||
at Str8.ptr, dq %%str_data
|
||||
at Str8.len, dq %%str_len
|
||||
iend
|
||||
%endmacro
|
||||
|
||||
section .data
|
||||
lit path_hello_files_asm, `./code/asm/hello_files.asm`
|
||||
;endregion Strings
|
||||
|
||||
;region String Ops
|
||||
|
||||
;region str8_to_cstr_capped
|
||||
%push proc_scope
|
||||
; result: rcounter = [UTF8]
|
||||
; content: Str8 = { .ptr = rdata, .len = r8 }
|
||||
; mem: r9 = [Slice_Byte]
|
||||
%define result rcounter
|
||||
%define content_ptr rdata
|
||||
%define content_len r8
|
||||
%define mem r9
|
||||
|
||||
section .text
|
||||
str8_to_cstr_capped:
|
||||
push raccumulator
|
||||
push rdst_id
|
||||
push rsrc_id
|
||||
sub rstack_ptr, 8
|
||||
; U64 raccumulator = min(content.len, mem.len - 1);
|
||||
mov rsrc_id, qword [mem + Slice_Byte.len]
|
||||
sub rsrc_id, 1
|
||||
min_S64 content_len, rsrc_id ; raccumulator has result
|
||||
; memory_copy(mem.ptr, content.ptr, copy_len);
|
||||
mov rdst_id, qword [mem + Slice_Byte.ptr]
|
||||
mov rsrc_id, content_ptr
|
||||
mov rcounter, raccumulator
|
||||
call memory_copy
|
||||
; mem.ptr[copy_len] = '\0';
|
||||
mov rdst_id, qword [mem + Slice_Byte.ptr]
|
||||
mov byte [rdst_id + raccumulator], 0
|
||||
; return cast(char*, mem.ptr);
|
||||
mov result, qword [mem + Str8.ptr]
|
||||
add rstack_ptr, 8
|
||||
pop rsrc_id
|
||||
pop rdst_id
|
||||
pop raccumulator
|
||||
ret
|
||||
%pop proc_scope
|
||||
;endregion str8_to_cstr_capped
|
||||
|
||||
;endregion String Ops
|
||||
|
||||
;region WinAPI
|
||||
|
||||
%define MS_INVALID_HANDLE_VALUE -1
|
||||
%define MS_FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||
%define MS_FILE_SHARE_READ 0x00000001
|
||||
%define MS_GENERIC_READ 0x80000000
|
||||
%define MS_OPEN_EXISTING 3
|
||||
%define MS_STD_OUTPUT_HANDLE -11
|
||||
|
||||
%define wapi_shadow_space 32
|
||||
|
||||
; kernel32.lib
|
||||
; Process API
|
||||
extern CloseHandle
|
||||
extern ExitProcess
|
||||
extern GetLastError
|
||||
; File API
|
||||
extern CreateFileA
|
||||
extern GetFileSizeEx
|
||||
extern ReadFile
|
||||
extern WriteFileA
|
||||
; Console IO
|
||||
extern GetStdHandle
|
||||
extern WriteConsoleA
|
||||
|
||||
struc wapi_ctbl
|
||||
.shadow: resq 4 ; 32 bytes for RCX, RDX, R8, R9
|
||||
endstruc
|
||||
|
||||
; rcx: hObject
|
||||
struc CloseHandle_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: uExitCode
|
||||
struc ExitProcess_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; no args
|
||||
struc GetLastError_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: lpFileName
|
||||
; rdx: dwDesiredAccess
|
||||
; r8: dwShareMode
|
||||
; r9: lpSecurityAttributes
|
||||
; s1: dwCreationDisposition
|
||||
; s2: dwFlagsAndAttributes
|
||||
; s3: hTemplateFile
|
||||
; NOTE: Even though the first two are DWORDs, on the stack they each
|
||||
; occupy a full 8-byte slot in the x64 ABI.
|
||||
struc CreateFileA_ctbl
|
||||
.shadow: resq 4
|
||||
.dwCreationDisposition: resq 1
|
||||
.dwFlagsAndAttributes: resq 1
|
||||
.hTemplateFile: resq 1
|
||||
endstruc
|
||||
|
||||
; rcx: hFile
|
||||
; rdx: lpFileSize
|
||||
struc GetFileSizeEx_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: hFile
|
||||
; rdx: lpBuffer
|
||||
; r8: nNumberOfBytesToRead
|
||||
; r9: lpNumberOfBytesRead
|
||||
; s1: lpOverlapped
|
||||
struc ReadFile_ctbl
|
||||
.shadow: resq 4
|
||||
.lpOverlapped: resq 1
|
||||
endstruc
|
||||
|
||||
; rcx: hFile
|
||||
; rdx: lpBuffer
|
||||
; r8: nNumberOfBytesToWrite
|
||||
; r9: lpNumberOfBytesWritten
|
||||
; s1: lpOverlapped
|
||||
struc WriteFileA_ctbl
|
||||
.shadow: resq 4
|
||||
.lpOverlapped: resq 1
|
||||
endstruc
|
||||
|
||||
struc FileOpInfo
|
||||
.content: resb Slice_Byte_size
|
||||
endstruc
|
||||
|
||||
; rcx: nStdHandle
|
||||
struc GetStdHandle_ctbl
|
||||
.shadow: resq 4
|
||||
endstruc
|
||||
|
||||
; rcx: hConsoleOutput
|
||||
; rdx: lpBuffer
|
||||
; r8: nNumberOfCharsToWrite
|
||||
; r9: lpNumberOfCharsWritten
|
||||
; s1: lpReserved
|
||||
struc WriteConsoleA_ctbl
|
||||
.shadow: resq 4
|
||||
.lpReserved: resq 1
|
||||
.lpNumberOfCharsWritten: resq 1
|
||||
endstruc
|
||||
|
||||
section .data
|
||||
std_out_hndl dq 0
|
||||
;endregion WinAPI
|
||||
|
||||
;region file_read_contents
|
||||
%push proc_scope
|
||||
; Reg allocation:
|
||||
; result: rcounter = [FileOpInfo]
|
||||
; path: Slice_Str8 = { .ptr = rdata, .len = r8 }
|
||||
; backing: r9 = [Slice_Byte]
|
||||
%define result rcounter
|
||||
%define path_ptr rdata
|
||||
%define path_len r8
|
||||
%define backing r9
|
||||
|
||||
section .text
|
||||
file_read_contents:
|
||||
; validation
|
||||
assert_not_null result
|
||||
slice_assert backing
|
||||
slice_assert path_ptr, path_len
|
||||
|
||||
; save registers
|
||||
push rbase ; id_file
|
||||
push r12 ; result
|
||||
push r13 ; backing
|
||||
push r14 ; file_size
|
||||
mov r12, result
|
||||
mov r13, backing
|
||||
%define result r12
|
||||
%define backing r13
|
||||
|
||||
; rcounter = str8_to_cstr_capped(path, slice_fmem(scratch));
|
||||
; We're using backing to store the cstr temporarily until ReadFile.
|
||||
call str8_to_cstr_capped ; (rdata, r8, r9)
|
||||
; path_cstr = rcounter; path_len has will be discarded in the CreateFileA call
|
||||
%define path_cstr rcounter
|
||||
|
||||
cf_ctbl CreateFileA ; call-frame CreateFileA {
|
||||
; rcounter = path_cstr
|
||||
mov rdata_32, MS_GENERIC_READ ; dwDesiredAccess = MS_GENERIC_READ
|
||||
mov r8_32, MS_FILE_SHARE_READ ; dwShareMode = MS_FILE_SHARE_READ
|
||||
xor r9, r9 ; lpSecurityAttributes = nullptr
|
||||
mov qword [rstack_ptr + CreateFileA_ctbl.dwCreationDisposition], MS_OPEN_EXISTING ; stack.ptr[.dwCreationDisposition] = MS_OPEN_EXISTING
|
||||
mov qword [rstack_ptr + CreateFileA_ctbl.dwFlagsAndAttributes ], MS_FILE_ATTRIBUTE_NORMAL ; stack.ptr[.dwFlagsAndAttributes ] = MS_FILE_ATTRIBUTE_NORMAL
|
||||
mov qword [rstack_ptr + CreateFileA_ctbl.hTemplateFile ], nullptr ; stack.ptr[.hTemplateFile ] = nullptr
|
||||
call CreateFileA ; CreateFileA <- rcounter, rdata, r8, r9, stack
|
||||
cf_end ; }
|
||||
|
||||
; B32 open_failed = raccumulator == MS_INVALID_HANDLE_VALUE
|
||||
; if (open_failed) goto %%.error_exit
|
||||
assert_cmp jne, raccumulator, MS_INVALID_HANDLE_VALUE
|
||||
je .error_exit
|
||||
|
||||
mov rbase, raccumulator ; rbase = id_file
|
||||
%define id_file rbase
|
||||
|
||||
cf_ctbl GetFileSizeEx ; call-frame GetFileSizeEx {
|
||||
mov rcounter, id_file ; rcounter = id_file
|
||||
lea rdata, [result + FileOpInfo.content + Slice_Byte.len] ; lpFileSize = result.content.len
|
||||
call GetFileSizeEx ; GetFileSizeEx <- rcounter, rdata, stack
|
||||
cf_end ; }
|
||||
|
||||
; B32 not_enough_backing = result.content.len > backing.len
|
||||
; if (not_enough_backing) goto .error_close_handle
|
||||
mov r8, [backing + Slice_Byte.len] ; r8 = backing.len
|
||||
mov r9, [result + FileOpInfo.content + Slice_Byte.len] ; r9 = result.content.len
|
||||
assert_cmp jle, r9, r8 ; r9 <= r8
|
||||
jg .error_close_handle ; if (flagged greater) goto .error_close_handle
|
||||
|
||||
; MS_BOOL get_size_failed = ! raccumulator
|
||||
; if (get_size_failed) goto .error_exit
|
||||
assert_cmp jne, raccumulator, false ; raccumulator != false
|
||||
je .error_close_handle ; if (flagged equal) goto .error_close_handle
|
||||
|
||||
%define file_size r14d
|
||||
mov r14d, r9d
|
||||
|
||||
cf_ctbl ReadFile ; call-frame ReadFile {
|
||||
mov rcounter, id_file ; hfile: rcounter = rbase
|
||||
mov rdata, [backing + Slice_Byte.ptr ] ; lpBuffer: rdata = backing.ptr
|
||||
mov r8_32, file_size ; nNumberOfBytesToRead: r8_32 = file_size
|
||||
lea r9, [result + FileOpInfo.content + Slice_Byte.len] ; lpNumberOfBytesRead: r9 = & result.content.len
|
||||
mov qword [rstack_ptr + ReadFile_ctbl.lpOverlapped], 0 ; lpOverlapped: nullptr
|
||||
call ReadFile ; ReadFile <- rcounter, rata, r8, r9, stack
|
||||
cf_end ; }
|
||||
|
||||
; B32 read_failed = ! read_result
|
||||
; if (read_failed) goto .error_exit
|
||||
assert_cmp jnz, raccumulator, false
|
||||
je .error_exit
|
||||
; read_failed |= amount_read != result.content.len
|
||||
; if (read_failed) goto .error_exit
|
||||
mov r9, qword [result + FileOpInfo.content + Slice_Byte.len]
|
||||
assert_cmp je, file_size, r9d
|
||||
jne .error_close_handle
|
||||
|
||||
; CloseHandle(id_file)
|
||||
cf_ctbl CloseHandle ; call-frame CloseHandle {
|
||||
mov rcounter, id_file ; rcounter = id_file (rbase)
|
||||
call CloseHandle ; CloseHandle <- rcounter, stack
|
||||
cf_end ; }
|
||||
|
||||
; reslt.content.ptr = raccumulator
|
||||
mov raccumulator, [backing + Slice_Byte.ptr] ; raccumulator = backing.ptr
|
||||
mov [result + FileOpInfo.content + Slice_Byte.ptr], raccumulator ; result.content.ptr = raccumulator
|
||||
jmp .cleanup ; goto .cleanup
|
||||
|
||||
.error_close_handle:
|
||||
cf_ctbl CloseHandle ; call-frame CloseHandle {
|
||||
mov rcounter, rbase ; rcounter = id_file (rbase)
|
||||
call CloseHandle ; CloseHandle <- rcounter, stack
|
||||
cf_end ; }
|
||||
|
||||
.error_exit:
|
||||
; result = {}
|
||||
mov qword [result + FileOpInfo.content + Slice_Byte.ptr], 0
|
||||
mov qword [result + FileOpInfo.content + Slice_Byte.len], 0
|
||||
|
||||
.cleanup:
|
||||
pop r14 ; file_size
|
||||
pop backing
|
||||
pop result
|
||||
pop id_file
|
||||
; restore registers
|
||||
ret
|
||||
|
||||
section .bss
|
||||
; local_persist raw_scratch : [64 * kilo]byte
|
||||
file_read_contents.raw_scratch: resb 64 * kilo
|
||||
file_read_contents.path_cstr: resq 1
|
||||
section .data
|
||||
; local_persist scratch = fmem_slice(raw_scratch)
|
||||
file_read_contents.scratch:
|
||||
istruc Slice_Byte
|
||||
at Slice_Byte.ptr, dq file_read_contents.raw_scratch
|
||||
at Slice_Byte.len, dq 64 * kilo
|
||||
iend
|
||||
%pop proc_scope
|
||||
;endregion file_read_contents
|
||||
|
||||
section .text
|
||||
global main
|
||||
%push proc_scope
|
||||
main:
|
||||
xor rcx, rcx
|
||||
|
||||
cf_ctbl GetStdHandle ; call-frame GetStdHandle {
|
||||
mov rcounter_32, MS_STD_OUTPUT_HANDLE ; rcounter.32 = MS_STD_OUTPUT_HANDLE
|
||||
call GetStdHandle ; GetStdHandle <- rcounter, stack
|
||||
cf_end ; }
|
||||
|
||||
mov [std_out_hndl], raccumulator ; std_out_hndl = raccumulator
|
||||
|
||||
%push calling
|
||||
cf ; call-frame file_read_contents {
|
||||
cf_alloc Slice_Byte_size ; stack local_backing : Slice_byte
|
||||
cf_commit
|
||||
%define local_backing rsp + Slice_Byte_size
|
||||
mov qword [local_backing + Slice_Byte.ptr], read_mem ; local_backing.ptr = read_mem.ptr
|
||||
mov qword [local_backing + Slice_Byte.len], Mem_128k_size ; local_backing.len = Mem_128k_size
|
||||
lea rcounter, file ; rcounter = file.ptr
|
||||
mov rdata, [path_hello_files_asm + Str8.ptr] ; rdata = path_hello_files.ptr
|
||||
mov r8, [path_hello_files_asm + Str8.len] ; r8 = path_hello_files.len
|
||||
lea r9, [local_backing] ; r9 = & local_backing
|
||||
call file_read_contents ; read_file_contents <- rcounter, rdata, r8, r9, stack
|
||||
cf_end ; }
|
||||
%pop calling
|
||||
|
||||
cf_ctbl WriteConsoleA ; call-frame WriteConsoleA {
|
||||
mov rcounter, [std_out_hndl] ; rcounter = std_out_hndl
|
||||
mov rdata, [file + FileOpInfo.content + Slice_Byte.ptr] ; rdata = file.content.ptr
|
||||
mov r8_32, [file + FileOpInfo.content + Slice_Byte.len] ; r8 = file.content.len
|
||||
lea r9, [rstack_ptr + WriteConsoleA_ctbl.lpNumberOfCharsWritten] ; r9 = & stack.ptr[WriteFileA.ctbl.lpNumberOfCharsWritten]
|
||||
mov qword [rstack_ptr + WriteConsoleA_ctbl.lpReserved], nullptr ; stack.ptr[.ctbl.lpRserved] = nullptr
|
||||
call WriteConsoleA ; WriteConsoleA <- rcounter, rdata, r9, stack
|
||||
cf_end
|
||||
|
||||
cf_ctbl ExitProcess ; call-frame ExitProcess {
|
||||
xor ecx, ecx ; ecx = 0
|
||||
call ExitProcess ; ExitProcess <- rcx, stack
|
||||
cf_end ; }
|
||||
ret
|
||||
%pop proc_scope
|
||||
|
||||
section .bss
|
||||
read_mem: resb Mem_128k_size ; internal global read_mem: Mem_128k
|
||||
file: resb FileOpInfo_size ; internal global file: FileOpInfo
|
43
code/asm/hello_nasm.asm
Normal file
43
code/asm/hello_nasm.asm
Normal file
@@ -0,0 +1,43 @@
|
||||
; hello.asm - Hello World with debug symbols for YASM
|
||||
BITS 64 ; Explicitly specify 64-bit mode
|
||||
DEFAULT REL ; Use RIP-relative addressing by default
|
||||
|
||||
extern ExitProcess ; Import Windows API functions
|
||||
extern GetStdHandle
|
||||
extern WriteConsoleA
|
||||
|
||||
; Data section
|
||||
section .data
|
||||
message db "Hello, NASM!", 13, 10, 0 ; String with CRLF and null terminator
|
||||
message_len equ $ - message ; Calculate string length
|
||||
|
||||
; Code section
|
||||
section .text
|
||||
global main ; Export main symbol for linker
|
||||
|
||||
main:
|
||||
; Function prologue
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 32 ; Shadow space for Windows API calls
|
||||
|
||||
; Get stdout handle
|
||||
mov ecx, -11 ; STD_OUTPUT_HANDLE
|
||||
call GetStdHandle
|
||||
mov rbx, rax ; Save handle for WriteConsole
|
||||
|
||||
; Write message
|
||||
mov rcx, rbx ; Console handle
|
||||
lea rdx, [message] ; Message buffer
|
||||
mov r8d, message_len ; Message length
|
||||
lea r9, [rsp+28] ; Written chars (unused)
|
||||
mov qword [rsp+20], 0 ; Reserved (must be 0)
|
||||
call WriteConsoleA
|
||||
|
||||
; Exit program
|
||||
xor ecx, ecx ; Exit code 0
|
||||
call ExitProcess
|
||||
|
||||
; Function epilogue (not reached due to ExitProcess)
|
||||
leave
|
||||
ret
|
81
code/asm/hello_slices.asm
Normal file
81
code/asm/hello_slices.asm
Normal file
@@ -0,0 +1,81 @@
|
||||
; Hello Slices!
|
||||
|
||||
%define marg
|
||||
|
||||
%define rcounter_32 ecx
|
||||
|
||||
%define reg8_32 r8d
|
||||
|
||||
%define raccumulator rax
|
||||
%define rcounter rcx
|
||||
%define rdata rdx
|
||||
%define rstack_ptr rsp
|
||||
%define rstack_base_ptr rbp
|
||||
|
||||
%define reg9 r9
|
||||
|
||||
%define MS_STD_OUTPUT_HANDLE 11
|
||||
|
||||
struc Slice_Byte
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
|
||||
struc Slice_Str8
|
||||
.ptr: resq 1
|
||||
.len: resq 1
|
||||
endstruc
|
||||
|
||||
; Usage: lit %1: <slice_label> %2: <utf-8 literal>
|
||||
%macro lit 2
|
||||
lit_ %+ %1: db %2
|
||||
lit_ %+ %1 %+ _len: equ $ - (lit_ %+ %1)
|
||||
%endmacro
|
||||
|
||||
BITS 64 ; Explicitly specify 64-bit mode
|
||||
DEFAULT REL ; Use RIP-relative addressing by default
|
||||
|
||||
; kernel32.lib
|
||||
extern GetStdHandle
|
||||
extern WriteConsoleA
|
||||
|
||||
section .data
|
||||
std_out_hndl dq 0
|
||||
|
||||
section .lits progbits noexec nowrite
|
||||
lit hello_msg, `Hello Slices\n`
|
||||
|
||||
section .text
|
||||
global main
|
||||
|
||||
%define wapi_shadow_width 48
|
||||
%macro wapi_shadow_space 0
|
||||
push rstack_base_ptr
|
||||
mov rstack_base_ptr, rstack_ptr
|
||||
sub rstack_ptr, wapi_shadow_width
|
||||
%endmacro
|
||||
%define wapi_arg4_offset 28
|
||||
%define wapi_arg5_offset 32
|
||||
|
||||
%define wapi_write_console_written_chars reg9
|
||||
%macro wapi_write_console 2
|
||||
mov rcounter,[%1] ; Console Handle
|
||||
lea rdata, [%2] ; Slice_Str8.Ptr
|
||||
mov reg8_32, %2 %+ _len ; Slice_Str8.Len
|
||||
lea reg9, [rstack_ptr + wapi_arg4_offset] ; Written chars
|
||||
mov qword [rstack_ptr + wapi_arg5_offset], 0 ; Reserved (must be 0)
|
||||
call WriteConsoleA
|
||||
%endmacro
|
||||
|
||||
main:
|
||||
wapi_shadow_space
|
||||
|
||||
; Setup stdout handle
|
||||
mov rcounter_32, -MS_STD_OUTPUT_HANDLE
|
||||
call GetStdHandle
|
||||
mov [std_out_hndl], raccumulator
|
||||
|
||||
wapi_write_console std_out_hndl, lit_hello_msg
|
||||
|
||||
leave
|
||||
ret
|
1
code/asm/readme.md
Normal file
1
code/asm/readme.md
Normal file
@@ -0,0 +1 @@
|
||||
# Handwritten assembly
|
23
code/host.odin
Normal file
23
code/host.odin
Normal file
@@ -0,0 +1,23 @@
|
||||
package asmduff
|
||||
|
||||
|
||||
|
||||
section_data :: proc()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
section_text :: proc()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
section_externs :: proc()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
main :: proc()
|
||||
{
|
||||
|
||||
}
|
3
code/pkg_mappings.odin
Normal file
3
code/pkg_mappings.odin
Normal file
@@ -0,0 +1,3 @@
|
||||
package asmduff
|
||||
|
||||
// import
|
120
scripts/build.odin
Normal file
120
scripts/build.odin
Normal file
@@ -0,0 +1,120 @@
|
||||
package build
|
||||
|
||||
//region Script Grime
|
||||
import mem "core:mem"
|
||||
import vmem "core:mem/virtual"
|
||||
import os "core:os/os2"
|
||||
import "core:fmt"
|
||||
import _strings "core:strings"
|
||||
StrGen :: _strings.Builder
|
||||
strgen_init :: _strings.builder_init
|
||||
strgen_join :: _strings.join
|
||||
|
||||
join_path :: #force_inline proc(elems : ..string) -> string { res, _ := os.join_path(transmute([]string)elems, context.allocator); return transmute(string)res }
|
||||
get_working_dir :: #force_inline proc() -> string { res, _ := os.get_working_directory(context.allocator); return transmute(string)res }
|
||||
|
||||
join_str :: #force_inline proc(elems : ..string) -> string {
|
||||
gen : StrGen; strgen_init(& gen, context.allocator)
|
||||
res, _ := strgen_join(elems, "")
|
||||
return res
|
||||
}
|
||||
|
||||
// For a beakdown of any flag, type <odin_compiler> <command> -help
|
||||
command_build :: "build"
|
||||
command_check :: "check"
|
||||
command_query :: "query"
|
||||
command_report :: "report"
|
||||
command_run :: "run"
|
||||
|
||||
flag_build_mode :: "-build-mode:"
|
||||
flag_build_mode_dll :: "-build-mode:dll"
|
||||
flag_collection :: "-collection:"
|
||||
flag_file :: "-file"
|
||||
flag_debug :: "-debug"
|
||||
flag_define :: "-define:"
|
||||
flag_default_allocator_nil :: "-default-to-nil-allocator"
|
||||
flag_disable_assert :: "-disable-assert"
|
||||
flag_dynamic_map_calls :: "-dynamic-map-calls"
|
||||
flag_extra_assembler_flags :: "-extra_assembler-flags:"
|
||||
flag_extra_linker_flags :: "-extra-linker-flags:"
|
||||
flag_ignore_unknown_attributes :: "-ignore-unknown-attributes"
|
||||
flag_keep_temp_files :: "-keep-temp-files"
|
||||
flag_max_error_count :: "-max-error-count:"
|
||||
flag_micro_architecture_native :: "-microarch:native"
|
||||
flag_no_bounds_check :: "-no-bounds-check"
|
||||
flag_no_crt :: "-no-crt"
|
||||
flag_no_entrypoint :: "-no-entry-point"
|
||||
flag_no_thread_local :: "-no-thread-local"
|
||||
flag_no_thread_checker :: "-no-threaded-checker"
|
||||
flag_output_path :: "-out="
|
||||
flag_optimization_level :: "-opt:"
|
||||
flag_optimize_none :: "-o:none"
|
||||
flag_optimize_minimal :: "-o:minimal"
|
||||
flag_optimize_size :: "-o:size"
|
||||
flag_optimize_speed :: "-o:speed"
|
||||
falg_optimize_aggressive :: "-o:aggressive"
|
||||
flag_pdb_name :: "-pdb-name:"
|
||||
flag_sanitize_address :: "-sanitize:address"
|
||||
flag_sanitize_memory :: "-sanitize:memory"
|
||||
flag_sanitize_thread :: "-sanitize:thread"
|
||||
flag_subsystem :: "-subsystem:"
|
||||
flag_show_debug_messages :: "-show-debug-messages"
|
||||
flag_show_timings :: "-show-timings"
|
||||
flag_show_more_timings :: "-show-more-timings"
|
||||
flag_show_system_calls :: "-show-system-calls"
|
||||
flag_target :: "-target:"
|
||||
flag_thread_count :: "-thread-count:"
|
||||
flag_use_lld :: "-linker:lld"
|
||||
flag_use_rad_link :: "-linker:radlink"
|
||||
flag_use_separate_modules :: "-use-separate-modules"
|
||||
flag_vet_all :: "-vet"
|
||||
flag_vet_unused_entities :: "-vet-unused"
|
||||
flag_vet_semicolon :: "-vet-semicolon"
|
||||
flag_vet_shadow_vars :: "-vet-shadowing"
|
||||
flag_vet_using_stmt :: "-vet-using-stmt"
|
||||
|
||||
flag_microarch_zen5 :: "--microarch:znver5"
|
||||
|
||||
flag_msvc_link_disable_dynamic_base :: "/DYNAMICBASE:NO"
|
||||
flag_msvc_link_base_address :: "/BASE:"
|
||||
flag_msvc_link_fixed_base_address :: "/FIXED"
|
||||
flag_msvc_link_stack_size :: "/STACK"
|
||||
flag_msvc_link_debug :: "/DEBUG"
|
||||
|
||||
msvc_link_default_base_address :: 0x180000000
|
||||
//endregion Script Grime
|
||||
|
||||
build :: proc(working_dir : string, args : []string) -> (stdout : string, stderr : string) {
|
||||
fmt.println("Building:", args)
|
||||
res, errs : []byte; _, res, errs, _ = os.process_exec({ working_dir = working_dir, command = args}, context.allocator)
|
||||
return transmute(string)res, transmute(string)errs;
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
varena : vmem.Arena; _ = vmem.arena_init_growing(& varena, mem.Megabyte * 64 ); context.allocator = vmem.arena_allocator(& varena)
|
||||
exe_odin :: "odin.exe"
|
||||
|
||||
path_root := get_working_dir()
|
||||
path_build := join_path(path_root, "build")
|
||||
path_code := join_path(path_root, "code")
|
||||
file_source := join_path(path_code, "host.odin")
|
||||
file_exe := join_path(path_build, "host.exe")
|
||||
|
||||
res, errs := build(path_build, {
|
||||
exe_odin,
|
||||
command_build,
|
||||
file_source,
|
||||
flag_file,
|
||||
join_str(flag_output_path, file_exe),
|
||||
flag_optimize_none,
|
||||
flag_default_allocator_nil,
|
||||
flag_debug,
|
||||
flag_microarch_zen5,
|
||||
flag_no_thread_checker,
|
||||
flag_show_timings,
|
||||
flag_use_rad_link,
|
||||
join_str(flag_subsystem, "console"),
|
||||
})
|
||||
fmt.println(res)
|
||||
fmt.println(errs)
|
||||
}
|
41
scripts/build_duff.ps1
Normal file
41
scripts/build_duff.ps1
Normal file
@@ -0,0 +1,41 @@
|
||||
$path_root = split-path -Path $PSScriptRoot -Parent
|
||||
$path_build = join-path $path_root 'build'
|
||||
$path_code = join-path $path_root 'code'
|
||||
|
||||
$path_source = join-path $PSScriptRoot 'build.odin'
|
||||
$exe = join-path $path_build 'build_win32.exe'
|
||||
|
||||
if ((test-path $path_build) -eq $false) {
|
||||
new-item -itemtype directory -path $path_build
|
||||
}
|
||||
|
||||
$odin = 'odin.exe'
|
||||
|
||||
$command_build = 'build'
|
||||
|
||||
$flag_debug = '-debug'
|
||||
$flag_file = '-file'
|
||||
$flag_dyn_map_calls = '-dynamic-map-calls'
|
||||
$flag_no_bounds_check = '-no-bounds-check'
|
||||
$flag_no_threaded_checker = '-no-threaded-checker'
|
||||
$flag_no_type_assert = '-no-type-assert'
|
||||
$flag_optimize_none = '-o:none'
|
||||
$flag_output_path = '-out='
|
||||
$flag_default_allocator_nil = '-default-to-nil-allocator'
|
||||
|
||||
push-location $path_root
|
||||
$build_args = @()
|
||||
$build_args += $command_build
|
||||
$build_args += $path_source
|
||||
$build_args += $flag_file
|
||||
# $build_args += $flag_debug
|
||||
$build_args += $flag_optimize_none
|
||||
$build_args += $flag_no_bounds_check
|
||||
$build_args += $flag_no_threaded_checker
|
||||
$build_args += $flag_no_type_assert
|
||||
$build_args += $flag_dyn_map_calls
|
||||
$build_args += $flag_default_allocator_nil
|
||||
$build_args += $flag_output_path + $exe
|
||||
# & $odin $build_args
|
||||
& $exe
|
||||
pop-location
|
120
scripts/build_hello_arenas.ps1
Normal file
120
scripts/build_hello_arenas.ps1
Normal file
@@ -0,0 +1,120 @@
|
||||
$ps1_devshell = join-path $PSScriptRoot 'helpers/devshell.ps1'
|
||||
. $ps1_devshell -arch amd64
|
||||
$path_root = split-path -Path $PSScriptRoot -Parent
|
||||
$path_build = join-path $path_root 'build'
|
||||
$path_code = join-path $path_root 'code'
|
||||
$path_asm = join-path $path_code 'asm'
|
||||
$path_toolchain = join-path $path_root 'toolchain'
|
||||
$path_rad = join-path $path_toolchain 'rad'
|
||||
|
||||
if ((test-path $path_build) -eq $false) {
|
||||
new-item -itemtype directory -path $path_build
|
||||
}
|
||||
|
||||
$unit_name = 'hello_arenas'
|
||||
|
||||
$src = join-path $path_asm "$unit_name.asm"
|
||||
$unit = join-path $path_build "$unit_name.unit.asm"
|
||||
$listing = join-path $path_build "$unit_name.asm.list"
|
||||
$link_obj = join-path $path_build "$unit_name.o"
|
||||
$map = join-path $path_build "$unit_name.map"
|
||||
$pdb = join-path $path_build "$unit_name.pdb"
|
||||
$rdi = join-path $path_build "$unit_name.rdi"
|
||||
$rdi_listing = join-path $path_build "$unit_name.rdi.list"
|
||||
$exe = join-path $path_build "$unit_name.exe"
|
||||
|
||||
$nasm = 'nasm'
|
||||
$link = 'link.exe'
|
||||
$radbin = join-path $path_rad 'radbin.exe'
|
||||
$radlink = join-path $path_rad 'radlink.exe'
|
||||
|
||||
push-location $path_root
|
||||
$f_assemble_only = '-a'
|
||||
$f_bin_fmt_coff = '-f coff'
|
||||
$f_bin_fmt_win64 = '-f win64'
|
||||
$f_debug = '-g'
|
||||
$f_debug_fmt_win64 = '-g cv8'
|
||||
$f_dmacro = '-Dmacro='
|
||||
$f_Ipath = '-Ipath '
|
||||
$f_listing = '-l'
|
||||
$f_listing_plus = '-L+'
|
||||
$f_preprocess_only = '-E'
|
||||
$f_optimize_none = '-O0'
|
||||
$f_optimize_min = '-O1'
|
||||
$f_optimize_multi = '-Ox'
|
||||
$f_optimize_multi_disp = '-Ov'
|
||||
$f_outfile = '-o '
|
||||
$f_warnings_as_errors = '-Werror'
|
||||
|
||||
# $nargs = @(
|
||||
# $src,
|
||||
# $f_preprocess_only,
|
||||
# $f_optimize_none,
|
||||
# ($f_outfile + $unit)
|
||||
# )
|
||||
# write-host 'Preprocessing'
|
||||
# $nargs | ForEach-Object { Write-Host $_ }
|
||||
# & $nasm $nargs
|
||||
|
||||
$nargs = @(
|
||||
$src,
|
||||
$f_optimize_none,
|
||||
$f_bin_fmt_win64,
|
||||
$f_debug_fmt_win64,
|
||||
$f_listing_plus,
|
||||
($f_listing + $listing),
|
||||
($f_outfile + $link_obj)
|
||||
)
|
||||
write-host 'Assembling'
|
||||
$nargs | ForEach-Object { Write-Host "`t$_" }
|
||||
& $nasm $nargs
|
||||
|
||||
$lib_kernel32 = 'kernel32.lib'
|
||||
$lib_msvcrt = 'msvcrt.lib'
|
||||
|
||||
$link_nologo = '/NOLOGO'
|
||||
$link_debug = '/DEBUG:'
|
||||
$link_entrypoint = '/ENTRY:'
|
||||
$link_mapfile = '/MAP:'
|
||||
$link_no_incremental = '/INCREMENTAL:NO'
|
||||
$link_large_address_aware = '/LARGEADDRESSAWARE:NO'
|
||||
$link_listing = '/LIST'
|
||||
$link_outfile = '/OUT:'
|
||||
$link_win_machine_64 = '/MACHINE:X64'
|
||||
$link_win_pdb = '/PDB:'
|
||||
$link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
|
||||
$link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
|
||||
$rad_debug = '/RAD_DEBUG'
|
||||
$rad_debug_name = '/RAD_DEBUG_NAME:'
|
||||
$rad_large_pages = '/RAD_LARGE_PAGES:'
|
||||
$nargs = @(
|
||||
# $rad_debug,
|
||||
$link_nologo,
|
||||
($link_debug + 'FULL'),
|
||||
($link_mapfile + $map),
|
||||
($link_win_pdb + $pdb),
|
||||
# $link_listing,
|
||||
$link_no_incremental,
|
||||
$link_large_address_aware,
|
||||
$link_win_machine_64,
|
||||
$link_win_subsystem_console,
|
||||
$lib_kernel32,
|
||||
# $lib_msvcrt,
|
||||
($link_entrypoint + 'main'),
|
||||
($link_outfile + $exe),
|
||||
$link_obj
|
||||
)
|
||||
write-host 'Linking'
|
||||
$nargs | ForEach-Object { Write-Host "`t$_" }
|
||||
& $link $nargs
|
||||
pop-location
|
||||
|
||||
$rbin_out = '--out:'
|
||||
$rbin_dump = '--dump'
|
||||
|
||||
write-host 'Dumping RDI'
|
||||
$nargs = @($pdb, ($rbin_out + $rdi))
|
||||
& $radbin $nargs
|
||||
$nargs = @($rbin_dump, $rdi)
|
||||
$dump = & $radbin $nargs
|
||||
$dump > $rdi_listing
|
120
scripts/build_hello_files.ps1
Normal file
120
scripts/build_hello_files.ps1
Normal file
@@ -0,0 +1,120 @@
|
||||
$ps1_devshell = join-path $PSScriptRoot 'helpers/devshell.ps1'
|
||||
. $ps1_devshell -arch amd64
|
||||
$path_root = split-path -Path $PSScriptRoot -Parent
|
||||
$path_build = join-path $path_root 'build'
|
||||
$path_code = join-path $path_root 'code'
|
||||
$path_asm = join-path $path_code 'asm'
|
||||
$path_toolchain = join-path $path_root 'toolchain'
|
||||
$path_rad = join-path $path_toolchain 'rad'
|
||||
|
||||
if ((test-path $path_build) -eq $false) {
|
||||
new-item -itemtype directory -path $path_build
|
||||
}
|
||||
|
||||
$unit_name = 'hello_files'
|
||||
|
||||
$src = join-path $path_asm "$unit_name.asm"
|
||||
$unit = join-path $path_build "$unit_name.unit.asm"
|
||||
$listing = join-path $path_build "$unit_name.asm.list"
|
||||
$link_obj = join-path $path_build "$unit_name.o"
|
||||
$map = join-path $path_build "$unit_name.map"
|
||||
$pdb = join-path $path_build "$unit_name.pdb"
|
||||
$rdi = join-path $path_build "$unit_name.rdi"
|
||||
$rdi_listing = join-path $path_build "$unit_name.rdi.list"
|
||||
$exe = join-path $path_build "$unit_name.exe"
|
||||
|
||||
$nasm = 'nasm'
|
||||
$link = 'link.exe'
|
||||
$radbin = join-path $path_rad 'radbin.exe'
|
||||
$radlink = join-path $path_rad 'radlink.exe'
|
||||
|
||||
push-location $path_root
|
||||
$f_assemble_only = '-a'
|
||||
$f_bin_fmt_coff = '-f coff'
|
||||
$f_bin_fmt_win64 = '-f win64'
|
||||
$f_debug = '-g'
|
||||
$f_debug_fmt_win64 = '-g cv8'
|
||||
$f_dmacro = '-Dmacro='
|
||||
$f_Ipath = '-Ipath '
|
||||
$f_listing = '-l'
|
||||
$f_listing_plus = '-L+'
|
||||
$f_preprocess_only = '-E'
|
||||
$f_optimize_none = '-O0'
|
||||
$f_optimize_min = '-O1'
|
||||
$f_optimize_multi = '-Ox'
|
||||
$f_optimize_multi_disp = '-Ov'
|
||||
$f_outfile = '-o '
|
||||
$f_warnings_as_errors = '-Werror'
|
||||
|
||||
# $nargs = @(
|
||||
# $src,
|
||||
# $f_preprocess_only,
|
||||
# $f_optimize_none,
|
||||
# ($f_outfile + $unit)
|
||||
# )
|
||||
# write-host 'Preprocessing'
|
||||
# $nargs | ForEach-Object { Write-Host $_ }
|
||||
# & $nasm $nargs
|
||||
|
||||
$nargs = @(
|
||||
$src,
|
||||
$f_optimize_none,
|
||||
$f_bin_fmt_win64,
|
||||
$f_debug_fmt_win64,
|
||||
$f_listing_plus,
|
||||
($f_listing + $listing),
|
||||
($f_outfile + $link_obj)
|
||||
)
|
||||
write-host 'Assembling'
|
||||
$nargs | ForEach-Object { Write-Host "`t$_" }
|
||||
& $nasm $nargs
|
||||
|
||||
$lib_kernel32 = 'kernel32.lib'
|
||||
$lib_msvcrt = 'msvcrt.lib'
|
||||
|
||||
$link_nologo = '/NOLOGO'
|
||||
$link_debug = '/DEBUG:'
|
||||
$link_entrypoint = '/ENTRY:'
|
||||
$link_mapfile = '/MAP:'
|
||||
$link_no_incremental = '/INCREMENTAL:NO'
|
||||
$link_large_address_aware = '/LARGEADDRESSAWARE:NO'
|
||||
$link_listing = '/LIST'
|
||||
$link_outfile = '/OUT:'
|
||||
$link_win_machine_64 = '/MACHINE:X64'
|
||||
$link_win_pdb = '/PDB:'
|
||||
$link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
|
||||
$link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
|
||||
$rad_debug = '/RAD_DEBUG'
|
||||
$rad_debug_name = '/RAD_DEBUG_NAME:'
|
||||
$rad_large_pages = '/RAD_LARGE_PAGES:'
|
||||
$nargs = @(
|
||||
# $rad_debug,
|
||||
$link_nologo,
|
||||
($link_debug + 'FULL'),
|
||||
($link_mapfile + $map),
|
||||
($link_win_pdb + $pdb),
|
||||
# $link_listing,
|
||||
$link_no_incremental,
|
||||
$link_large_address_aware,
|
||||
$link_win_machine_64,
|
||||
$link_win_subsystem_console,
|
||||
$lib_kernel32,
|
||||
# $lib_msvcrt,
|
||||
($link_entrypoint + 'main'),
|
||||
($link_outfile + $exe),
|
||||
$link_obj
|
||||
)
|
||||
write-host 'Linking'
|
||||
$nargs | ForEach-Object { Write-Host "`t$_" }
|
||||
& $link $nargs
|
||||
pop-location
|
||||
|
||||
$rbin_out = '--out:'
|
||||
$rbin_dump = '--dump'
|
||||
|
||||
write-host 'Dumping RDI'
|
||||
$nargs = @($pdb, ($rbin_out + $rdi))
|
||||
& $radbin $nargs
|
||||
$nargs = @($rbin_dump, $rdi)
|
||||
$dump = & $radbin $nargs
|
||||
$dump > $rdi_listing
|
103
scripts/build_hello_nasm.ps1
Normal file
103
scripts/build_hello_nasm.ps1
Normal file
@@ -0,0 +1,103 @@
|
||||
$ps1_devshell = join-path $PSScriptRoot 'helpers/devshell.ps1'
|
||||
. $ps1_devshell -arch amd64
|
||||
$path_root = split-path -Path $PSScriptRoot -Parent
|
||||
$path_build = join-path $path_root 'build'
|
||||
$path_code = join-path $path_root 'code'
|
||||
$path_asm = join-path $path_code 'asm'
|
||||
$path_toolchain = join-path $path_root 'toolchain'
|
||||
$path_rad = join-path $path_toolchain 'rad'
|
||||
|
||||
if ((test-path $path_build) -eq $false) {
|
||||
new-item -itemtype directory -path $path_build
|
||||
}
|
||||
|
||||
$unit_name = 'hello_nasm'
|
||||
|
||||
$unit = join-path $path_asm "$unit_name.asm"
|
||||
$listing = join-path $path_build "$unit_name.list"
|
||||
$link_obj = join-path $path_build "$unit_name.o"
|
||||
$map = join-path $path_build "$unit_name.map"
|
||||
$pdb = join-path $path_build "$unit_name.pdb"
|
||||
$rdi = join-path $path_build "$unit_name.rdi"
|
||||
$exe = join-path $path_build "$unit_name.exe"
|
||||
|
||||
$nasm = 'nasm'
|
||||
$link = 'link.exe'
|
||||
$radbin = join-path $path_rad 'radbin.exe'
|
||||
$radlink = join-path $path_rad 'radlink.exe'
|
||||
|
||||
push-location $path_root
|
||||
$f_assemble_only = '-a'
|
||||
$f_bin_fmt_coff = '-f coff'
|
||||
$f_bin_fmt_win64 = '-f win64'
|
||||
$f_debug = '-g'
|
||||
$f_debug_fmt_win64 = '-g cv8'
|
||||
$f_dmacro = '-Dmacro='
|
||||
$f_Ipath = '-Ipath '
|
||||
$f_listing = '-l'
|
||||
$f_listing_plus = '-L+'
|
||||
$f_preprocess_only = '-E'
|
||||
$f_optimize_none = '-O0'
|
||||
$f_optimize_min = '-O1'
|
||||
$f_optimize_multi = '-Ox'
|
||||
$f_optimize_multi_disp = '-Ov'
|
||||
$f_outfile = '-o '
|
||||
$f_warnings_as_errors = '-Werror'
|
||||
|
||||
write-host 'Preprocessing'
|
||||
$args = @(
|
||||
$unit,
|
||||
$f_preprocess_only,
|
||||
$f_optimize_none,
|
||||
($f_listing + $listing),
|
||||
$f_listing_plus
|
||||
)
|
||||
& $nasm $args
|
||||
|
||||
write-host 'Assembling'
|
||||
$args = @(
|
||||
$unit,
|
||||
$f_preprocess_only,
|
||||
$f_optimize_none,
|
||||
$f_bin_fmt_win64,
|
||||
$f_debug_fmt_win64,
|
||||
($f_outfile + $link_obj)
|
||||
)
|
||||
& $nasm $args
|
||||
|
||||
$lib_kernel32 = 'kernel32.lib'
|
||||
$lib_msvcrt = 'msvcrt.lib'
|
||||
|
||||
$link_nologo = '/NOLOGO'
|
||||
$link_debug = '/DEBUG:'
|
||||
$link_entrypoint = '/ENTRY:'
|
||||
$link_mapfile = '/MAP:'
|
||||
$link_library = '/'
|
||||
$link_outfile = '/OUT:'
|
||||
$link_win_machine_64 = '/MACHINE:X64'
|
||||
$link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
|
||||
$link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
|
||||
$rad_debug = '/RAD_DEBUG'
|
||||
$rad_debug_name = '/RAD_DEBUG_NAME:'
|
||||
$rad_large_pages = '/RAD_LARGE_PAGES:'
|
||||
$args = @(
|
||||
# $rad_debug,
|
||||
$link_nologo,
|
||||
($link_debug + 'FULL'),
|
||||
($link_mapfile + $map)
|
||||
$link_win_machine_64,
|
||||
$link_win_subsystem_console,
|
||||
$lib_kernel32,
|
||||
# $lib_msvcrt,
|
||||
($link_entrypoint + 'main'),
|
||||
($link_outfile + $exe),
|
||||
$link_obj
|
||||
)
|
||||
write-host 'Linking'
|
||||
& $link $args
|
||||
pop-location
|
||||
|
||||
$rbin_out = '--out:'
|
||||
$rbin_dump = '--dump '
|
||||
|
||||
# $radbin
|
76
scripts/build_hello_slices.ps1
Normal file
76
scripts/build_hello_slices.ps1
Normal file
@@ -0,0 +1,76 @@
|
||||
$ps1_devshell = join-path $PSScriptRoot 'helpers/devshell.ps1'
|
||||
. $ps1_devshell -arch amd64
|
||||
$path_root = split-path -Path $PSScriptRoot -Parent
|
||||
$path_build = join-path $path_root 'build'
|
||||
$path_code = join-path $path_root 'code'
|
||||
$path_asm = join-path $path_code 'asm'
|
||||
$path_toolchain = join-path $path_root 'toolchain'
|
||||
$path_radlink = join-path $path_toolchain 'radlink'
|
||||
|
||||
if ((test-path $path_build) -eq $false) {
|
||||
new-item -itemtype directory -path $path_build
|
||||
}
|
||||
|
||||
$hello_nasm = join-path $path_asm 'hello_slices.asm'
|
||||
$listing = join-path $path_build 'hello_slices.list'
|
||||
$link_obj = join-path $path_build 'hello_slices.o'
|
||||
$exe = join-path $path_build 'hello_slices.exe'
|
||||
|
||||
$nasm = 'nasm'
|
||||
$radlink = join-path $path_radlink 'radlink.exe'
|
||||
|
||||
push-location $path_root
|
||||
$f_assemble_only = '-a'
|
||||
$f_bin_fmt_coff = '-f coff'
|
||||
$f_bin_fmt_win64 = '-f win64'
|
||||
$f_debug = '-g'
|
||||
$f_debug_fmt_win64 = '-g cv8'
|
||||
$f_dmacro = '-Dmacro='
|
||||
$f_Ipath = '-Ipath '
|
||||
$f_listing = '-l'
|
||||
$f_preprocess_only = '-E'
|
||||
$f_optimize_none = '-O0'
|
||||
$f_optimize_min = '-O1'
|
||||
$f_optimize_multi = '-Ox'
|
||||
$f_optimize_multi_disp = '-Ov'
|
||||
$f_outfile = '-o '
|
||||
$f_warnings_as_errors = '-Werror'
|
||||
$args = @(
|
||||
$hello_nasm,
|
||||
$f_optimize_none,
|
||||
# $f_preprocess_only,
|
||||
$f_bin_fmt_win64,
|
||||
$f_debug_fmt_win64,
|
||||
($f_listing + $listing),
|
||||
($f_outfile + $link_obj)
|
||||
)
|
||||
& $nasm $args
|
||||
|
||||
$lib_kernel32 = 'kernel32.lib'
|
||||
$lib_msvcrt = 'msvcrt.lib'
|
||||
|
||||
$link = 'link.exe'
|
||||
|
||||
$link_debug = '/DEBUG:'
|
||||
$link_entrypoint = '/ENTRY:'
|
||||
$link_library = '/'
|
||||
$link_outfile = '/OUT:'
|
||||
$link_win_machine_64 = '/MACHINE:X64'
|
||||
$link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
|
||||
$link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
|
||||
$rad_debug = '/RAD_DEBUG'
|
||||
$rad_debug_name = '/RAD_DEBUG_NAME:'
|
||||
$rad_large_pages = '/RAD_LARGE_PAGES:'
|
||||
$args = @(
|
||||
$rad_debug,
|
||||
# ($link_debug + 'FULL'),
|
||||
$link_win_machine_64,
|
||||
$link_win_subsystem_console,
|
||||
$lib_kernel32,
|
||||
# $lib_msvcrt,
|
||||
($link_entrypoint + 'main'),
|
||||
($link_outfile + $exe),
|
||||
$link_obj
|
||||
)
|
||||
& $radlink $args
|
||||
pop-location
|
28
scripts/helpers/devshell.ps1
Normal file
28
scripts/helpers/devshell.ps1
Normal file
@@ -0,0 +1,28 @@
|
||||
if ($env:VCINSTALLDIR) {
|
||||
return
|
||||
}
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Use vswhere to find the latest Visual Studio installation
|
||||
$vswhere_out = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath
|
||||
if ($null -eq $vswhere_out) {
|
||||
Write-Host "ERROR: Visual Studio installation not found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find Launch-VsDevShell.ps1 in the Visual Studio installation
|
||||
$vs_path = $vswhere_out
|
||||
$vs_devshell = Join-Path $vs_path "\Common7\Tools\Launch-VsDevShell.ps1"
|
||||
|
||||
if ( -not (Test-Path $vs_devshell) ) {
|
||||
Write-Host "ERROR: Launch-VsDevShell.ps1 not found in Visual Studio installation"
|
||||
Write-Host Tested path: $vs_devshell
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Launch the Visual Studio Developer Shell
|
||||
Push-Location
|
||||
write-host @args
|
||||
& $vs_devshell @args
|
||||
Pop-Location
|
82
scripts/helpers/incremental_checks.ps1
Normal file
82
scripts/helpers/incremental_checks.ps1
Normal file
@@ -0,0 +1,82 @@
|
||||
# This is meant to be used with build.ps1, and is not a standalone script.
|
||||
|
||||
function check-FileForChanges
|
||||
{
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$path_file
|
||||
)
|
||||
|
||||
if (-not (Test-Path $path_file -PathType Leaf)) {
|
||||
Write-Error "The provided path is not a valid file: $path_file"
|
||||
return $false
|
||||
}
|
||||
$file_name = Split-Path $path_file -Leaf
|
||||
$path_csv = Join-Path $path_build ($file_name + "_file_hash.csv")
|
||||
|
||||
$csv_file_hash = $null
|
||||
if (Test-Path $path_csv) {
|
||||
$csv_file_hash = Import-Csv $path_csv | Select-Object -ExpandProperty value
|
||||
}
|
||||
|
||||
$current_hash_info = Get-FileHash -Path $path_file -Algorithm MD5
|
||||
$current_file_hash = $current_hash_info.Hash
|
||||
|
||||
# Save the current hash to the CSV
|
||||
[PSCustomObject]@{
|
||||
name = $path_file
|
||||
value = $current_file_hash
|
||||
} | Export-Csv $path_csv -NoTypeInformation
|
||||
|
||||
if ($csv_file_hash -and $csv_file_hash -eq $current_file_hash) {
|
||||
return $false
|
||||
} else {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
# Check to see if the module has changed files since the last build
|
||||
function check-ModuleForChanges
|
||||
{
|
||||
param( [string]$path_module, [array]$excludes )
|
||||
|
||||
$module_name = split-path $path_module -leaf
|
||||
$path_csv = Join-Path $path_build ("module_" + $module_name + "_hashes.csv")
|
||||
|
||||
$csv_file_hashes = $null
|
||||
if ( test-path $path_csv ) {
|
||||
$csv_file_hashes = @{}
|
||||
import-csv $path_csv | foreach-object {
|
||||
$csv_file_hashes[ $_.name ] = $_.value
|
||||
}
|
||||
}
|
||||
|
||||
$file_hashes = @{}
|
||||
get-childitem -path $path_module -file -Exclude $excludes -Recurse | foreach-object {
|
||||
$id = $_.fullname
|
||||
$hash_info = get-filehash -path $id -Algorithm MD5
|
||||
$file_hashes[ $id ] = $hash_info.Hash
|
||||
}
|
||||
|
||||
$file_hashes.GetEnumerator() | foreach-object { [PSCustomObject]$_ } |
|
||||
export-csv $path_csv -NoTypeInformation
|
||||
|
||||
if ( -not $csv_file_hashes ) { return $true }
|
||||
if ( $csv_file_hashes.Count -ne $file_hashes.Count ) { return $true }
|
||||
|
||||
foreach ( $key in $csv_file_hashes.Keys ) {
|
||||
if ( $csv_file_hashes[ $key ] -ne $file_hashes[ $key ] ) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
return $false
|
||||
}
|
||||
|
||||
function mark-ModuleDirty {
|
||||
param( [string]$path_module )
|
||||
|
||||
$module_name = split-path $path_module -leaf
|
||||
$path_csv = Join-Path $path_build ("module_" + $module_name + "_hashes.csv")
|
||||
|
||||
remove-item -Force -Path $path_csv
|
||||
}
|
20
scripts/helpers/ini.ps1
Normal file
20
scripts/helpers/ini.ps1
Normal file
@@ -0,0 +1,20 @@
|
||||
# This is meant to be used with build.ps1, and is not a standalone script.
|
||||
|
||||
function Get-IniContent { param([ string]$filePath )
|
||||
$ini = @{}
|
||||
$currentSection = $null
|
||||
switch -regex -file $filePath
|
||||
{
|
||||
"^\[(.+)\]$" {
|
||||
$currentSection = $matches[1].Trim()
|
||||
$ini[$currentSection] = @{}
|
||||
}
|
||||
"^(.+?)\s*=\s*(.*)" {
|
||||
$key, $value = $matches[1].Trim(), $matches[2].Trim()
|
||||
if ($null -ne $currentSection) {
|
||||
$ini[$currentSection][$key] = $value
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ini
|
||||
}
|
67
scripts/helpers/misc.ps1
Normal file
67
scripts/helpers/misc.ps1
Normal file
@@ -0,0 +1,67 @@
|
||||
function clone-gitrepo { param( [string] $path, [string] $url )
|
||||
if (test-path $path) {
|
||||
# git -C $path pull
|
||||
}
|
||||
else {
|
||||
Write-Host "Cloning $url ..."
|
||||
git clone $url $path
|
||||
}
|
||||
}
|
||||
|
||||
function Update-GitRepo
|
||||
{
|
||||
param( [string] $path, [string] $url, [string] $build_command )
|
||||
|
||||
if ( $build_command -eq $null ) {
|
||||
write-host "Attempted to call Update-GitRepo without build_command specified"
|
||||
return
|
||||
}
|
||||
|
||||
$repo_name = $url.Split('/')[-1].Replace('.git', '')
|
||||
|
||||
$last_built_commit = join-path $path_build "last_built_commit_$repo_name.txt"
|
||||
if ( -not(test-path -Path $path))
|
||||
{
|
||||
write-host "Cloining repo from $url to $path"
|
||||
git clone $url $path
|
||||
|
||||
write-host "Building $url"
|
||||
push-location $path
|
||||
& "$build_command"
|
||||
pop-location
|
||||
|
||||
git -C $path rev-parse HEAD | out-file $last_built_commit
|
||||
$script:binaries_dirty = $true
|
||||
write-host
|
||||
return
|
||||
}
|
||||
|
||||
git -C $path fetch
|
||||
$latest_commit_hash = git -C $path rev-parse '@{u}'
|
||||
$last_built_hash = if (Test-Path $last_built_commit) { Get-Content $last_built_commit } else { "" }
|
||||
|
||||
if ( $latest_commit_hash -eq $last_built_hash ) {
|
||||
write-host
|
||||
return
|
||||
}
|
||||
|
||||
write-host "Build out of date for: $path, updating"
|
||||
write-host 'Pulling...'
|
||||
git -C $path pull
|
||||
|
||||
write-host "Building $url"
|
||||
push-location $path
|
||||
& $build_command
|
||||
pop-location
|
||||
|
||||
$latest_commit_hash | out-file $last_built_commit
|
||||
$script:binaries_dirty = $true
|
||||
write-host
|
||||
}
|
||||
|
||||
function verify-path { param( $path )
|
||||
if (test-path $path) {return}
|
||||
|
||||
new-item -ItemType Directory -Path $path
|
||||
return
|
||||
}
|
18
scripts/update_deps.ps1
Normal file
18
scripts/update_deps.ps1
Normal file
@@ -0,0 +1,18 @@
|
||||
$misc = join-path $PSScriptRoot 'helpers/misc.ps1'
|
||||
. $misc
|
||||
|
||||
$path_root = git rev-parse --show-toplevel
|
||||
$path_build = join-path $path_root 'build'
|
||||
$path_scripts = join-path $path_root 'scripts'
|
||||
$path_source = join-path $path_root 'source'
|
||||
$path_toolchain = join-path $path_root 'toolchain'
|
||||
|
||||
# Note: No longer using nasm
|
||||
if ($false) {
|
||||
$url_yasm = 'https://github.com/yasm/yasm.git'
|
||||
|
||||
$path_yasm = join-path $path_toolchain 'yasm'
|
||||
$path_libyasm = join-path $path_yasm 'libyasm'
|
||||
|
||||
clone-gitrepo $path_yasm $url_yasm
|
||||
}
|
29125
toolchain/gencpp/gencpp_c11.h
Normal file
29125
toolchain/gencpp/gencpp_c11.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
toolchain/rad/radbin.exe
Normal file
BIN
toolchain/rad/radbin.exe
Normal file
Binary file not shown.
BIN
toolchain/rad/radlink.exe
Normal file
BIN
toolchain/rad/radlink.exe
Normal file
Binary file not shown.
BIN
toolchain/rad/radlink.pdb
Normal file
BIN
toolchain/rad/radlink.pdb
Normal file
Binary file not shown.
13
toolchain/readme.md
Normal file
13
toolchain/readme.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Toolchain
|
||||
|
||||
## Gencpp C11
|
||||
|
||||
Repo: https://github.com/Ed94/gencpp.git
|
||||
Commit: 685bba36d5ed64b48908c950fbbb7f1dbb297120
|
||||
|
||||
## NASM
|
||||
|
||||
Version: 2.16.03
|
||||
Installed Via: scoop
|
||||
|
||||
## RAD Linker
|
Reference in New Issue
Block a user