任何使用标准 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
...方式,但这并没有改变任何事情
编辑:删除源代码和日志的所有图像并将其作为代码块粘贴到此处
是的。事实上,问题是因为我的堆栈没有对齐到 16 个字节,正如 RbMm 和 Peter Cordes 指出的那样。我完全忘记了程序的入口点也有它的返回地址在堆栈顶部,这导致分配 32 个字节是不够的。将
sub rsp, 32
和 add rsp, 32
更改为 sub rsp, 40
和 add rsp, 40
修复了它。
感谢您的帮助