I am trying to call an x86 C function, printf
, in assembly, but there is a linking error: error LNK2019: unresolved external symbol _printf referenced in function _main
.
.model flat, C
.code
extern printf: proc
main proc
push offset msg
push offset fmt
call printf
ret
main endp
.data
msg db "Hello world!", 0
fmt db "%s", 0
end
How can I solve that problem?
I am trying to call an x86 C function, printf
, in assembly, but there is a linking error: error LNK2019: unresolved external symbol _printf referenced in function _main
.
.model flat, C
.code
extern printf: proc
main proc
push offset msg
push offset fmt
call printf
ret
main endp
.data
msg db "Hello world!", 0
fmt db "%s", 0
end
How can I solve that problem?
Share Improve this question edited Apr 2 at 2:46 Peter Cordes 367k49 gold badges717 silver badges979 bronze badges asked Apr 2 at 1:23 Lion KingLion King 33.9k26 gold badges90 silver badges157 bronze badges 2 |3 Answers
Reset to default 1here can be several ways. if want use existing libs - _printf
was in legacy_stdio_definitions.lib
but if use it need also link to legacy_stdio_wide_specifiers.lib
and ucrt.lib
, call __initterm
( or set entry point to _wmainCRTStartup
) complete code in this case can look like
.686
.model flat
extern _printf: PROC
extern __imp__exit: DWORD
extern __imp___initterm: DWORD
.code
ep proc
push offset __xc_z
push offset __xc_a
call __imp___initterm
add esp,8
push offset msg
push offset fmt
call _printf
add esp,8
push eax
call __imp__exit
ret
ep endp
CRT$XIA SEGMENT ALIAS(".CRT$XIA")
__xc_a DD 0
CRT$XIA ENDS
CRT$XIZ SEGMENT ALIAS(".CRT$XIZ")
__xc_z DD 0
CRT$XIZ ENDS
.const
msg db "Hello world!", 0
fmt db "%s", 0
end
(note that better use .const
section instead .data
here for constand data )
and link file with
link.exe /MAP /MERGE:.CRT=.rdata /SUBSYSTEM:CONSOLE /ENTRY:ep /LARGEADDRESSAWARE /DYNAMICBASE /MACHINE:X86 /SAFESEH:NO /OPT:REF /OPT:ICF /NODEFAULTLIB /EMITPOGOPHASEINFO /EMITVOLATILEMETADATA:NO /LIBPATH:"C:\lib\um\x86" /LIBPATH:"C:\msvc\lib\x86" /LIBPATH:"C:\lib\ucrt\x86" test.obj legacy_stdio_definitions.lib legacy_stdio_wide_specifiers.lib ucrt.lib
another way - build my self msvcrt.lib ( standard msvcrt.lib have no printf
despite it was exported by msvcrt.dll
and then use it ) minimal way
.686
.model flat
API MACRO name
name proc
name endp
ENDM
.code
API _printf
end
and msvcrt.def
:
EXPORTS
printf
build with
link.exe /DLL /NOENTRY:ep /LARGEADDRESSAWARE /DYNAMICBASE /MACHINE:X86 /SAFESEH:NO /OPT:REF /OPT:ICF /NODEFAULTLIB /EMITPOGOPHASEINFO /EMITVOLATILEMETADATA:NO /DEF:msvcrt.def msvcrt.obj
and than can use this
.686
.model flat
extern __imp__printf: DWORD
extern __imp__ExitProcess@4: DWORD
.code
ep proc
push offset msg
push offset fmt
call __imp__printf
add esp,8
push eax
call __imp__ExitProcess@4
ret
ep endp
.const
msg db "Hello world!", 0
fmt db "%s", 0
end
link with:
link.exe /MAP /SUBSYSTEM:CONSOLE /ENTRY:ep /LARGEADDRESSAWARE /DYNAMICBASE /MACHINE:X86 /SAFESEH:NO /OPT:REF /OPT:ICF /NODEFAULTLIB /EMITPOGOPHASEINFO /EMITVOLATILEMETADATA:NO /LIBPATH:"C:\lib\um\x86" /LIBPATH:"C:\msvc\lib\x86" /LIBPATH:"C:\lib\ucrt\x86" test2.obj msvcrt.lib kernel32.lib
(more general way auto build lib for dll - here)
32 bit code example:
.686p ;enable instructions
.xmm ;enable instructions
.model flat,c ;use C naming convention (stdcall is default)
; include C libraries
includelib msvcrtd
includelib oldnames
includelib legacy_stdio_definitions.lib ;for scanf, printf, ...
.data ;initialized data
pfstr db "Hello world!",0dh,0ah,0
.data? ;uinitialized data
.stack 4096 ;stack (optional, linker will default)
.code ;code
extrn printf:near
public main
main proc
push offset pfstr
call printf
add esp,4
xor eax,eax
ret
main endp
end
64 bit code example:
; include C libraries
includelib msvcrtd
includelib oldnames
includelib legacy_stdio_definitions.lib ;for scanf, printf, ...
.data
msg db "test",00dh,00ah,000h
.code
extern printf:near
main proc
sub rsp,32 ;caller allocates space for rcx,rcx,r8,r9
lea rcx,msg
call printf
xor eax,eax
add rsp,32
ret
main endp
end
If you're using Windows the main
the function is actually expected to be named _main
includelib legacy_stdio_definitions.lib
or add it to the libraries – Jester Commented Apr 2 at 1:25