You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win64 NASM调用CommandLineToArgvW出现段错误问题求助

Win64下NASM调用CommandLineToArgvW出现段错误的问题

在Win64环境下,使用NASM按照标准Windows调用约定调用CommandLineToArgvW函数时触发段错误,但功能完全等效的C程序运行正常。本人是NASM新手,怀疑问题出在调用约定的理解上,遵循的教程中定义的调用约定(栈上分配32字节shadow space,RCX为第一个参数,RDX为第二个,返回结果存于RAX等)对GetCommandLineW和printf均有效,尝试过栈传参的写法也无法解决问题。

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

NASM程序运行结果

...\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;
}

C程序运行结果

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

尝试过的其他写法(无效)

call GetCommandLineW

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

问题原因与解决方法

核心问题:栈对齐不符合Windows x64调用约定

Windows x64调用约定强制要求:调用任何函数前,RSP必须保持16字节对齐。

当main函数被启动代码调用时,call指令会将8字节的返回地址压入栈,此时RSP的地址是16n + 8(即8字节偏移,未对齐)。你的代码中仅执行sub rsp, 32分配shadow space,此时RSP的偏移为8 + 32 = 40,并非16的倍数,导致调用CommandLineToArgvW时栈未对齐,进而触发段错误。

修正方案

将main函数中的栈调整指令从sub rsp, 32改为sub rsp, 40,从add rsp, 32改为add rsp, 40。这样既分配了32字节的shadow space,又将RSP调整回16字节对齐状态(8 + 40 = 48,48是16的倍数,减去后RSP为16n +8 -48 =16(n-2),符合对齐要求)。

同时,CommandLineToArgvW的第二个参数是int*类型,你可以将.bss段中的argc: resq 1改为argc: resd 1(占用4字节,符合int类型大小),并将printf的格式符改为%u(匹配unsigned int),这样更严谨。

修正后的完整代码:

extern GetCommandLineW
extern CommandLineToArgvW
extern LocalFree
extern printf

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

section .bss
    argc: resd 1

section .text
global main

main:
    sub rsp, 40

    call GetCommandLineW

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

    mov rcx, rax
    call LocalFree

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

    add rsp, 40

    xor rax, rax
    ret

运行修正后的代码即可正常输出argc值,无段错误。


内容的提问来源于stack exchange,提问作者LoC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 05:50:55