Search code examples
cassemblymasm

How to call printf from a C function that I call in the MASM assembler?


I have a C file called C.c and for now in that file I have one function that compares two numbers and saves the greater number to the register eax.

I need help with creating the second function that will call printf inside and print some text. How to add support for printf in C that I can call from MASM assembler?

My masm file:

    TITLE MASM Template (main.asm)
.386
.model FLAT
.stack 4096

WriteString PROTO stdcall
ReadChar PROTO stdcall
Crlf PROTO stdcall
ExitProcess PROTO stdcall:DWORD
greater PROTO C :DWORD, :DWORD


.data
PorukaZaIspis db "Poruka za ispis", 0

.code
_main PROC

push 8
push 3
call greater


call Crlf
mov edx, OFFSET PorukaZaIspis
call WriteString
call ReadChar
Invoke ExitProcess, 0
_main ENDP
END _main

END

My C.c file:

int greater(int a, int b) {
if ( a > b)
return a;
else 
return b;
}

Solution

  • You need to link to an appropriate library (e.g. msvcrt.lib) and you need to know the exported names of the functions. To detect the names I use dumbinGUI.

    The calling conventions of C-functions is called "cdecl". The arguments are pushed onto the stack and the stack have to be adjusted after the call. You can let MASM do that job by using INVOKE, if you declare the function as PROTO C.

    Example:

    test.asm:

    .686
    .model FLAT
    
    INCLUDELIB msvcrt.lib
    printf PROTO C, :VARARG
    exit PROTO C, :DWORD
    
    ; Functions in C.c:
    greater PROTO C :DWORD, :DWORD          ; Declaration of greater (int,int)
    hello PROTO C                           ; Declaration of hello (void)
    
    .data
    fmt db "%s %u", 10, 0                   ; '10': printf of msvcrt.dll doesn't accept "\n"
    PorukaZaIspis db "Message from ASM: ", 0
    
    .code
    _main PROC
        invoke greater, 8, 3
        call output                         ; "Message from ASM ..."
        invoke hello                        ; "Message from C ..."
        invoke exit, 0
    _main ENDP
    
    output PROC                             ; ARG: EAX
        invoke printf, OFFSET fmt, OFFSET PorukaZaIspis, eax
        ret
    output ENDP
    
    END _main
    

    Let's add an output function to the C file:

    C.c:

    #include <stdio.h>
    
    void hello ()
    {
        puts ("Message from C: hello");
    }
    
    int greater(int a, int b)
    {
        if ( a > b)
            return a;
        else
            return b;
    }
    

    Play with following batch file:

    @ECHO OFF
    SET VS_PATH=<Full\Path\to\Visual Studio\e.g.\C:\Program Files\Microsoft Visual Studio 10.0>
    
    SET PATH=%VS_PATH%\VC\bin
    SET LIB=%VS_PATH%\VC\lib
    SET INCLUDE=%VS_PATH%\VC\include
    
    SET CALLER=test.asm
    SET CALLEE=C.c
    SET TARGET=test.exe
    
    echo cl_first
    del %TARGET%
    call :cl_first %CALLER% %CALLEE% %TARGET%
    if exist %TARGET% %TARGET%
    
    echo.
    echo ml_first
    del %TARGET%
    call :ml_first %CALLER% %CALLEE% %TARGET%
    if exist %TARGET% %TARGET%
    
    goto :eof
    
    :cl_first
    cl /nologo /c %2
    ml /nologo /Fe%3 %1 %~n2.obj /link /nologo
    goto :eof
    
    :ml_first
    ml /nologo /c %1
    cl /nologo /Fe%3 %~n1.obj %~n2.c /link /nologo
    goto :eof