Win64 NASM:CommandLineArgvW 中的段错误

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

任何使用标准 Windows 调用约定在 NASM 中调用 CommandLineToArgvW 的尝试都会导致出现段错误。这个 C 程序的等价物工作得很好

NASM源代码:

extern GetCommandLineW
extern CommandLineToArgvW
extern LocalFree
extern printf

section .rodata
    argc_format: db '%llu', 0

section .bss
    argc: resq 1

section .text
global main

main:
    sub rsp, 32

    call GetCommandLineW

    mov rcx, rax
    lea rdx, [rel argc]
    call CommandLineToArgvW;

    mov rcx, rax
    call LocalFree

    lea rcx, [rel argc_format]
    mov rdx, [rel argc]
    call printf

    add rsp, 32

    xor rax, rax
    ret

运行结果:

...\main_nasm>main_nasm

...\main_nasm>echo %ERRORLEVEL%
-1073741819

GDB 概览:

Reading symbols from main_nasm...
(gdb) break main
Breakpoint 1 at 0x140001540
(gdb) run
Starting program: ...\main_nasm.exe
[New Thread 10868.0x4ed0]
[New Thread 10868.0x3adc]
[New Thread 10868.0x479c]

Thread 1 hit Breakpoint 1, 0x00007ff6a6b71540 in main ()
(gdb) next
Single stepping until exit from function main,
which has no line number information.
0x00007ff6a6b7157c in GetCommandLineW ()
(gdb) next
Single stepping until exit from function GetCommandLineW,
which has no line number information.
0x00007ffac901f6d0 in KERNEL32!GetCommandLineW () from C:\Windows\System32\kernel32.dll
(gdb) next
Single stepping until exit from function KERNEL32!GetCommandLineW,
which has no line number information.
0x00007ffac8d00fd0 in KERNELBASE!GetCommandLineW () from C:\Windows\System32\KernelBase.dll
(gdb) next
Single stepping until exit from function KERNELBASE!GetCommandLineW,
which has no line number information.
0x00007ff6a6b71549 in main ()
(gdb) next
Single stepping until exit from function main,
which has no line number information.

Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ffac9da4220 in StrStrW () from C:\Windows\System32\shell32.dll
(gdb) next
Single stepping until exit from function StrStrW,
which has no line number information.

Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ffac9da4220 in StrStrW () from C:\Windows\System32\shell32.dll
(gdb) next
Single stepping until exit from function StrStrW,
which has no line number information.
[Thread 10868.0x479c exited with code 3221225477]
[Thread 10868.0x4ed0 exited with code 3221225477]
[Thread 10868.0x3adc exited with code 3221225477]

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.

C源代码:

#include <stdio.h>
#include <Windows.h>

int main()
{
    int argc = 0;
    LocalFree(CommandLineToArgvW(GetCommandLineW(), &argc));

    printf("%llu", argc);

    return 0;
}

运行结果:

...\main_c>main_c
1
...\main_c>echo %ERRORLEVEL%
0

坦率地说,我对 NASM 还很陌生,我对调用约定的理解很可能是错误,但我遵循的教程按照我使用它的方式定义了它(在堆栈上分配 32 个字节,rcx - 第一个参数,rdx - 第二个,r8 - 第三个,r9 - 第四个,其他所有 - 在堆栈上,偏移量为 32,返回结果 - rax)。此外,适用于 GetCommandLineW 和 printf

我尝试实施它

call GetCommandLineW

lea rbx, [rel argc]
push rbx
push rax
call CommandLineToArgvW

...方式,但这并没有改变任何事情

编辑:删除源代码和日志的所有图像并将其作为代码块粘贴到此处

assembly winapi x86 nasm command-line-arguments
1个回答
0
投票

是的。事实上,问题是因为我的堆栈没有对齐到 16 个字节,正如 RbMmPeter Cordes 指出的那样。我完全忘记了程序的入口点也有它的返回地址在堆栈顶部,这导致分配 32 个字节是不够的。将

sub rsp, 32
add rsp, 32
更改为
sub rsp, 40
add rsp, 40
修复了它。

感谢您的帮助

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