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