Reputation: 1118
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;
}
Upvotes: 1
Views: 7061
Reputation: 11
I just worked this one out starting with the tutorial/console/demo1 that came with MASM for x86. It says to compile using the console option which is in the drop down 'Project' menu. It works good, and I think it near the minimum to get started:
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\windows.inc ; always first
include \masm32\macros\macros.asm ; MASM support macros
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
.code
start:
print chr$("Hey, this actually works.",13,10)
mov eax, 0
mov ebx, 0
printf("%d\t %d\t\n", eax, ebx);
mov eax, 100
mov ebx, 100
printf("%d\t %d\t\n", eax, ebx);
mov eax, 100
mov ebx, 100
add eax, ebx
printf("%d\t %d\t\n", eax, ebx)
exit
end start
I am using printf here to print from the registers. I found out from this that printf itself effects the registers EAX, ECX, and EDX, as the add
will not give a proper result if eax isn't reloaded before the printf statement passing it. (You can also see this when single-stepping in a debugger and watching register values change).
This will print from the eax and ebx registers, but you can print whatever you want following the C syntax. The important thing is to include these two lines:
include \masm32\include\msvcrt.inc
includelib \masm32\lib\msvcrt.lib
You need to include both of them; the .inc
defines the printf()
C-style macro, so that syntax will not work without it.
rkhb's answer on this question shows how you can declare printf
manually and call it with standard MASM INVOKE
like any other function, or even pushing args yourself and doing a call printf
without MASM doing any magic. In that case you just need the .lib
.
Upvotes: 1
Reputation: 14409
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
Upvotes: 2