【问题标题】:Running a Win32 app written in NASM results in 'This app cant run on your pc' error运行以 NASM 编写的 Win32 应用程序会导致“此应用程序无法在您的电脑上运行”错误
【发布时间】:2021-07-22 04:11:18
【问题描述】:

我开始在 Windows 上学习 x86 汇编。我正在学习 32 位 x86 汇编。我使用nasmld 来编译我的程序。我使用mingw32-make makefile 作为我的构建系统。我假设 ld 包含在 MinGW 中,但我不确定。我只知道它已经在我的电脑上。

我想编译一个非常简单的程序,以确保一切正常,当然,事实并非如此。运行我的可执行文件时,出现一个巨大的蓝色框,上面写着“此应用无法在您的电脑上运行”,关闭通知后,Access is denied 字样打印到我的终端上。

这是我的程序:

global _main

_main:
  mov eax, 1
  ret

这是我的makefile:

main: learn.asm
    nasm -f win32 learn.asm -o learn.o
    ld learn.o -o learn.exe

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 你确定它不只是崩溃,因为它应该?您需要终止程序。在windows上,我相信你可以简单地ret
  • 您能提供代码作为答案吗?
  • 只需在mov eax, 1 之后添加ret
  • @Jester 不起作用 :(
  • 您的环境是否有file 命令?如果你运行file learn.exe,它会说明什么?

标签: assembly x86 mingw nasm ld


【解决方案1】:

最初您的问题是关于使用_start 作为入口点。您链接的方式不包括 C 运行时。

对于某些版本的 Windows,如果在某些情况下没有 .rdata(只读数据)部分,则在与 MinGW LD 链接时可能会收到错误 This app cant run on your pc。一种情况似乎是带有 .idata 部分 (import directory) 的可执行文件没有被标头引用并且不包含 .rdata 部分。当 MinGW LD 链接器在不使用 C 运行时时从您的代码创建可执行文件时,似乎就是这种情况。要解决此问题,请添加一个包含至少一个字节数据的 .rdata 部分。这应该有效:

global _start

section .rdata
db 0

section .text
_start:
    mov eax, 1
    ret 

您还需要将代码放在.text 部分,否则您可能会遇到其他问题。然后你可以组装和链接:

nasm -fwin32 learn.asm -o learn.obj
ld -o learn.obj -o learn.exe

如果您想使用 _main 并打算使用 C 运行时,那么您不需要创建 .rdata 部分,但是您可以组装和链接:

nasm -fwin32 learn.asm -o learn.obj
gcc -m32 learn.obj -o learn.exe

我对链接的建议

或者,您可以使用与 LD 不同的链接器。 GoLink 特别应该从您使用的代码生成可执行文件。您可以这样创建一个带有_start 入口点的 Win32 控制台应用程序:

nasm -fwin32 learn.asm -o learn.obj
golink /console /entry _start learn.obj

GoLink 将生成一个可执行文件,其中包含适当的标题和部分,Windows 运行应该没有问题,而无需添加 .rdata 部分。

如果你安装了 MSVC/C++,你也可以使用Microsoft linker:

nasm -fwin32 learn.asm -o learn.obj
link learn.obj /entry:start /subsystem:console

【讨论】:

  • 背景似乎是“.idata”部分(顺便说一下,不需要命名为“.idata”):如果以OP的方式使用ld,没有使用启动代码,所以入口点是_main(或_start,如果函数以这种方式命名)。因为程序必须调用操作系统(至少对于exiting)并且调用 Windows 内核的唯一可靠(和允许)的可能性是使用 DLL,所以程序必须使用 DLL。在 Windows 和 Linux 中都不允许使用 ret 从入口点代码返回。
  • @MartinRosenau :如果主线程返回 ret,当且仅当主线程是唯一一个处于活动状态的线程时,Win32 进程才能终止。
  • 如果 Windows 加载程序碰巧创建了多个线程,那么ret 可能不会导致进程退出。避免该问题的一般经验法则是调用 ExitProcess。我自己不是这样使用ret的人。
  • 有趣。但是,我观察到如果导入部分中没有列出 DLL 文件,许多 Windows 版本会拒绝加载可执行文件。如果 EXE 文件不包含任何导入,Windows Vista 或 Windows 7(我不确定)根本不执行任何操作:代码不会执行,但程序会立即返回。您可以通过编写无限循环或一些导致异常的代码来验证这一点。我可以想象 Windows 10 打印问题中报告的错误消息,而不是“默默地”什么都不做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 2016-07-02
  • 1970-01-01
  • 1970-01-01
  • 2014-09-18
相关资源
最近更新 更多