在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.lib和legacy_stdio_wide_specifiers.lib ,但您也可以select使用旧版Visual Studio 2013平台工具集与较旧的C库。
要更改平台工具集:下拉Project
菜单; selectProperties...
; 转到Configuration Properties
/ General
,并将Platform Toolset
更改为Visual Studio 2013(v120)
看起来可以通过一些修改来使用Visual Studio 2015工具集。
- 您需要将这些库添加到您的依赖项中: libcmt.lib , libvcruntime.lib , libucrt.lib , legacy_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函数。