提问人:Sunrise 提问时间:11/15/2015 最后编辑:Michael PetchSunrise 更新时间:9/11/2019 访问量:7064
在 Visual Studio 中从 asm 调用 C 标准库函数
Call C standard library function from asm in Visual Studio
问:
我从Visual Studio(Win10 x64,Visual Studio 2015)中创建的asm项目调用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
当我构建项目时,链接器输出错误:
错误LNK2019 中引用的未解析的外部符号_printf 功能_main@0
链接器输出参数:
/OUT:“C:\Users\apple\Documents\SP_Lab7\Debug\SP_Lab7_Demo.exe” /清单:否 /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:否 /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” /错误报告:提示 /NOLOGO /TLBID:1
如果我注释,那么一切都正常执行(甚至是 Windows API 函数)。有没有办法从 asm 文件调用 C 函数而不创建包含的 cpp 文件?
可以做到吗?call print
<cstdio>
答:
您可以调用 C 函数,但随后需要与 C 库链接。具体如何完成将取决于您要链接的 C 库。我建议找到一个最小的 C 运行时,例如 WCRT 库。
该库可能需要初始化,并且可能需要您在某处定义一堆缓冲区来保存其簿记。
与其麻烦,我建议你坚持使用 Windows API,在你的情况下使用 WriteConsole 函数。
评论
strcspn
StrSpn
includelib msvcrt.lib
Microsoft 在 VS 2015 中重构了大部分 C 运行时和库。某些函数不再从 C 库导出(某些函数在 C 头文件中定义)。Microsoft 有一些兼容性库,如 legacy_stdio_definitions.lib 和 legacy_stdio_wide_specifiers.lib,但你也可以选择将较旧的 Visual Studio 2013 平台工具集与较旧的 C 库一起使用。
要更改平台工具集:下拉菜单;选择;转到 /,然后更改为 Visual Studio 2013 (v120)Project
Properties...
Configuration Properties
General
Platform Toolset
似乎可以通过一些修改来使用 Visual Studio 2015 工具集。
- 您需要将这些库添加到依赖项中:libcmt.lib、libvcruntime.lib、libucrt.lib legacy_stdio_definitions.lib。 或者,您可以使用这些库包含在程序集文件中。
includelib
- 使用指定过程的 C 调用约定
main
PROC C
- 在文件末尾(这很重要)不要使用 ,仅使用。如果不解决此问题,可能会导致意外崩溃。
end main
end
- 虽然我们可以使用 ExitProcess 退出我们的应用程序,但我们也可以将返回代码放在 EAX 中并执行 return 操作。C 运行时调用我们的函数,并在返回时为我们调用关闭代码。
ret
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
评论
includelib legacy_stdio_definitions.lib
评论
platform toolset
Project
properties...
Configuration Properties
General
Platform Toolset