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
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
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
Hi Mark,
Did you set correctly the environment variable PATH to reflect the path to the compiler?
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
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
Just remember INVOKE will balance the stack for you when calling C functions.
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
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
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
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.
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.
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
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
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.
well - that is a new instance of CMD.EXE
the temporaries are lost when you close the console window
to make them permanent, you have to go through the System cpl in the control panel or through the registry
Quote from: allynm on January 21, 2010, 10:14:45 PM
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.
...
Hi Mark,
When using a C function the caller is obliged to balance the stack after the call, normally INVOKE will do this for you in MASM as long as it is informed that the call adheres to the C calling convention. In order to do that you must include the [langtype] directive in your PROTO definition. In you original post you had this:
summer PROTO :DWORD, :DWORD
This will inform MASM that it is to expect a STDCALL (modified RTL pascal) function and the stack will not be balanced after the call which is incorrect. Vortex corrected it in his post:
summer PROTO C :DWORD,:DWORD
Regardless of whether it fixed all of the problems you were having, the language directive still has to be set properly, the fact that it did not seem to solve the problem just means that it was not the only one. I did not look at the code you uploaded, only what was in the post since I don't bother much with MASM code (GoAsm does not use protos or libs) and was simply commenting on Greg's post.
Edgar
Hi everyone-
I looked over what dedndave did, and it looks like the right way to restore the original functionality after setting the paths. And it could all be stashed in a bat file. So, it's pretty cool.
I finally "got it" as far as including the C modifier in the Proc statement. I will in future make this a standard. Thanks for clarifying this point. And, yes, there were other problems sinking my ship.
One point that would be helpful to me since I am new to setting environments is what exactly happens when you do something like this:
set path=c:\etc, etc,;%PATH%
I don't understand what sticking the %PATH% variable at the end accomplishes. It's probably simple, but it isn't clear. I also don't understand why quotation marks are sometimes used and sometimes not. If anybody cares to elucidate this, I would find it most helpful.
What I ended up doing was to reset the permanent path, lib, and includes in the environment so that they would automatically be available in my masm directory. In other words, I quit messing around with temporarily changing these variables the way Vortex suggested, and just put them into the permanent environment. They work nicely that way and there is no problem with restoring Notepoad at the end of a buiild.
Thanks to all,
Mark
QuoteI don't understand what sticking the %PATH% variable at the end accomplishes. It's probably simple, but it isn't clear. I also don't understand why quotation marks are sometimes used and sometimes not. If anybody cares to elucidate this, I would find it most helpful.
You use %PATH% because you want to add the folder to the current path, not completely replace it. Quotes are usually used when there is a space or other delimiter in the path.
Hi Mark,
set path=c:\etc, etc,;%PATH%
c:\etc means that there is a directory named etc in the root of your drive C
The second etc means that there is subfolder named etc in your current directory.
The %PATH% expression will be expanded to the current path info. Let's have a look in this example :
set path=C:\MyFirstDir
path
PATH=C:\MyFirstDir
set path=C:\MySecondDir;%PATH%
path
PATH=C:\MySecondDir;C:\MyFirstDir
It's not obligatory to enclose the paths between double quotes.
commas should not appear in the path variable
and, it is generally considered good practice to reference all paths completely, including the drive
when you do something like this...
set PATH=C:\MyNewPath\Folder;%PATH%
or
set PATH=%PATH%;C:\MyNewPath\Folder
the new folder is appended to the current PATH variable
placing the new path first means windows will look in that folder first for the executable or batch command
that can make a difference if there are executables in other folders in the PATH variable that are named the same
in days of old, it used to speed things up for earlier named folders, as well
that is no longer true, as the directories of these folders gets cached anyways
Quote from: Vortex on January 23, 2010, 04:42:50 PM
It's not obligatory to enclose the paths between double quotes.
set path=
"C:\Programmi\Microsoft Visual Studio 9.0\Common7\IDE
";%path% throws a "mspdb80.dll not found error"
set path=C:\Programmi\Microsoft Visual Studio 9.0\Common7\IDE;%path% works fine.
Old Dos convention - 8 char (filename) and 3 char (ext).
Use the tilde key (~) in the eigth char for all directories that are longer than 8 chars.
Also, spaces in the names need to be quoted, else the space creates tokens persay, versus path info.
Quote from: z941998 on January 24, 2010, 04:50:42 AM
Old Dos convention - 8 char (filename) and 3 char (ext).
Use the tilde key (~) in the eigth char for all directories that are longer than 8 chars.
You should test your advice before posting in the Campus. Even if there was only one folder starting with MICROS, it would still be the seventh, not the eight char.
C:\PROGRA~1\MICROS~2.0
C:\Program Files\Microsoft Not so Visual Crap 1.0
C:\PROGRA~1\MICROS~1.0
C:\Program Files\Microsoft Visual Studio 9.0
> Also, spaces in the names need to be quoted, else the space creates tokens persay, versus path info.
See my post before. There is
no need to quote long path names with spaces.
Quote from: z941998 on January 24, 2010, 04:50:42 AM
Old Dos convention - 8 char (filename) and 3 char (ext).
Use the tilde key (~) in the eigth char for all directories that are longer than 8 chars.
Also, spaces in the names need to be quoted, else the space creates tokens persay, versus path info.
Actually the tilde (~) can be on any character though it is generally on the 7th or 8th and can be followed by a number (ie PROGRA~1) in order to distinguish between items that have the first 8 characters in common. If you want to get the actual short name you need to use the GetShortPathName function or from Windows using DIR from the command prompt with the /x switch.
Quote
C:\PROGRA~1\MICROS~2.0
C:\Program Files\Microsoft Not so Visual Crap 1.0
C:\PROGRA~1\MICROS~1.0
C:\Program Files\Microsoft Visual Studio 9.0
normally, it would be like this
C:\PROGRA~1\MICROS~[N]
C:\PROGRA~1\MICROS~[N]
where [N] is an incremented value based on on the order of folder creation (or recognition)
the period in folder names is treated similar to file extensions in that it becomes a new name section
when it reaches a 2-digit value...
C:\PROGRA~1\MICRO~[NN]
when it reaches a 3-digit value...
C:\PROGRA~1\MICR~[NNN]
and so on
QuoteSee my post before. There is no need to quote long path names with spaces.
i am pretty sure that depends on which batch command you are using
some batch commands recognize spaces as parameter delimiters
Quote from: dedndave on January 25, 2010, 03:07:01 PM
...
where [N] is an incremented value based on on the order of folder creation (or recognition)
the period in folder names is treated similar to file extensions in that it becomes a new name section
when it reaches a 2-digit value...
C:\PROGRA~1\MICRO~[NN]
That is correct, to my knowledge. I obtained my example paths with an equivalent to GetShortPathName. Caution with the dir /x variant, it yields this on my machine, XP SP2:
Quote25.01.10 15:38 <DIR> MICROS~2.0 Microsoft Not so Visual Crap 1.0
14.01.10 16:38 <DIR> MICROS~2 Microsoft Office
30.11.05 16:01 <DIR> MICROS~3 Microsoft Visual Studio
05.01.10 13:30 <DIR> MICROS~1.0 Microsoft Visual Studio 9.0
QuoteSee my post before. There is no need to quote long path names with spaces.
Quote
i am pretty sure that depends on which batch command you are using
some batch commands recognize spaces as parameter delimiters
That is correct but rarely relevant since the path starts with an executable, not with parameters.