News:

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

Need basic help creating a library

Started by NoCforMe, November 03, 2011, 06:22:46 PM

Previous topic - Next topic

NoCforMe

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.

NoCforMe

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?

dedndave

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

fearless

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 ;-)
ƒearless

NoCforMe

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?)

NoCforMe

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!)

fearless

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.
ƒearless

NoCforMe

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 ...

Tedd

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.
No snowflake in an avalanche feels responsible.

NoCforMe

So can I safely leave all those INCLUDELIBs out? I like to minimize program clutter ...

dedndave

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

dedndave

just happened to think
you might try the LIB environment variable

nope - that doesn't get it

dedndave

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 /?

dedndave

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

dedndave

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