Another (somewhat) n00b question here:
I want to create a library for some routines I plan on using in several programs. I used to do this, long ago and far away in a land of 16-bit words.
But things are different now, and I can't get this simple thing to work.
Here's my test routine for the library:
INCLUDE \techstuff\masm32\include\my_masm32rt.inc
PUBLIC Test1
.data
testmsg DB "libtest.asm here", 0
.code
Test1 PROC
INVOKE MessageBox, 0, ADDR testmsg, NULL, MB_OK
RET
Test1 ENDP
END
and here's the main program I'm using to test it (I took "minimum" from the MASM32 examples and cut it down even further):
include /techstuff/masm32/include/my_masm32rt.inc
includelib mylib.lib
extrn Test1:NEAR
.code
start:
call Test1
push 0
call ExitProcess
end start
(See Note 1 below)
Here are the commands I used to put things together:
ml /c /coff libtest.asm
lib /out:mylib.lib libtest
ml /c /coff minimum.asm
link /subsystem:windows minimum
(See Note 2 below)
When I try to link the test program, I get this error message:
minimum.obj : error LNK2001: unresolved external symbol _Test1
minimum.exe : fatal error LNK1120: 1 unresolved externals
Help! I understand what's happening here: in high-level-language convention, function names are being prefixed with underscores. (In 16-bit land things were so much simpler: if you called a function "foo", that's what it looked like all through the assemble/link process.) So somewhere along the line there's a mismatch.
I thought that putting the "includelib" statement in the main (calling) program should make everything work. Can't figure out why this reference to the subroutine isn't getting resolved. Everything--both source files, both object files and the library file--is in the same folder.
What magic incantation am I missing here? Please tell me it's something simple ...
Note 1: Yes, that's where I like to park the MASM32 package (not in the root), since, well, since it's MY computer and I'll do as I please. Don't like that? Tough.
Note 2: Tools (ml.exe, lib.exe & link.exe) load just fine; no need for that "[path]\.ml.exe" nonsense, since I have my PATH properly set to point to the MASM32\bin folder.
Something about the LIB program (Microsoft Library Manager Version 5.12.8078) that bugs me: when I run it from the command line, it seems to be waiting for more input (from STDIN) after it executes whatever command I give it, so I'm never sure what it's really doing. Is this normal? Is it meant to be run from a script or batch file, but not "by hand"?
Another thing: when I look at the library I created (with a hex file viewer), I see that the module name is actually "_Test1@0". Is this correct?
a while back, i wanted to do the same thing
under masm 5.10, i used PUBLIC and EXTRN (or EXTERN), just like you
now days, they are both replaced by EXTERNDEF - lol
you may want to browse through the entire thread, but the first post has the attachment...
http://www.masm32.com/board/index.php?topic=15480.0
PROC's are public by nature, unless you specify PRIVATE on the PROC line
DATA is private by nature, and must be made public to be externally visible
Link can output library files as well, have a look at masm32 library to give you an idea how it was compiled, the folder has some batch files in it for assembling and will give you an idea what to specify.
Also you probably want to have your own .inc file for your library to has the functions that are available for use.
So in other asm programs you use you would add the following:
include mylib.inc
includelib mylib.lib
(also remember to copy the .lib to your masm32\lib folder and the .inc file to masm32\include for ease of use)
In your mylib.inc you woudl probably have the definitions like so:
Test1 PROTO
obviously coz you only have one function with no parameters there is nothing else to declare.
If you have another proc, lets say its called TestMe, and has four params like so:
TestMe PROC szName:DWORD, lpszOutBuffer:DWORD, fOutputType:DWORD, MiscParam:DWORD
... some stuff for proc
ret
TestMe ENDP
In your .inc file (same one) you would add the definition for your new function as:
TestMe PROTO :DWORD, :DWORD, :DWORD, :DWORD
To someone reading your source code they would know what each param is and why, but to someone else they wont, so make a note somewhere, document the parameter inputs (whats expected) and any return values - more for yourself if you come back to it months later and have forgotten what exactly it does ;-)
Well, while I really can't argue with your advice, it's all beside the point here because I can't get the library routine to be linked at all. Kind of a more pressing problem at the moment than having nice include files.
So can someone please lay out here (not in an attachment!) exactly what I need to do here, with EXTERNDEFs and all, to make this simple example work? I'm totally confused, especially about the use of this directive. (Do I use it both in the subroutine AND the calling module? Do I use it with PROTO? How the hell does this all work, anyhow?)
Problem solved.
Turned out I needed the following statement in both the library module and the calling program:
Test1 PROTO
Seems kinda silly, but it makes it work ...
Still not completely clear on the use of EXTERNDEF, PROTO, etc. Damn Micro$oft! I've got a copy (printed copy) of the MASM 6.1 Programmer's Guide. While they mention both of these directives in several places, they never once clearly define them, give the exact syntax, or explain what exactly they do. Piss-poor manual, that. (If anyone knows of some better documentation out there, I'm all ears!)
Yep, just include your mylib.inc in your new project - which has the proto defined and it will pick it up when linking due to the includelib and include statements.
So that last statement brings up another question that's been bugging me: what's up with using "includelib", anyhow? (Apologies if this has already been discussed on this forum.)
It doesn't make sense to me that this goes in the assembly source file; isn't this something that's handled by the linker, not the assembler? Why does the assembler care about any linked library modules, apart from the names of the symbols in those modules, which are already taken care of by use of EXTRN, EXTERNDEF, PROTO, etc.?
Even if one uses ml.exe to both assemble and link, shouldn't the library module resolution stuff be taken care of during the link phase anyhow?
I'm confused ...
The assembler doesn't care about includelib, it's actually just a convenience that we can put it in there. It's inserted into the object file as a 'pragma,' which the linker processes when given the object file.
So can I safely leave all those INCLUDELIBs out? I like to minimize program clutter ...
have you tried it ? :bg
you can probably leave them out if you specify them on the link command line
much more convenient in the assembler source
when you create your own static library, you will probably want to create an INC file to go with it
you can put the INCLUDELIB in that INC file, if desired, along with the PROTOtypes and constants (EQU) that go with the LIB
just happened to think
you might try the LIB environment variable
nope - that doesn't get it
first, let's make a static library
we want one public data item and one public function
for the data, we will use a string that we can display
for the function, we will use the print macro wrapped in a PROC
create a file named Module.asm...
;static library module source
INCLUDE \masm32\include\masm32rt.inc
;------------------------------------------------
EXTERNDEF szTestString:BYTE ;probably don't need the type here - just the label name
;------------------------------------------------
.DATA
szTestString db 'Static Library Test String',13,10,0
;------------------------------------------------
.CODE
TestFunc PROC lpszString:LPSTR
print lpszString
ret
TestFunc ENDP
;------------------------------------------------
END
this will make one module - the library may hold many such modules
to assemble it...
ml /c /coff Module.asm
to create the library from that module...
link /lib Module.obj /out:MyLib.lib
notice that LINK does all the stuff that we used to use LIB for
there is also a LIB.exe that may be used (notice how small it is - it's a stub for LINK)
you can get all the add/remove/extract module management commands with LIB /?
now, we want an INC file to go with the LIB
it can define any constants (EQUates) and PROTOtypes required to use the library
an example of such a file might come from microsoft
they give you files like kernel32.h - a C include file
we want an assembler version (INC)
the syntax is different, but the idea is the same
one of the functions in kernel32 is SetConsoleMode
that function has several constants that go with it, like ENABLE_MOUSE_INPUT
so, in kernel32.inc, we would see...
SetConsoleMode PROTO :HANDLE,:DWORD
ENABLE_MOUSE_INPUT EQU 10h
of course, there are more prototypes and constants, too
Hutch has taken all these constants and put them in windows.inc
that is why it is so large (the masm32 windows.inc is actually split in 2)
i think he did it that way so all the constant definitions could be found in one place, without searching for them
for our little library, we have one function, and no constants
as you add things to the library, you will update the INC file
so - create a file named MyLib.inc...
;INCLUDE file for MyLib.lib
EXTERNDEF szTestString:BYTE ;the type is required, here
TestFunc PROTO :LPSTR
finally, we want to write a little program to test the library...
INCLUDE \masm32\include\masm32rt.inc
INCLUDE MyLib.inc
INCLUDELIB MyLib.lib
;------------------------------------------------
.CODE
_main PROC
INVOKE TestFunc,offset szTestString
inkey
exit
_main ENDP
;------------------------------------------------
END _main
as i mentioned before, you could take the INCLUDELIB directive out of the source and put it in the INC file
Quote from: dedndave on November 04, 2011, 12:27:48 PM
as i mentioned before, you could take the INCLUDELIB directive out of the source and put it in the INC file
Regarding this, while it obviously makes it more convenient, it seems a little silly to include the INCLUDELIB in the source file where the library module itself is being defined. So what is the effect of that: nothing? (Otherwise, it would have to be recursive or something!)
Its more about making the lib distributable and re-usable with ease, and since all the function prototypes are defined in your .inc makes sense to use that with the includelib. Both for your lib and for referencing the lib functions in other asm modules that you create.
Right, I got that. I guess the answer to my question above, then, is "it doesn't hurt if you put INCLUDELIB in the file where the library module is declared".
well - there are cases where you may want to build a project with different versions of a library
in that context, it makes sense to put the INCLUDELIB in the asm source, where it is clearly visible and easily changed