News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

linking c function with masm caller

Started by allynm, January 20, 2010, 07:00:43 PM

Previous topic - Next topic

allynm

Hi folks -

This is driving me nuts because I solved it once 9 months ago, and can't find my own solution.

Here's what I'm trying to do:  Call a subroutine that adds two integers and is written in C.  The caller is a simple little MASM proc.

Here's the C subroutine:


extern int summer (int x, int y)
{
x = x + y
return x ;
}


The MASM caller looks like this:


include \masm32\include\masm32rt.inc

summer PROTO :DWORD, :DWORD

.data
int1 DWORD 5
int2 DWORD 7
fmt db "%d", 0
.code

start:

INVOKE summer, int1, int2
INVOKE crt_printf, ADDR fmt, eax
INVOKE ExitProcess, NULL

end start



I get an error message saying that 'LIBCMT.lib" isn't found.

As I say it's making me crazy.  I seem to recall that I needed to decorate the c code with something more than just "extern". 

Thanks, Mark Allyn

Vortex

The line x = x + y is missing a semi-colon :


int summer (int x, int y)
{
    x = x + y ;
    return x ;
}



include \masm32\include\masm32rt.inc

; masm32rt.inc sets the default calling convention to STDCALL

summer PROTO C :DWORD,:DWORD

.data

int1    dd 5
int2    dd 7
fmt     db "%d", 0

.code

start:

    invoke summer,int1,int2
    invoke crt_printf,ADDR fmt,eax
    invoke ExitProcess,0

END start


Project built with Visual Studio 2010 Pro Beta 1 compiler :


set PATH=D:\VS2010b\bin;%PATH%

SET INCLUDE=D:\VS2010b\include;D:\VS2010bSDK\Include

SET LIB=D:\VS2010b\lib;D:\VS2010bSDK\lib

cl /c /Oty2 /Zl /Gs /GS- summer.c

\masm32\bin\ml /c /coff test.asm
\masm32\bin\polink /SUBSYSTEM:CONSOLE test.obj summer.obj

allynm

Hi Vortex-

I found the missing semi-colon and fixed that.  Then I got into a major slug fest with the cl command.  I used your switches.  Finally I got it to work.  I am using VC 9.0, not 10.0 so it didn't recognize the Oty2 switch, but it turns out that that wasn't crucial.

What was crucial for me was that I had to use the command line that was part of the VC package, the one that comes up when you use the "tools" drop-down, in order to get an obj file for the subroutine that would link.  If I tried to use the "ordinary" command line, then I got a message saying that there was a missing DLL. 

The program(s) do link and run, but there is something seriously deficient in my understanding of the situation.  In order to get the C subroutine to compile into a linkable obj I have to stick the C code into a file within the VC directory of my download of VC 9.0.  If I use the cl command and your switches to do the compilation, I get a usable obj file.  I then have to copy the obj file into the MASM directory and do the usual link with the calling asm obj file.  Otherwise, I get the error message I mentioned.  Doesn't make sense.  It's ugly, and it's probably my fault it's ugly.

HOWEVER, thanks for helping me get as far as I have gotten.

Mark

Vortex

Hi Mark,

Did you set correctly the environment variable PATH to reflect the path to the compiler?

allynm

Hi Vortex-

You are probably onto the way to fix the problem.  When I looked at your code, I wasn't sure how to deal with the fact that I am not using VS 2010.  I am using Visual Express 9.0 and the assocaited libraries that came with that distribution.  Wasn't sure how to do the  "set include" and other sets.  Perhaps you could help me with this?

Maybe it is as simple as replacing all the references in your lines to "2010" with "2009"?  Somehow that seems to easy...

Thanks,
Mark

dedndave

for old C procs, the caller was responsible for balancing the stack
i think you are compelled to use STDCALL if you want to use API functions
i dunno - i have not written anything C-ish for years - lol
i have used a few C functions from msvcrtlib that require the stack to be balanced

        .MODEL  flat,stdcall

        mov     StackVal,esp
        INVOKE  EmptyCProc,eax,eax
        cmp     esp,StackVal
        jz      ExitMain

        print   chr$('Stack is not Balanced'),13,10

ExitMain:
        exit

GregL

Just remember INVOKE will balance the stack for you when calling C functions.

allynm

Hi to Vortex, Dave, and others

I obviously do not know what I'm doing and it's embarrassing.   I don't understand this Set Path, SEt Include stuff. 

If I compile the original c program snippet I posted using the command line from my distribution of Visual Express, and using also the switches that Vortex suggested, the code compiles.  If I MOVE the compiled obj file for the function to my MASM directory from its VS directory and then use polink to do the linking, the whole thing links and runs perfectly.

What I can't get a grasp of is how to avoid MOVing the obj file from one directory to the other.  Obviously I can write a BAT that will automate this, but it's sort of ugly, isn't it.  My problem is my grossly inadequate grasp of how set the environment ( and then reset it to its original state) in order to do something like what Vortex is suggesting above.

The reason I was trying to do any of this stuff was because I had a decent routine in C that prints stuff, but I don't want to rewrite it into MASM32...it's a ton of work, as you know. 


Thanks,

Mark Allyn

donkey

Quote from: Greg Lyon on January 21, 2010, 04:29:05 AM
Just remember INVOKE will balance the stack for you when calling C functions.


Only if the PROTO declaration is correct (in this case it was not) otherwise it will default to STDCALL if you use the standard MASM32 .MODEL directive. If you are calling your own function you have to make sure that [langtype] in the function declaration or .MODEL directive is set to C. If you set it in the .MODEL directive you will have to explicitly set STDCALL in other PROTO declarations. Also note that for 64 bit programming all calls are FASTCALL, including those that formerly were C calls in 32 bit, a thing to keep in mind when translating code.

http://support.microsoft.com/kb/73407
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

GregL

Quote from: DonkeyOnly if the PROTO declaration is correct (in this case it was not) ...

Good point.  I always use PROTO C for C functions.


Quote from: DonkeyAlso note that for 64 bit programming all calls are FASTCALL, including those that formerly were C calls in 32 bit, a thing to keep in mind when translating code.

Yes, it took a while to get that one to sink in.  :bg


Vortex

Hi Mark,

I installed VC++ 9.0 Express Edition and edited the batch file to point this environment :


set PATH=C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE;C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN;%PATH%

SET INCLUDE="C:\Program Files\Microsoft Visual Studio 9.0\VC\include";"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include"

REM SET LIB="C:\Program Files\Microsoft Visual Studio 9.0\VC\lib";"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib"

cl /c /Zl /Gs /GS- summer.c

\masm32\bin\ml /c /coff test.asm
\masm32\bin\polink /SUBSYSTEM:CONSOLE test.obj summer.obj


Have a look at C:\Program Files\Microsoft Visual Studio 9\Common7\Tools\vsvars32.bat to see how the environmet variables are set by the VC++ Express installation.

allynm

Hi everyone -

I'm not clear on the two comments regarding PROTO C.  The discussion here was a bit unclear.  In the original snippet I sent, I sent a asm program that had no PROTO C proto.  In an earlier version of the code, I in fact incorporated the C modifier.  Didn't seem to fix anything, and in fact, I have been able to get the subroutine to function appropiately without including the C modifier in the asm caller. 

So, maybeI don't understand quite the statement that "in this case it was not correct".  Perhaps not, but the code seems to run even if the PROTO statement could be made more precise with the inclusion of the "C" modifier.

Vortex:  Thanks for the heads up on the .bat file in VC 9.0 tools folder.  I didn't know it was there.  I've looked at it.  It's a good learning tool. 

I've been experimenting with the Set Path, Includes, etc.  One thing I don't understand:  when I do the "Sets", does it matter whether I am at the c:\ root or can I do the setting from \masm32\mymasm the directory? 


Thanks to all,
Mark Allyn


...unfortunately, gotta go teach now.

allynm

Hi Vortex -

This morning I tried out your set path, include, lib commands.  They worked beautifully.  Everything hums.

But, of course, when I'm done with the build I have knocked out the "permanent" environment variables, so if I want to call NOTEPAD right awat to do some more editing on the asm/c files, I can't unless I close out the window and then restart the command prompt.

Is there a way around this?

Thanks for all your help.

Mark

dedndave

well - if you make a simple batch file, you can get around it
for the executable paths, you can just add these to the permanent path (seperated by simcolons)

C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE
C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN

or - leave as is - they probably won't hurt anything


for LIB and INCLUDE, you can store the original variables into temporary ones
then restore them at the end of the batch file

set LIB_SAVE=%LIB%
set INC_SAVE=%INCLUDE%

set LIB="C:\Program Files\Microsoft Visual Studio 9.0\VC\lib";"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib"
set INCLUDE="C:\Program Files\Microsoft Visual Studio 9.0\VC\include";"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include"

cl /c /Zl /Gs /GS- summer.c
C:\masm32\bin\ml /c /coff test.asm
C:\masm32\bin\polink /SUBSYSTEM:CONSOLE test.obj summer.obj

set LIB=%LIB_SAVE%
set INCLUDE=%INC_SAVE%

set LIB_SAVE=""
set INC_SAVE=""

there is also a batch "local" but i forget how to use it - lol (probably setlocal)
it limits the scope of the variables to the batch file
you might google it if you are interested

EDIT here you go....

http://ss64.com/nt/setlocal.html

jj2007

Quote from: dedndave on January 22, 2010, 05:43:38 PM

there is also a batch "local" but i forget how to use it - lol (probably setlocal)
it limits the scope of the variables to the batch file
.. http://ss64.com/nt/setlocal.html

What you launch from your IDE seems to be local by default. I use this line
set path=C:\Programmi\Microsoft Visual Studio 9.0\Common7\IDE;%path%
echo ThePath: %path%

needed to run the newer linker versions. But when I launch a command prompt afterwards and type path, I only see the old path.