重复调用WriteConsoleWin64上为NASM x64

问题描述

我最近开始学习汇编,为了练习,我想到了做一个小游戏。 要制作游戏的边框图形,我需要打印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整除。