在Visual Studio中从asm调用C标准库函数

时间:2015-11-15 14:53:25

标签: visual-studio assembly linker-errors masm

我在Visual Studio中创建的asm项目调用C函数时出现问题(Win10 x64,Visual Studio 2015)。项目由一个asm文件组成:

.586
.model flat, stdcall
option casemap:none
includelib msvcrt.lib

ExitProcess PROTO return:DWORD
extern printf:near

.data
text BYTE "Text", 0

.code
main PROC
    push offset text
    call printf
    add esp,4
    invoke ExitProcess,0
main ENDP
end main

当我构建项目时,链接器输出错误:

  

错误LNK2019未解析的外部符号_printf在中引用   function _main @ 0

链接器输出参数:

  

/ OUT:" C:\用户\苹果\文件\ SP_Lab7 \调试\ SP_Lab7_Demo.exe"   / MANIFEST:NO / NXCOMPAT   /PDB:"C:\Users\apple\Documents\SP_Lab7\Debug\SP_Lab7_Demo.pdb"   / DYNAMICBASE" kernel32.lib" " USER32.LIB" " GDI32.LIB" " winspool.lib"   " comdlg32.lib" " advapi32.lib" " SHELL32.LIB" " ole32.lib" " oleaut32.lib"   " UUID.LIB" " odbc32.lib" " odbccp32.lib" /机器:X86 / SAFESEH:没有   /增量:NO   /PGD:"C:\Users\apple\Documents\SP_Lab7\Debug\SP_Lab7_Demo.pgd"   / SUBSYSTEM:WINDOWS / MANIFESTUAC:" level =' asInvoker' uiAccess ='假'"   /ManifestFile:"Debug\SP_Lab7_Demo.exe.intermediate.manifest"   / ERRORREPORT:PROMPT / NOLOGO / TLBID:1

如果我评论call print,那么一切都正常执行(甚至是Windows API函数)。有没有办法从asm文件调用C函数而不创建包含<cstdio>的cpp文件? 有可能吗?

3 个答案:

答案 0 :(得分:9)

Microsoft在VS 2015中重构了大部分 C 运行时和库。某些函数不再从 C 库中导出(某些函数在 C中定义) 头文件)。 Microsoft有一些兼容性库,如 legacy_stdio_definitions.lib legacy_stdio_wide_specifiers.lib ,但您也可以选择使用较旧的Visual Studio 2013平台工具集和较旧的 C < / em> libraries。

更改平台工具集:下拉Project菜单;选择Properties...;转到Configuration Properties / General,然后将Platform Toolset更改为 Visual Studio 2013(v120)

答案 1 :(得分:7)

它似乎是&#39;可以使用Visual Studio 2015 Toolset进行一些修改。

  • 您需要将这些库添加到依赖项中: libcmt.lib libvcruntime.lib libucrt.lib legacy_stdio_definitions.lib 。或者,您可以使用includelib将这些库包含在程序集文件中。
  • 使用main
  • PROC C程序指定 C 调用约定
  • 在文件末尾(这很重要)请勿使用end main,仅使用end。不修复此问题可能会导致意外崩溃。
  • 虽然我们可以使用 ExitProcess 退出我们的应用程序,但我们也可以将返回代码放在 EAX 中并执行ret返回。 C 运行时调用我们的main函数,并在返回时为我们调用关闭代码。

代码可能如下所示:

.586
.model flat, stdcall
option casemap:none

includelib libcmt.lib
includelib libvcruntime.lib
includelib libucrt.lib
includelib legacy_stdio_definitions.lib

ExitProcess PROTO return:DWORD
extern printf:NEAR

.data
text BYTE "Text", 0

.code
main PROC C                    ; Specify "C" calling convention
    push offset text
    call printf
    add  esp, 4
;   invoke ExitProcess,0       ; Since the C library called main (this function)
                               ; we can set eax to 0 and use ret`to have
                               ; the C runtime close down and return our error
                               ; code instead of invoking ExitProcess
    mov eax, 0
    ret
main ENDP
end                            ; Use `end` on a line by itself
                               ; We don't want to use `end main` as that would
                               ; make this function our program entry point
                               ; effectively skipping by the C runtime initialization

答案 2 :(得分:1)

您可以调用C函数,但是您需要链接C库。具体如何完成将取决于您想要链接的C库。我建议找一个最小的C运行时,例如WCRT library

该库可能需要初始化,并且可能需要您在某处定义一堆缓冲区以便保存。

我建议您坚持使用Windows API,而不是遇到所有这些麻烦,在您的情况下使用WriteConsole函数。