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

Sun*_*ise 6 x86 assembly masm linker-errors visual-studio

我在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
Run Code Online (Sandbox Code Playgroud)

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

错误LNK2019未解析的函数_main @ 0中引用的外部符号_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函数而不创建包含的cpp文件<cstdio>?有可能吗?

Mic*_*tch 9

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

要更改平台工具集:请下拉Project菜单; 选择Properties...; 转到Configuration Properties/ General,然后切换Platform ToolsetVisual Studio 2013(v120)


Mic*_*tch 7

看起来可以使用Visual Studio 2015 Toolset进行一些修改.

  • 您需要将这些库添加到依赖项中:libcmt.lib,libvcruntime.lib,libucrt.lib,legacy_stdio_definitions.lib.或者,您可以使用includelib在程序集文件中包含这些库.
  • 指定Ç调用约定的main使用方法PROC C
  • 在文件的末尾(这很重要)不要使用end main,end仅使用.不修复此问题可能会导致意外崩溃.
  • 虽然我们可以使用ExitProcess来退出我们的应用程序,但我们也可以将返回代码放在EAX中并执行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
Run Code Online (Sandbox Code Playgroud)