当我们使用x64程序集进行Windows x64内存管理时,如何计算参数应该推送到的位置

问题描述 投票:0回答:1

我对一些用于内存管理的 x64 汇编代码感到困惑,例如 CreateFileA、WriteFile 和 ReadFile。当使用 WriteFile 创建文件时,他们为将被推送到堆栈的参数定义了几个位置。例如,

.dwCreationDisposition equ 32
.dwFlagsAndAttributes equ 36
.hTemplateFile equ 40

WriteFile 的函数结构为

HANDLE CreateFileA(
  [in]           LPCSTR                lpFileName, //8 bytes
  [in]           DWORD                 dwDesiredAccess, //4 bytes
  [in]           DWORD                 dwShareMode, //4 bytes
  [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, //8 bytes
  [in]           DWORD                 dwCreationDisposition, //4 bytes
  [in]           DWORD                 dwFlagsAndAttributes, //4 bytes
  [in, optional] HANDLE                hTemplateFile //8 bytes
);

我对WriteFile的猜测:因为在x86中调用函数时所有参数都会被压入堆栈,但在x64中它们发生了变化。前四个参数传递到寄存器。从第五个开始,它们将被推入堆栈。在 x86 中,hTemplateFile 将通过 esp + 40 访问,dwFlagsAndAttributes 将通过 esp + 36 访问。x64 程序集遵循此规则。

但是,对于 WriteFile,他们使用

.lpNumberOfBytesWritten equ 52
.lpOverlapped equ 0
.fileHandle equ 40

BOOL WriteFile(
  [in]                HANDLE       hFile,  //8 bytes
  [in]                LPCVOID      lpBuffer, //8 bytes
  [in]                DWORD        nNumberOfBytesToWrite, //4 bytes
  [out, optional]     LPDWORD      lpNumberOfBytesWritten, //8 bytes
  [in, out, optional] LPOVERLAPPED lpOverlapped  //8 bytes
);

我不知道他们是如何计算的。

与 ReadFile 相同,他们使用

.lpOverlapped2 equ 0
.lpNumberOfBytesRead equ 32
.lpBuffer equ 40

BOOL ReadFile(
  [in]                HANDLE       hFile,
  [out]               LPVOID       lpBuffer,
  [in]                DWORD        nNumberOfBytesToRead,
  [out, optional]     LPDWORD      lpNumberOfBytesRead,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);

代码参考:https://github.com/sonictk/asm_tutorial/blob/master/win_create_file.asm

我想知道当我们使用x64程序集进行Windows x64内存管理时,如何计算参数应该推送到的位置。

windows assembly memory-management 64-bit
1个回答
0
投票

在 64 位模式下将参数传输到 Windows 函数有点复杂。

  1. 确保 RSP 在
    CALL Function
    之前是 16 字节对齐的。
  2. 推送参数#last、#last-but-one、...#5.
  3. 使用 SUB RSP, 4*8
     创建
    阴影空间
  4. 分别加载参数#4、#3、#2、#1到寄存器R9、R8、RDX、RCX。
  5. 调用导入的函数。
  6. 恢复RSP。

在调用的函数内部(当

CALL function
被执行时),RSP不是16对齐的,事实上寄存器SPL的最低位是
1000b
并且RSP指向返回地址。
前四个参数在寄存器中可用,参数 #5 位于
[RSP+5*8]
,参数 #6 位于
[RSP+6*8]
等等。

无论参数指定为HANDLE、LPVOID还是DWORD,堆栈上每个对应的槽总是8字节宽。 x86 不允许在 64 位模式下推送 DWORD。另请参阅此示例(快速版本)

© www.soinside.com 2019 - 2024. All rights reserved.