使用VC++生成的汇编输出如何编译?

7

我有一个简单的C语言hello world程序,使用/FA编译它。结果,编译器也生成了相应的汇编列表。现在我想使用masm/link从生成的.asm汇编列表中组装一个可执行文件。

下面的命令行显示3个链接器错误:

\masm32\bin\ml /I"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include" /c /coff asm_test.asm
\masm32\bin\link /SUBSYSTEM:CONSOLE /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\lib" asm_test.obj

提示未将C运行时函数链接到先前生成的对象文件中:

asm_test.obj : error LNK2001: 未解析的外部符号 __security_check_cookie@4 asm_test.obj : error LNK2001: 未解析的外部符号 _printf LINK : error LNK2001: 未解析的外部符号 _wmainCRTStartup asm_test.exe : fatal error LNK1120: 3 个未解析的外部

这是生成的汇编清单。

; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00.30729.01 

    TITLE   c:\asm_test\asm_test\asm_test.cpp
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB OLDNAMES

PUBLIC  ??_C@_0O@OBPALAEI@hello?5world?$CB?6?$AA@   ; `string'
EXTRN   @__security_check_cookie@4:PROC
EXTRN   _printf:PROC
;   COMDAT ??_C@_0O@OBPALAEI@hello?5world?$CB?6?$AA@
CONST   SEGMENT
??_C@_0O@OBPALAEI@hello?5world?$CB?6?$AA@ DB 'hello world!', 0aH, 00H ; `string'
CONST   ENDS
PUBLIC  _wmain
; Function compile flags: /Ogtpy
;   COMDAT _wmain
_TEXT   SEGMENT
_argc$ = 8                      ; size = 4
_argv$ = 12                     ; size = 4
_wmain  PROC                        ; COMDAT
; File c:\users\octon\desktop\asm_test\asm_test\asm_test.cpp
; Line 21
    push    OFFSET ??_C@_0O@OBPALAEI@hello?5world?$CB?6?$AA@
    call    _printf
    add esp, 4
; Line 22
    xor eax, eax
; Line 23
    ret 0
_wmain  ENDP
_TEXT   ENDS
END

我正在使用最新的masm32版本(6.14.8444)。
更新:
如Cogwheel所建议的,我在asm源代码中包含了“INCLUDELIB msvcrt.lib”。程序编译成功并生成可执行文件,但链接器生成了一个警告:
msvcrt.lib(crtmanifestrtm.obj):警告LNK4044:未识别的选项“manifestdependency:type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'”;被忽略
当我启动可执行文件时,C运行时会生成以下错误:
运行时错误:R6034 应用程序尝试不正确地加载 C 运行库

你已经提供了库的路径,但是你没有列出任何你想链接到的库本身。虽然我不确定你需要链接到哪些库的名称(因此只能留下评论而不是答案)。 - Cogwheel
1
好的,它肯定与清单文件有关,但是我现在被卡住了。也许创建一个简单的纯 C++ 项目并查看链接器设置以获取线索? - Cogwheel
2个回答

2
我最近做了这件事。结果发现在MSVC2012中仍可以在32位模式下执行此操作,但我认为64位模式是无望的。
对于32位模式,请按照以下步骤进行:
创建一个空项目和源文件Source.cpp
 #include <stdio.h>
 int main() {
     printf("hello world\n");
     return 0;
 }
  1. 右键单击您的项目,选择“生成定制”并选择masm,如http://www.masm32.com/board/index.php?topic=9231.0所述
  2. 在C++/输出文件下选择汇编输出 /FA
  3. 以32位模式Release模式进行编译
  4. Source.asm文件加载到MSVC中以便查看。它还不能正常工作,需要做一些更改。
  5. 在C++/优化下关闭整个程序优化(删除/GL)。这会添加行INCLUDELIB MSVCRT
  6. 在链接器/高级设置中将最后一个选项“图像具有安全异常处理程序”设置为No (/SAFESEH:NO)
  7. 现在您应该有一个可以像Source.cpp文件一样执行相同操作的Source.asm文件。将Source.cpp从发布目录复制到与Source.cpp相同的目录中(这样在构建/清理时不会被删除)。
  8. Source.asm(作为现有文件)添加到源文件中,并从构建中删除Source.cpp
  9. 重新构建,您应该看到“Hello World”,而无需手动更改任何汇编行。

我已经使用这个方法来实现更复杂的功能。通常我会在一个单独的模块中进行操作,并在函数名上使用extern "C"来消除C++名称混淆。


0

移除 listing.inc 移除 security_check_cookie 引用 添加 INCLUDELIB MSVCRT ...et Robert est ton oncle!

另外你可以添加: EXTERN _getchar:PROC 并在 ret 前加上:call _getchar 这将在程序关闭前等待按键。

Honkjonk.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接