我有以下简单的程序,我试图在Windows 10上使用MASM构建目标x64:
WSTR MACRO lbl:req,qstr:VARARG
LOCAL arg,unq,qot,q
lbl LABEL WORD
FOR arg,<qstr>
qot SubStr <arg>,1,1
q = 0
IFIDNI qot,<!'>;'
q = 1
ELSEIFIDNI qot,<!">;"
q = 1
ELSE
DW arg
ENDIF
IF q EQ 1
unq SubStr <arg>,2,@SizeStr(<arg>)-2
% FORC c,<unq>
DW "&c"
ENDM
ENDIF
ENDM
DW 0
ENDM
L MACRO qstr:VARARG
LOCAL sym,seg
seg EQU <.code>
%IFIDNI <@CurSeg>,<_DATA>
seg EQU <.data>
ENDIF
.CONST
ALIGN 4
WSTR sym,qstr
seg
EXITM <OFFSET sym>
ENDM
extrn LoadCursorW: PROC
extrn MessageBoxW: PROC
extrn ExitProcess: PROC
extrn GetModuleHandleW: PROC
extrn RegisterClassExW: PROC
extrn CreateWindowExW: PROC
extrn GetLastError: PROC
extrn DefWindowProcW: PROC
.data
wstr windowClassName,"AsmTestClass",0,0
wstr windowTitle,"AsmTest",0,0
HWND_DESKTOP textequ <0h>
MB_OK textequ <0h>
WM_CREATE textequ <0001h>
WM_DESTROY textequ <0002h>
WM_SIZE textequ <0005h>
WM_PAINT textequ <000fh>
CS_VREDRAW textequ <0001h>
CS_HREDRAW textequ <0002h>
WS_OVERLAPPED textequ <00000000h>
WS_CAPTION textequ <00c00000h>
WS_SYSMENU textequ <00080000h>
WS_MINIMIZEBOX textequ <00020000h>
CW_USEDEFAULT textequ <80000000h>
IDI_APPLICATION textequ <00007f00h>
WINDOW_WIDTH DWORD 800
WINDOW_HEIGHT DWORD 600
WNDCLASSEX STRUCT DWORD
cbSize DWORD ?
style DWORD ?
lpfnWndProc QWORD ?
cbClsExtra DWORD ?
cbWndExtra DWORD ?
hInstance QWORD ?
hIcon QWORD ?
hCursor QWORD ?
hbrBackground QWORD ?
lpszMenuName QWORD ?
lpszClassName QWORD ?
hIconSm QWORD ?
WNDCLASSEX ENDS
.code
main proc
LOCAL wc:WNDCLASSEX
LOCAL hWnd:QWORD
LOCAL hInstance:QWORD
LOCAL hCursor:QWORD
LOCAL ATOM:WORD
; hInstance = GetModuleHandle(NULL)
mov rcx, 0
call GetModuleHandleW
mov hInstance, rax
; hCursor = LoadCursor(NULL,IDI_APPLICATION)
mov edx, IDI_APPLICATION
xor ecx, ecx
call LoadCursorW
mov hCursor, rax
; Setup Window Class
mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, CS_VREDRAW or CS_HREDRAW
lea rax, OFFSET WndProc
mov wc.lpfnWndProc, rax
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
lea rax, hInstance
mov wc.hInstance, rax
mov wc.hbrBackground, 0
mov wc.lpszMenuName, 0
lea rax, hCursor
mov wc.hCursor, rax
lea rax, windowClassName
mov wc.lpszClassName, rax
mov wc.hIconSm, 0
lea rcx, wc
call RegisterClassExW
mov ATOM, ax
; CreateWindowExW
mov QWORD PTR [rsp+88], 0 ; lpParam
lea rax, hInstance
mov QWORD PTR [rsp+80], rax ; hInstance
mov QWORD PTR [rsp+72], 0 ; hMenu
mov QWORD PTR [rsp+64], 0 ; hWndParent
mov edx, WINDOW_HEIGHT
mov DWORD PTR [rsp+56], edx ; nHeight
mov edx, WINDOW_WIDTH
mov DWORD PTR [rsp+48], edx ; nWidth
mov DWORD PTR [rsp+40], CW_USEDEFAULT ; Y
mov DWORD PTR [rsp+32], CW_USEDEFAULT ; X
mov r9d, WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX ; dwStyle
lea r8, windowTitle ; lpWindowName
lea rdx, windowClassName ; lpClassName
xor ecx,ecx ; dwExStyle
call CreateWindowExW
cmp rax, 0
je WindowFailed
jmp WindowSuccess
WindowFailed:
call GetLastError
; to-do check error
WindowSuccess:
mov hWnd, rax
mov rcx, HWND_DESKTOP ; hWnd
lea rdx, L("Hello x64 World!",0,0) ; lpText
lea r8, L("Win64 Demo",0,0) ; lpCaption
mov r9d, MB_OK ; uType
call MessageBoxW
mov ecx, eax ; uExitCode
call ExitProcess
main endp
WndProc proc
LOCAL hWnd:QWORD
LOCAL uMsg:DWORD
LOCAL wParam:QWORD
LOCAL lParam:QWORD
LOCAL result:QWORD
mov lParam, r9
mov wParam, r8
mov uMsg, edx
mov hWnd, rcx
; msg handler
cmp uMsg,WM_CREATE
je create
cmp uMsg,WM_PAINT
je paint
cmp uMsg,WM_DESTROY
je destroy
cmp uMsg,WM_SIZE
je resize
; default
call DefWindowProcW
mov result,rax
jmp finish
create:
mov result, 0
jmp finish
paint:
mov result, 0
jmp finish
destroy:
mov result, 0
jmp finish
resize:
mov result, 0
jmp finish
finish:
mov rax, result
ret
WndProc endp
End
Masm会自动添加以下代码:
main proc
push rbp
mov rbp,rsp
add rsp,0FFFFFFFFFFFFFF90h
..
main endp
WndProc proc
push rbp
mov rbp,rsp
add rsp,0FFFFFFFFFFFFFFD8h
...
leave
ret
WndProc endp
但是,当我们调用WndProc例程时,在调用DefWindowProcW时会触发访问冲突
我怀疑这是因为堆栈指针没有正确设置,但masm似乎正在为此添加代码。如何正确地做到这一点?
masm添加的代码
add rsp,0FFFFFFFFFFFFFFD8h
它相当于亚转速40。它不能被16整除,在我的代码中添加sub rsp,8修复了崩溃。
WndProc proc
LOCAL hWnd:QWORD
LOCAL uMsg:DWORD
LOCAL wParam:QWORD
LOCAL lParam:QWORD
LOCAL result:QWORD
sub rsp, 8
解决这个问题的最好方法是什么,或者masm有没有一种方法可以自动计算正确的值/或预测需要提前纠正的内容?
2条答案
按热度按时间b91juud31#
您可以使用此命令将rsp向下舍入到16字节边界:
我使用VS2015进行了测试,并且使用了JavaScript会导致MASM自动生成该代码。使用VS2015,使用wmain而不是WndProc,在进入时,rsp的最后一个半字节== 8,显然预计进入代码将使用rbp作为帧指针:
将rsp置于16字节边界上
如果在输入时,rsp的最后一个半字节总是8,那么你可以使用虚拟LOCALS,这样所有的LOCALS都占用8 + 16字节的倍数。
h43kikqp2#
看起来你没有在程序中添加阴影空间。我读到,对于常规调用,你应该从rsp中减去32,而对于较大的调用,你要减去16的倍数来覆盖你的参数。Windows有12个参数,所以
32 + 64
将覆盖你的阴影空间,然后在调用后将其添加回来。诚然,我是新的组装,并不认为我完全理解为什么这需要。