【问题标题】:How to compile a Hello World assembly on Windows?如何在 Windows 上编译 Hello World 程序集?
【发布时间】:2021-12-07 14:54:23
【问题描述】:

有这么简单的assemblyWin 32程序:

.386
.model flat, stdcall
option casemap :none

EXTERN printf :PROC ; declare printf

.data
    HelloWorld db "Hello Wolrd!:-)", 0

.code
start:
  sub esp, 4
  push offset HelloWorld
  call printf
  add esp, 4
  ret
end start

我可以通过以下方式成功编译它:

ml.exe /c HelloWorld.asm

但是在链接它时遇到问题。当我使用时:

link HelloWorld.obj libcmt.lib

我收到一个错误:

unresolved external symbol _main called in _mainCRTStartup

为了成功链接程序以运行它,我需要更改/更正什么?

附言

请不要告诉我只使用nasm。我想使用我的 MSVC 中的 mllink

【问题讨论】:

  • 不应该是ml.exe /c /coff HelloWorld.asm, link /SUBSYSTEM:CONSOLE HelloWorld.obj libcmt.lib 吗?
  • @Michael 我已经尝试过你的建议,但仍然有相同的链接器错误。:-(..
  • 没有人会告诉你使用 NASM;它无法汇编这个使用 MASM 语法/指令的文件。而且 NASM 只是一个汇编器,反正不附带链接器。

标签: windows visual-studio assembly masm


【解决方案1】:

经过一些小的调整,现在可以正确构建。

.386    
.model flat, c
option casemap :none

includelib libcmt.lib
includelib legacy_stdio_definitions.lib

EXTERN printf :PROC ; declare printf

.data
    HelloWorld db "Hello World!:-)", 0

.code
main PROC
  push offset HelloWorld
  call printf
  add esp, 4
  ret
main ENDP
END

主要的修改是

  • .model flat, c 将过程的调用约定设置为 C。
    如果您决定将 .model 保持不变,stdcall 将需要进行这些更改。

替换

EXTERN printf :PROC

main PROC 

printf PROTO NEAR C,:DWORD

main PROC NEAR C    
  • 包括 libcmt.liblegacy_stdio_definitions.lib,它们将本地 C-Runtime 启动静态链接到您的代码中。

  • 将入口点从 start 更改为 ma​​in。在 C-Runtime 库 (CRT) libcmt.lib 中有一个入口点 (_mainCRTStartup),它执行一些初始化任务,然后将控制权交给您的应用程序 ma​​in 的入口点。您可以更改默认入口点,但通常您希望 CRT 入口点自动为您进行初始化的便利。

  • 删除了第一个 sub esp,4,所以剩下的一个 push 由 add esp,4 平衡,所以 ret 运行时 ESP 指向返回地址。

要构建,请打开 Windows 命令提示符并运行:

"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars32.bat"

设置 MSVC 环境初始化为:'x86'

接下来,运行这些 MASM 命令

ml.exe /c /coff HelloWorld.asm

link.exe /SUBSYSTEM:console HelloWorld.obj

程序显示

你好世界!:-)

【讨论】:

  • 你应该提到你改变的东西,比如main而不是start,并删除第一个sub esp,4,所以剩下的一个推送被add esp,4平衡,所以ESP指向在ret 运行时的返回地址。
  • @vengy Thx 朋友,它终于可以工作了!:-) 但我收到一个链接器警告,说 .CRT 部分与具有不同属性的 .data 部分合并...这是什么意思?纠正这个?
  • 快速修复是在 x86 中添加 /MERGE 链接器选项以将 .CRT 部分(只读)与 .rdata(只读)部分合并:link.exe /SUBSYSTEM:console /MERGE :.CRT=.rdata HelloWorld.obj
【解决方案2】:

您的错误消息说它找不到导出的符号(即函数)“_main”。我希望将您的 start 函数重命名为 _main 会使其编译。

【讨论】:

  • 我已将start 重命名为_main,甚至还尝试了_mainCRTStartup,但仍然没有运气......
  • @darek_911:也许可以试试叫它main;我想我已经读过 MASM 可以选择使用前导 _ 为您装饰名称,具体取决于某些指令或选项。但是,是的,start(以及缺少 _main 符号)当然是个问题,可能是 问题。
猜你喜欢
  • 2014-05-17
  • 2014-08-26
  • 1970-01-01
  • 2023-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
相关资源
最近更新 更多