最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

windows - How can I call printf function correctly from assembly? - Stack Overflow

programmeradmin3浏览0评论

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
  • 1 includelib legacy_stdio_definitions.lib or add it to the libraries – Jester Commented Apr 2 at 1:25
  • @Jester: Writing that line gives me many linking errors (20 errors). – Lion King Commented Apr 2 at 1:32
Add a comment  | 

3 Answers 3

Reset to default 1

here 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

发布评论

评论列表(0)

  1. 暂无评论