文章目錄
- nasm - BasicWindow_64
- 概述
- 筆記
- nasm_main.asm
- my_build.bat
- END
nasm - BasicWindow_64
概述
學個demo, 這個demo最主要學到了:
不用在調用每個API前都準備陰影區,在API調用后棧平衡。
可以在函數入口處考慮到所用的棧尺寸最大值(16字節對齊,陰影區,函數的所有局部變量,調用API時用的參數最多的棧尺寸),開棧;在函數出口進行棧平衡。
其他細節地方,自己對著VS2019release版的x64反匯編就能搞。
說到底,要想拿匯編代碼來寫東西,要知道正向怎么寫,然后才能參考反匯編代碼來寫NASM的工程。要不誰知道對應的匯編代碼怎么弄。
NASM代碼和x64反匯編出來的代碼基本一樣,稍微改一下就能拿來用。
筆記
nasm_main.asm
; @file nasm_main.asm
; @brief 用NASM實現一個64bits的基本窗口擴展
; nasm - BasicWindow_64
; ----------------------------------------
; 宏定義
; ----------------------------------------
; Basic Window Extended, 64 bit. V1.05
ANSI_CHARSET EQU 0 ; Constants
BLACKNESS EQU 42h
CLIP_DEFAULT_PRECIS EQU 0
CS_BYTEALIGNWINDOW EQU 2000h
CS_HREDRAW EQU 2
CS_VREDRAW EQU 1
DEFAULT_PITCH EQU 0
ES_AUTOHSCROLL EQU 80h
ES_CENTER EQU 1
FALSE EQU 0
GRAY_BRUSH EQU 2
IDC_ARROW EQU 7F00h
IDI_APPLICATION EQU 7F00h
IDNO EQU 7
IMAGE_CURSOR EQU 2
IMAGE_ICON EQU 1
LR_SHARED EQU 8000h
MB_DEFBUTTON2 EQU 100h
MB_YESNO EQU 4
NULL EQU 0
NULL_BRUSH EQU 5
OPAQUE EQU 2
PROOF_QUALITY EQU 2
SM_CXFULLSCREEN EQU 10h
SM_CYFULLSCREEN EQU 11h
SS_CENTER EQU 1
SS_NOTIFY EQU 100h
SW_SHOWNORMAL EQU 1
TRUE EQU 1
WM_CLOSE EQU 10h
WM_COMMAND EQU 111h
WM_CREATE EQU 1
WM_CTLCOLOREDIT EQU 133h
WM_CTLCOLORSTATIC EQU 138h
WM_DESTROY EQU 2
WM_PAINT EQU 0Fh
WM_SETFONT EQU 30h
OUT_DEFAULT_PRECIS EQU 0
WS_CHILD EQU 40000000h
WS_EX_COMPOSITED EQU 2000000h
WS_OVERLAPPEDWINDOW EQU 0CF0000h
WS_TABSTOP EQU 10000h
WS_VISIBLE EQU 10000000hWindowWidth EQU 640
WindowHeight EQU 170
Static1ID EQU 100
Static2ID EQU 101
Edit1ID EQU 102
Edit2ID EQU 103; ----------------------------------------
; 外部函數聲明
; ----------------------------------------
extern AdjustWindowRectEx ; Import external symbols
extern BeginPaint ; Windows API functions, not decorated
extern BitBlt
extern CreateFontA
extern CreateSolidBrush
extern CreateWindowExA
extern DefWindowProcA
extern DeleteObject
extern DestroyWindow
extern DispatchMessageA
extern EndPaint
extern ExitProcess
extern GetDlgCtrlID
extern GetStockObject
extern GetMessageA
extern GetModuleHandleA
extern GetSystemMetrics
extern InvalidateRect
extern IsDialogMessageA
extern LoadImageA
extern MessageBoxA
extern PostQuitMessage
extern RegisterClassExA
extern SendMessageA
extern SetBkColor
extern SetBkMode
extern SetTextColor
extern ShowWindow
extern TranslateMessage
extern UpdateWindowglobal fn_Start ; Export symbols. The entry point; ----------------------------------------
; 區段定義
; ----------------------------------------
section .data ; Initialized data segment
; // 常量是不需要字節對齊的Static1Colour dd 0F0F0F0h ; Colour (0BBGGRRh)Static1ColourA dd 020A0F0hStatic2Colour dd 000FFFFhStatic2ColourA dd 08000FFhEdit1TextColour dd 0F590F5hEdit1BackColour dd 0A00000hEdit2TextColour dd 0A56E3BhEdit2BackColour dd 0FEFE8EhBackgroundColour dd 0A56E3Bh WindowName db "Basic Window Extended 64", 0ClassName db "Window", 0SegoeUI db "Segoe UI", 0StaticClass db "STATIC", 0EditClass db "EDIT", 0Text1 db "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789", 0Text2 db "abcdefghijklmnopqrstuvwxyz_0123456789", 0ExitText db "Do you want to exit?", 0section .bss ; Uninitialized data segmentalignb 8 ; 8字節對齊hInstance resq 1BackgroundBrush resq 1Font resq 1Static1 resq 1Static2 resq 1Edit1 resq 1Edit2 resq 1section .text ; Code segment
; ----------------------------------------
; 函數定義
; ----------------------------------------
fn_Start:; 16字節對齊; 進了函數之后,默認就是8字節對齊(因為系統調用fn_Start時, 棧上有調用fn_Start后的返回地址8個字節), 將棧頂再減去8, 就是16字節對齊sub RSP, 8 ; Align stack pointer to 16 bytes; // 在一個函數中,如果調用的API比較少,則需要在API調用的前后進行單獨的棧平衡sub RSP, 32 ; 32 bytes of shadow spacexor ECX, ECXcall GetModuleHandleAmov qword [REL hInstance], RAXadd RSP, 32 ; Remove the 32 bytes; 如果是自己實現的函數, 就不用特意做(陰影區, 16字節對齊, 棧平衡)都在自己的函數內做了就行call fn_WinMain.Exit:xor ECX, ECXcall ExitProcess ; 退出的函數是API, 為什么不做棧平衡, 是ExitProcess內部不用陰影區么? ExitProcess是特例?
; ----------------------------------------
fn_WinMain:push RBP ; Set up a stack frame; 返回地址 + push RBP 就已經是16字節對齊了mov RBP, RSP; 函數內棧開多大,也不用精確計算,差不多就行(32字節的陰影區 + 函數內局部變量的字節數 + 多開一點,夠函數調用時用的臨時入參變量的賦值); 這里有一個技巧,在一個函數中調用API, 不用每次都在前后準備棧(陰影區)/清除棧(陰影區); 只需要在函數入口出口處準備足夠棧空間(16字節對齊 + 陰影區 + 函數的局部變量區 + 調用API時最多的參數變量空間)/棧平衡; 調用API時, 只需要準備API需要的參數就行(RCX,RDX,R8,R9; 其余參數從RBP + 32開始, 參數5,參數6, ...)sub RSP, 160 + 64 + 32 ; 160 bytes for local variables; + 64 (8 * 8 byte) parameters ; + 32 shadow space; Kept to a multiple of 16 for API functions%define Screen.Width RBP - 160 ; 4 bytes
%define Screen.Height RBP - 156 ; 4 bytes%define ClientArea RBP - 152 ; RECT structure. 16 bytes
%define ClientArea.left RBP - 152 ; 4 bytes. Start on a 4 byte boundary
%define ClientArea.top RBP - 148 ; 4 bytes
%define ClientArea.right RBP - 144 ; 4 bytes
%define ClientArea.bottom RBP - 140 ; 4 bytes. End on a 4 byte boundary%define wc RBP - 136 ; WNDCLASSEX structure, 80 bytes
%define wc.cbSize RBP - 136 ; 4 bytes. Start on an 8 byte boundary
%define wc.style RBP - 132 ; 4 bytes
%define wc.lpfnWndProc RBP - 128 ; 8 bytes
%define wc.cbClsExtra RBP - 120 ; 4 bytes
%define wc.cbWndExtra RBP - 116 ; 4 bytes
%define wc.hInstance RBP - 112 ; 8 bytes
%define wc.hIcon RBP - 104 ; 8 bytes
%define wc.hCursor RBP - 96 ; 8 bytes
%define wc.hbrBackground RBP - 88 ; 8 bytes
%define wc.lpszMenuName RBP - 80 ; 8 bytes
%define wc.lpszClassName RBP - 72 ; 8 bytes
%define wc.hIconSm RBP - 64 ; 8 bytes. End on an 8 byte boundary%define msg RBP - 56 ; MSG structure, 48 bytes
%define msg.hwnd RBP - 56 ; 8 bytes. Start on an 8 byte boundary
%define msg.message RBP - 48 ; 4 bytes
%define msg.Padding1 RBP - 44 ; 4 bytes. Natural alignment padding
%define msg.wParam RBP - 40 ; 8 bytes
%define msg.lParam RBP - 32 ; 8 bytes
%define msg.time RBP - 24 ; 4 bytes
%define msg.py.x RBP - 20 ; 4 bytes
%define msg.pt.y RBP - 16 ; 4 bytes
%define msg.Padding2 RBP - 12 ; 4 bytes. Structure length padding%define hWnd RBP - 8 ; 8 bytesmov ECX, dword [REL BackgroundColour]call CreateSolidBrush ; Create a brush for the window backgoundmov qword [REL BackgroundBrush], RAXmov dword [wc.cbSize], 80 ; [RBP - 136]mov dword [wc.style], CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW ; [RBP - 132]lea RAX, [REL fn_WndProc]mov qword [wc.lpfnWndProc], RAX ; [RBP - 128]mov dword [wc.cbClsExtra], NULL ; [RBP - 120]mov dword [wc.cbWndExtra], NULL ; [RBP - 116]mov RAX, qword [REL hInstance]mov qword [wc.hInstance], RAX ; [RBP - 112]xor ECX, ECXmov EDX, IDI_APPLICATIONmov R8D, IMAGE_ICONxor R9D, R9Dmov qword [RSP + 4 * 8], NULLmov qword [RSP + 5 * 8], LR_SHAREDcall LoadImageA ; Large program iconmov qword [wc.hIcon], RAX ; [RBP - 104]xor ECX, ECXmov EDX, IDC_ARROWmov R8D, IMAGE_CURSORxor R9D, R9Dmov qword [RSP + 4 * 8], NULLmov qword [RSP + 5 * 8], LR_SHAREDcall LoadImageA ; Cursormov qword [wc.hCursor], RAX ; [RBP - 96]mov RAX, qword [REL BackgroundBrush]mov qword [wc.hbrBackground], RAX ; [RBP - 88]mov qword [wc.lpszMenuName], NULL ; [RBP - 80]lea RAX, [REL ClassName]mov qword [wc.lpszClassName], RAX ; [RBP - 72]xor ECX, ECXmov EDX, IDI_APPLICATIONmov R8D, IMAGE_ICONxor R9D, R9Dmov qword [RSP + 4 * 8], NULLmov qword [RSP + 5 * 8], LR_SHAREDcall LoadImageA ; Small program iconmov qword [wc.hIconSm], RAX ; [RBP - 64]lea RCX, [wc] ; [RBP - 136]call RegisterClassExAmov ECX, SM_CXFULLSCREENcall GetSystemMetrics ; Get the current screen widthmov dword [Screen.Width], EAX ; [RBP - 160]mov ECX, SM_CYFULLSCREENcall GetSystemMetrics ; Get the current screen heightmov dword [Screen.Height], EAX ; [RBP - 156]mov dword [ClientArea.left], 0 ; [RBP - 152]mov dword [ClientArea.top], 0 ; [RBP - 148]mov dword [ClientArea.right], WindowWidth ; [RBP - 144]mov dword [ClientArea.bottom], WindowHeight ; [RBP - 140]lea RCX, [ClientArea] ; [RBP - 152]mov EDX, WS_OVERLAPPEDWINDOW ; Stylexor R8D, R8Dmov R9D, WS_EX_COMPOSITED ; Extended stylecall AdjustWindowRectEx ; Get window size for the desired client size; Size is returned in ClientAreamov EAX, dword [ClientArea.top] ; [RBP - 148]sub dword [ClientArea.bottom], EAX ; New Height = ClientArea.bottom - ClientArea.topmov EAX, dword [ClientArea.left] ; [RBP - 152]sub dword [ClientArea.right], EAX ; New Width = ClientArea.right - ClientArea.leftmov ECX, WS_EX_COMPOSITEDlea RDX, [REL ClassName]lea R8, [REL WindowName]mov R9D, WS_OVERLAPPEDWINDOWxor R10D, R10Dmov EAX, dword [Screen.Width] ; [RBP - 160]sub EAX, dword [ClientArea.right] ; Corrected window width. [RBP - 144]cmovs EAX, R10D ; Clamp to 0 (left) if negativeshr EAX, 1 ; EAX = (Screen.Width - window height) / 2mov dword [RSP + 4 * 8], EAX ; X position, now centredmov EAX, dword [Screen.Height] ; [RBP - 156]sub EAX, dword [ClientArea.bottom] ; Corrected window height. [RBP - 140]cmovs EAX, R10D ; Clamp to 0 (top) if negativeshr EAX, 1 ; EAX = (Screen.Height - window height) / 2mov dword [RSP + 5 * 8], EAX ; Y position, now centredmov EAX, dword [ClientArea.right] ; [RBP - 144]mov dword [RSP + 6 * 8], EAX ; Widthmov EAX, dword [ClientArea.bottom] ; [RBP - 140]mov dword [RSP + 7 * 8], EAX ; Heightmov qword [RSP + 8 * 8], NULLmov qword [RSP + 9 * 8], NULLmov RAX, qword [REL hInstance]mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [hWnd], RAX ; [RBP - 8]mov RCX, qword [hWnd] ; [RBP - 8]mov EDX, SW_SHOWNORMALcall ShowWindowmov RCX, qword [hWnd] ; [RBP - 8]call UpdateWindow.MessageLoop:lea RCX, [msg] ; [RBP - 56]xor EDX, EDXxor R8D, R8Dxor R9D, R9Dcall GetMessageAcmp RAX, 0je .Donemov RCX, qword [hWnd] ; [RBP - 8]lea RDX, [msg] ; [RBP - 56]call IsDialogMessageA ; For keyboard strokescmp RAX, 0jne .MessageLoop ; Skip TranslateMessage and DispatchMessageAlea RCX, [msg] ; [RBP - 56]call TranslateMessagelea RCX, [msg] ; [RBP - 56]call DispatchMessageAjmp .MessageLoop.Done:xor EAX, EAXmov RSP, RBP ; Remove the stack framepop RBPret
; ----------------------------------------
fn_WndProc:push RBP ; Set up a stack framemov RBP, RSPsub RSP, 80 + 80 + 32 ; 80 bytes for local variables; + 80 (10 * 8 byte) parameters; + 32 shadow space; Kept to a multiple of 16 for API functions%define hWnd RBP + 16 ; Location of the shadow space setup by
%define uMsg RBP + 24 ; the calling function
%define wParam RBP + 32
%define lParam RBP + 40%define ps RBP - 80 ; PAINTSTRUCT structure. 72 bytes
%define ps.hdc RBP - 80 ; 8 bytes. Start on an 8 byte boundary
%define ps.fErase RBP - 72 ; 4 bytes
%define ps.rcPaint.left RBP - 68 ; 4 bytes
%define ps.rcPaint.top RBP - 64 ; 4 bytes
%define ps.rcPaint.right RBP - 60 ; 4 bytes
%define ps.rcPaint.bottom RBP - 56 ; 4 bytes
%define ps.Restore RBP - 52 ; 4 bytes
%define ps.fIncUpdate RBP - 48 ; 4 bytes
%define ps.rgbReserved RBP - 44 ; 32 bytes
%define ps.Padding RBP - 12 ; 4 bytes. Structure length padding%define hdc RBP - 8 ; 8 bytesmov qword [hWnd], RCX ; Free up RCX RDX R8 R9 by spilling themov qword [uMsg], RDX ; 4 passed parameters to the shadow spacemov qword [wParam], R8 ; We can now access these parameters by namemov qword [lParam], R9cmp qword [uMsg], WM_CLOSE ; [RBP + 24]je proc.WMCLOSEcmp qword [uMsg], WM_COMMAND ; [RBP + 24]je proc.WMCOMMANDcmp qword [uMsg], WM_CREATE ; [RBP + 24]je proc.WMCREATEcmp qword [uMsg], WM_CTLCOLOREDIT ; [RBP + 24]je proc.WMCTLCOLOREDITcmp qword [uMsg], WM_CTLCOLORSTATIC ; [RBP + 24]je proc.WMCTLCOLORSTATICcmp qword [uMsg], WM_DESTROY ; [RBP + 24]je proc.WMDESTROYcmp qword [uMsg], WM_PAINT ; [RBP + 24]je proc.WMPAINTproc.DefaultMessage:mov RCX, qword [hWnd] ; [RBP + 16]mov RDX, qword [uMsg] ; [RBP + 24]mov R8, qword [wParam] ; [RBP + 32]mov R9, qword [lParam] ; [RBP + 40]call DefWindowProcAjmp proc.Returnproc.WMCLOSE:mov RCX, qword [hWnd] ; [RBP + 16]lea RDX, [REL ExitText]lea R8, [REL WindowName]mov R9D, MB_YESNO | MB_DEFBUTTON2call MessageBoxAcmp RAX, IDNOje proc.Return.WM_Processedmov RCX, qword [hWnd] ; [RBP + 16]call DestroyWindow ; Send a WM_DESTROY messagejmp proc.Return.WM_Processedproc.WMCOMMAND:mov RAX, qword [wParam] ; RAX = ID. [RBP + 32]cmp AX, Static1IDje .Static1cmp AX, Static2IDje .Static2jmp proc.Return.WM_Processed.Static1:mov EAX, dword [REL Static1Colour]mov ECX, dword [REL Static1ColourA]mov dword [REL Static1Colour], ECXmov dword [REL Static1ColourA], EAX ; Swap coloursmov RCX, qword [lParam] ; Static1 handle. [RBP + 40]xor EDX, EDXmov R8D, TRUEcall InvalidateRect ; Redraw controljmp proc.Return.WM_Processed.Static2:mov EAX, dword [REL Static2Colour]mov ECX, dword [REL Static2ColourA]mov dword [REL Static2Colour], ECXmov dword [REL Static2ColourA], EAX ; Swap coloursmov RCX, qword [lParam] ; Static2 handle. [RBP + 40]xor EDX, EDXmov R8D, TRUEcall InvalidateRect ; Redraw controljmp proc.Return.WM_Processedproc.WMCREATE:xor ECX, ECXlea RDX, [REL StaticClass]lea R8, [REL Text1] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTERmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 10 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Static1ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Static1], RAXxor ECX, ECXlea RDX, [REL StaticClass]lea R8, [REL Text2] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTERmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 40 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Static2ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Static2], RAXxor ECX, ECXlea RDX, [REL EditClass]lea R8, [REL Text1] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLLmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 70 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Edit1ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Edit1], RAXxor ECX, ECXlea RDX, [REL EditClass]lea R8, [REL Text2] ; Default textmov R9D, WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLLmov qword [RSP + 4 * 8], 120 ; Xmov qword [RSP + 5 * 8], 100 ; Ymov qword [RSP + 6 * 8], 400 ; Widthmov qword [RSP + 7 * 8], 20 ; Heightmov RAX, qword [hWnd] ; [RBP + 16]mov qword [RSP + 8 * 8], RAX mov qword [RSP + 9 * 8], Edit2ID mov RAX, qword [REL hInstance] mov qword [RSP + 10 * 8], RAXmov qword [RSP + 11 * 8], NULLcall CreateWindowExAmov qword [REL Edit2], RAXmov ECX, 20 ; Sizexor EDX, EDXxor R8D, R8D xor R9D, R9Dmov qword [RSP + 4 * 8], 400 ; Weightmov qword [RSP + 5 * 8], NULLmov qword [RSP + 6 * 8], NULLmov qword [RSP + 7 * 8], NULLmov qword [RSP + 8 * 8], ANSI_CHARSETmov qword [RSP + 9 * 8], OUT_DEFAULT_PRECISmov qword [RSP + 10 * 8], CLIP_DEFAULT_PRECISmov qword [RSP + 11 * 8], PROOF_QUALITYmov qword [RSP + 12 * 8], DEFAULT_PITCHlea RAX, [REL SegoeUI]mov qword [RSP + 13 * 8], RAXcall CreateFontAmov qword [REL Font], RAXmov RCX, qword [REL Static1]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Static1 fontmov RCX, qword [REL Static2]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Static2 fontmov RCX, qword [REL Edit1]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Edit1 fontmov RCX, qword [REL Edit2]mov EDX, WM_SETFONTmov R8, qword [REL Font]xor R9D, R9Dcall SendMessageA ; Set Edit2 fontjmp proc.Return.WM_Processedproc.WMCTLCOLOREDIT: ; For colouring edit controlsmov RCX, qword [lParam] ; [RBP + 40]call GetDlgCtrlID ; RAX = IDcmp RAX, Edit1IDje .Edit1cmp RAX, Edit2IDje .Edit2.Default:mov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Edit1:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit1TextColour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit1BackColour]call SetBkColormov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Edit2:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit2TextColour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Edit2BackColour]call SetBkColormov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Returnproc.WMCTLCOLORSTATIC: ; For colouring static controlsmov RCX, qword [lParam] ; [RBP + 40]call GetDlgCtrlID ; RAX = IDcmp RAX, Static1IDje .Static1cmp RAX, Static2IDje .Static2.Default:mov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Static1:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Static1Colour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, 0604060hcall SetBkColormov ECX, NULL_BRUSHcall GetStockObject ; Return a brushjmp proc.Return.Static2:mov RCX, qword [wParam] ; [RBP + 32]mov EDX, dword [REL Static2Colour]call SetTextColormov RCX, qword [wParam] ; [RBP + 32]mov EDX, OPAQUEcall SetBkModemov RCX, qword [wParam] ; [RBP + 32]mov EDX, 0005000hcall SetBkColormov ECX, GRAY_BRUSHcall GetStockObject ; Return a brushjmp proc.Returnproc.WMDESTROY:mov RCX, qword [REL BackgroundBrush]call DeleteObjectmov RCX, qword [REL Font]call DeleteObjectxor ECX, ECXcall PostQuitMessagejmp proc.Return.WM_Processedproc.WMPAINT:mov RCX, qword [hWnd] ; [RBP + 16]lea RDX, [ps] ; [RBP - 80]call BeginPaintmov qword [hdc], RAX ; [RBP - 8]mov RCX, qword [hdc] ; Destination device context. [RBP - 8]mov EDX, 120 ; Destination Xmov R8D, 130 ; Destination Ymov R9D, 400 ; Widthmov qword [RSP + 4 * 8], 20 ; Heightmov RAX, qword [hdc] ; [RBP - 8]mov qword [RSP + 5 * 8], RAX ; Source device contextmov qword [RSP + 6 * 8], 0 ; Source Xmov qword [RSP + 7 * 8], 0 ; Source Ymov qword [RSP + 8 * 8], BLACKNESS ; Operationcall BitBlt ; Blit a black rectanglemov RCX, qword [hWnd] ; [RBP + 16]lea RDX, [ps] ; [RBP - 80]call EndPaintproc.Return.WM_Processed:xor EAX, EAX ; WM_ has been processed, return 0proc.Return:mov RSP, RBP ; Remove the stack framepop RBPret
my_build.bat
@echo off
clsrem ----------------------------------------
rem my_build.batrem env
rem NASM version 2.16.03 compiled on Apr 17 2024
rem GoLink.Exe Version 1.0.4.6 Copyright Jeremy Gordon 2002-2025set path=C:\Program Files\NASM;C:\soft\Golink;%path%rem . bat默認是不支持中文的 .
rem echo full path name - %~f0
rem echo full path - %~dp0
rem echo file name - %~nx0
rem echo work path - %cd%
rem all param - %*rem . rem注釋的第1個字符和最后1個字符,不能是中文,否則有概率會當作命令來執行 .
rem . 調試.bat的方法 .
rem . 如果.bat寫的不對,又不容易看出來,只能在每行后面加pause, 然后執行.bat, 然后按一下空格執行一行 .set prj_src_name_1=nasm_main.asm
set prj_obj_name_1=nasm_main.obj
set prj_exe_name=BasicWindow_ext_64.exerem win32 or win64
set prj_build_type=win64rem /console or /SUBSYSTEM:WINDOWS
set prj_sub_sys=/SUBSYSTEM:WINDOWSecho [%~nx0 %*]if "%1" == "build" (call :fn_build
) else if "%1" == "clear" (call :fn_clear
) else (call :fn_usage
)goto endrem ----------------------------------------
rem function
rem ----------------------------------------:fn_usage
echo usage my_build.bat [option]
echo build - build asm to EXE
echo clear - clear trush on the project
exit /brem ----------------------------------------
:fn_build
echo build ...rem find file on work path
call :fn_del_file "%prj_obj_name_1%"nasm -f %prj_build_type% %prj_src_name_1% -o %prj_obj_name_1%
rem 用IDA打開.obj 已經可以看到實現邏輯了call :fn_del_file "%prj_exe_name%"rem 如果不指定要連接的dll, 會報錯
golink /entry:fn_Start '%prj_sub_sys%' kernel32.dll user32.dll gdi32.dll %prj_obj_name_1% /fo %prj_exe_name%call :fn_exec "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_clear
echo clear ...
call :fn_del_file "%prj_obj_name_1%"
call :fn_del_file "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_del_file
if exist "%~1" (echo del "%~1" del "%~1"
)
exit /b:fn_exec
if exist "%~1" (echo exec "%~1"%~1
)
exit /brem ----------------------------------------
:end
echo END
rem pause
rem call cmd