Pure x64 Microsoft Macro Assembler & Vulkan Game Engine to explore Assembly Programming.
- Visual Studio 2022 for
ml64.exe
&link.exe
- Vulkan SDK 1.4.313.0 for the
vulkan-1.lib
- Unofficial MASM64 SDK
.asm
found inextern\masm64
- Assembler compatible Vulkan headers found in
extern\vulkan
Warning
You must add copy the masm64
folder from extern\masm64
to C:\
- Launch
x64 Native Tools Command Prompt for VS 2022
- Run
scripts\build.bat
- Run
build\main.exe
ordevenv build\main.exe
- MASM64 based Arena Allocator (saha.asm)
- Translated Vulkan C headers to MASM64 (using
tools\vulkan_gen.bat
)
Not using the CRT at all, just pure Assembler + Win32 + Vulkan.
I don't need the full SDK so I just took the .asm
files and placed them in my project.
They are hard coded to be in the C:\
root so maybe this can be fixed later.
I'm using 1.4.313.0
but it should be upgradable using vulkan-extractor.py
.
I went ahead and made a Unity/Jumbo build:
- Everything is included inside
main.asm
- Only assembing
main.asm
is required - Modules have header guards
- Modules are used to fake private but everything is global
- Variables/Functions dumped in main are intended to be specifically global
- The MASM64 SDK comes with an
invoke
macro that automates the Windows x64 calling convention - Example:
void Proc(&handle, count, NULL);
->invoke Proc, ADDR handle, count, 0
- In case of stack usage, stack MUST be aligned to
0x10
or 16 so make sureRSP
ends with a0
before calling a Windows or Vulkan function. - I noticed that the
invoke
macro doesn't take care of the shadow space allocation so you have tosub rsp, 32
thenadd rsp, 32
before a function call or else crash. This is especially true if you have to call some Windows/Vulkan function multiple times in a row such as printing otherwise its fine.
- I divided each vulkan step into its own module with each module having its own variables as I did not do any stack allocation.
- Modules look like this:
ModuleDrawFrame.asm
and insideDrawFrame_render_info
for vars andDrawFrame_Execute
for procs. - Everything is zeroed out since everything is allocated in the
.data
section but I don't zero anything manually which might be dangerous. - Look at
ModuleTemplate.asm
- Get the Vulkan triangle
- Fix
saha.asm
arena macro - Create an arena allocator for permanent storage
- Create modules for the rest of the vulkan code
- Clean up
vulkan-extractor.py
- Play with SIMD and game logic
You can regenerate the vulkan headers using python + libclang by invoking the ugly vulkan_gen.bat
file from the tools
directory. The generated headers are almost perfect except for a few bugs which I fixed manually. Will fully automate the process.
64 | 32 | 16 | 8 | name |
---|---|---|---|---|
rax | eax | ax | ah/al | accumulator |
rbx | ebx | bx | bh/bl | base |
rcx | ecx | cx | ch/cl | counter |
rdx | edx | dx | dh/dl | data |
rsi | esi | si | sil | source_idx |
rdi | edi | di | dil | destination_idx |
rbp | ebp | bp | bpl | base_pointer |
rsp | esp | sp | spl | stack_pointer |
r8 | r8d | r8w | r8b | general_purpose |
r9 | r9d | r9w | r9b | general_purpose |
r10 | r10d | r10w | r10b | general_purpose |
r11 | r11d | r11w | r11b | general_purpose |
r12 | r12d | r12w | r12b | general_purpose |
r13 | r13d | r13w | r13b | general_purpose |
r14 | r14d | r14w | r14b | general_purpose |
r15 | r15d | r15w | r15b | general_purpose |
Type | Registers | Responsibility |
---|---|---|
Volatile | rax, rcx, rdx, r8, r9, r10, r11, rsp, xmm0–xmm5 | Caller must save |
Non-Volatile | rbx, rbp, rsi, rdi, r12, r13, r14, r15, xmm6–xmm15 | Callee must save/restore |
If you are new to x86-64 Assembly I suggest: