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

我在Visual Studio中创build的asm项目(Win10 x64,Visual Studio 2015)中调用C函数时遇到问题。 项目由一个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 

当我build立项目,链接器输出错误:

在函数_main @ 0中引用LNK2019未parsing的外部符号_printf时出错

链接器输出参数:

/OUT:"C:\Users\apple\Documents\SP_Lab7\Debug\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”/ MACHINE:X86 / SAFESEH:NO / INCREMENTAL:NO /PGD:"C:\Users\apple\Documents\SP_Lab7\Debug\SP_Lab7_Demo.pgd“/ SUBSYSTEM:WINDOWS / MANIFESTUAC: “level ='asInvoker'uiAccess ='false'”/ManifestFile:"Debug\SP_Lab7_Demo.exe.intermediate.manifest“/ ERRORREPORT:PROMPT / NOLOGO / TLBID:1

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

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

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

看起来可以通过一些修改来使用Visual Studio 2015工具集。

  • 您需要将这些库添加到您的依赖项中: libcmt.liblibvcruntime.liblibucrt.liblegacy_stdio_definitions.lib 。 或者,您可以使用includelib将这些库包含在您的程序集文件中。
  • 使用PROC C main程序指定C调用约定
  • 在你的文件结尾(这很重要)不要使用end main ,只使用end 。 不修复这可能会导致意外的崩溃。
  • 虽然我们可以使用ExitProcess来退出我们的应用程序,但是我们也可以把返回代码放在EAX中,然后做一个ret返回。 C运行库调用我们的main函数,并在返回时调用我们的closures代码。

代码可能如下所示:

 .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 

你可以调用C函数,但是你需要链接到C库。 到底如何完成取决于你想要链接的C库。 我build议找一个最小的C运行库,比如WCRT库 。

该库可能需要初始化,并可能需要您在某处定义一堆缓冲区来存储它。

而不是所有这些麻烦,我build议你只是坚持Windows API,并在你的情况下使用WriteConsole函数。