问题描述
我最近开始学习汇编,为了练习,我想到了做一个小游戏。 要制作游戏的边框图形,我需要打印n次块字符。 为了对此进行测试,我编写了以下代码:
bits 64
global main
extern ExitProcess
extern GetStdHandle
extern WriteConsoleA
section .text
main:
mov rcx,-11
call GetStdHandle
mov rbx,rax
drawFrame:
mov r12,[sze]
l:
mov rcx,rbx
mov rdx,msg
mov r8,1
sub rsp,48
mov r9,[rsp+40]
mov qword [rsp+32],0
call WriteConsoleA
dec r12
jnz l
xor rcx,rcx
call ExitProcess
section .data
score dd 0
sze dq 20
msg db 0xdb
我想使用WinAPI Function进行输出。 有趣的是,使用WriteConsoleA时,此代码在打印一个字符后停止,但是当我使用C的putchar时,它可以正常工作。我还可以使用WriteConsoleA函数使C等效,也可以正常工作。 C代码的反汇编并没有使我更进一步。
我怀疑在使用堆栈时出现了我看不到的错误。希望有人可以解释或指出。
解决方法
您不想在每个循环中都从 RSP 减去48。您只需在循环之前和调用C库函数或WinAPI之前分配一次该空间。
主要问题是您在 R9 中的第四个参数。 import React from "react";
import Modal from "../components/Modal";
export default function ComponentThatWrapsModifySalespersons() {
function handleSubmit(newSalesperson) {
console.log(newSalesperson);
}
return (
<ModifySalespersons
salesperson={{ firstName: "hello",lastName: "world",address: "calif" }}
onSubmit={handleSubmit}
/>
);
}
function ModifySalespersons(props) {
const [state,setState] = React.useState({ ...props.salesperson });
function handleChange(e) {
const key = e.target.name;
const value = e.target.value;
setState(prev => ({
...prev,[key]: value
}));
}
function submit() {
// return new salesperson object
props.onSubmit(state);
// props.setIsOpen(false);
}
console.log(state);
return (
<>
<div>
<div>
<h3 class="text-lg leading-6 font-medium text-gray-900">
Salesperson Information
</h3>
</div>
<form class="mt-6 sm:mt-5">
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label
for="first_name"
class="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2"
>
First name
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<div class="max-w-lg rounded-md shadow-sm sm:max-w-xs">
<input
name="firstName"
onChange={handleChange}
value={state.firstName}
id="first_name"
class="form-input block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"
/>
</div>
</div>
</div>
<div class="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start">
<label
for="last_name"
class="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2"
>
Last name
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<div class="max-w-lg rounded-md shadow-sm sm:max-w-xs">
<input
name="lastName"
onChange={handleChange}
value={state.lastName}
id="last_name"
class="form-input block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"
/>
</div>
</div>
</div>
<div class="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label
for="address1"
class="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2"
>
Address
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<div class="max-w-lg rounded-md shadow-sm sm:max-w-xs">
<input
name="address"
onChange={handleChange}
value={state.address}
id="address1"
class="form-input block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"
/>
</div>
</div>
</div>
{/* more controls here */}
</form>
</div>
<div class="mt-5 sm:mt-6 space-y-2">
<span class="flex w-full rounded-md shadow-sm">
<button
onClick={submit}
type="button"
class="inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-indigo-600 text-base leading-6 font-medium text-white shadow-sm hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo transition ease-in-out duration-150 sm:text-sm sm:leading-5"
>
Submit
</button>
</span>
<span class="flex w-full rounded-md shadow-sm">
<button
onClick={() => props.setIsOpen(false)}
type="button"
class="inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-white text-base leading-6 font-medium text-gray-500 shadow-sm hover:bg-gray-100 focus:outline-none focus:border-gray-700 focus:shadow-outline-gray transition ease-in-out duration-150 sm:text-sm sm:leading-5"
>
Cancel
</button>
</span>
</div>
</>
);
}
函数定义为:
WriteConsole
R9 应该是指向存储位置的指针,该存储位置返回带有写入的字符数的BOOL WINAPI WriteConsole(
_In_ HANDLE hConsoleOutput,_In_ const VOID *lpBuffer,_In_ DWORD nNumberOfCharsToWrite,_Out_opt_ LPDWORD lpNumberOfCharsWritten,_Reserved_ LPVOID lpReserved
);
,但是您可以这样做:
DWORD
这会将从内存地址mov r9,[rsp+40]
开始的8个字节移到 R9 。您想要的是RSP+40
的地址,可以使用LEA
指令完成此操作:
[rsp+40]
您的代码可能看起来像这样:
lea r9,[rsp+40]
重要说明:为了符合64-bit Microsoft ABI,必须在调用WinAPI或 C 之前保持堆栈指针的16字节对齐。库功能。调用bits 64
global main
extern ExitProcess
extern GetStdHandle
extern WriteConsoleA
section .text
main:
sub rsp,56 ; Allocate space for local variable(s)
; Allocate 32 bytes of space for shadow store
; Maintain 16 byte stack alignment for WinAPI/C library calls
; 56+8=64 . 64 is evenly divisible by 16.
mov rcx,-11
call GetStdHandle
mov rbx,rax
drawFrame:
mov r12,[sze]
l:
mov rcx,rbx
mov rdx,msg
mov r8,1
lea r9,[rsp+40]
mov qword [rsp+32],0
call WriteConsoleA
dec r12
jnz l
xor rcx,rcx
call ExitProcess
section .data
score dd 0
sze dq 20
msg db 0xdb
函数后,堆栈指针( RSP )对齐了16个字节。在main
函数开始执行堆栈时,由于8字节的返回地址被压入了堆栈,因此未对齐8。 48 + 8 = 56不会使您回到16字节对齐的堆栈地址(56不能被16整除),而56 + 8 = 64可以。 64被16整除。