Call C standard library function from asm in Visual Studio
Asked Answered
R

3

7

I have a problem with calling C function from asm project created in visual studio (Win10 x64, Visual Studio 2015). Project consist of one asm file:

.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

When I build project, linker outputs the error:

Error LNK2019 unresolved external symbol _printf referenced in function _main@0

Linker output parameters:

/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

If I comment call print, then everything executes normally (even Windows API function). Is there any way to call C function from asm file without creating cpp file that includes <cstdio>? Is it possible to do?

Radioscope answered 15/11, 2015 at 14:53 Comment(4)
A work around is to set the platform toolset to VS 2013. To do that pull down the Project menu select properties... . Go to Configuration Properties/General, and change Platform Toolset to Visual Studio 2013 (v120)Lyrebird
@MichaelPetch It's really working, thank youRadioscope
Microsoft refactored much of the C runtime. Some functions are no longer exported in the library (some are defined in a C header file). MS has some compatibility libraries legacy_stdio_definitions.lib and legacy_stdio_wide_specifiers.lib , but I have yet to get printf to work with them, so I fall back to VS 2013 toolset. There may be another work around for it, but I haven't seen it.Lyrebird
I have added a new answer with a solution you might be interested in trying. It uses the Visual Studio 2015 toolset. You will have to switch from Visual Studio 2013 toolset to 2015 before trying it. I am very cruious if this works for you.Lyrebird
L
12

Microsoft refactored much of the C runtime and libraries in VS 2015. Some functions are no longer exported from the C library (some are defined in a C header file). Microsoft has some compatibility libraries like legacy_stdio_definitions.lib and legacy_stdio_wide_specifiers.lib, but you can also choose to use the older Visual Studio 2013 platform toolset with the older C libraries.

To change the platform toolset: pull down the Project menu; select Properties...; go to Configuration Properties/General, and change Platform Toolset to Visual Studio 2013 (v120)

Lyrebird answered 15/11, 2015 at 20:24 Comment(0)
L
11

It appears that it' possible to use the Visual Studio 2015 Toolset with a few modifications.

  • You'll need to add these libraries to your dependencies: libcmt.lib, libvcruntime.lib, libucrt.lib, legacy_stdio_definitions.lib. Alternatively you could use includelib to include these libraries in your assembly file.
  • Specify C calling convention for your main procedure using PROC C
  • At the end of your file (and this is important) do not use end main, use end only. Not fixing this may cause unexpected crashes.
  • Although we can use ExitProcess to exit our application, we can also put the return code in EAX and do a ret to return. The C runtime calls our main function, and will call the shutdown code for us upon returning.

The code could look like:

.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
Lyrebird answered 15/11, 2015 at 21:56 Comment(1)
It seems that just includelib legacy_stdio_definitions.lib is sufficient in visual studio 2022. learn.microsoft.com/en-us/cpp/porting/…Zelaya
S
1

You can call C functions, but then you'll need to link with the C library. Exactly how that is done will depend on what C library you want to link with. I'd suggest finding a minimal C runtime, such as the WCRT library.

The library will probably require initialization, and might require you to define a bunch of buffers somewhere for its book keeping.

Instead of going to all this trouble, I'd suggest you just stick to Windows API, and in your case use the WriteConsole function.

Suh answered 15/11, 2015 at 14:57 Comment(1)
thanks for pointing to use WinAPI functions, because the main function that I wanted was strcspn and similar function StrSpn is available. But I still don't understand, why includelib msvcrt.lib don't load C library.Radioscope

© 2022 - 2024 — McMap. All rights reserved.