home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
488.lha
/
reslib
/
reslib.doc.pp
/
reslib.doc
Wrap
Text File
|
1991-03-12
|
10KB
|
218 lines
======================================================================
How to create an Amiga shareable library:
======================================================================
1) Compile all modules that reference global data with the -ml option.
Note that global data will be shared between all processes that open
the library.
2) Add the __saveds keyword to any function that is callable from outside
the library.
3) Create a .fd describing your library. A sample .fd file is included
for reference.
4) Link with the following command:
blink LIBFD <fdfile> [LIBPREFIX <prefix>] [LIBID <idstring>] TO <libname>
FROM lib:libent.o lib:libinit.o <modules>
where
LIBFD <fdfile> specifies the name of the .fd file you created in step (3).
LIBPREFIX specifies an optional prefix to add to the functions listed
in the .fd file. The default is simply an underscore (_).
If for some reason you don't want to use the #pragmas to
access the library, you can use the old method of having
assembly-language stubs that accept parameters on the stack
like a typical C routine, pop them into registers and call
the library function for you. (You must write the stubs
yourself in assembler.) If you do this, the library
routines cannot have exactly the same names as the entries
in the .fd file, since these names will have been taken
by the stub routines. The LIBPREFIX option specifies a
common prefix to be prepended to the function names in the
.fd file. You will be responsible for making sure that the
actual function declarations in the library's .c source file
match the full name, including any specified prefix. For
example, if your library has a function called 'foo' and
you specify a LIBPREFIX of _LIB, you should declare the
function in your source code as LIBfoo. (Remember that
Blink always adds an extra underscore to symbol names.)
If you always use the automatically-generated #pragma
statements to access the library, you can ignore LIBPREFIX.
LIBID <idstring> specifies an optional library ID string (See _LibID, below).
LIBID is purely informational and is never required.
TO <libname> specifies the resulting library name.
libent.o contains the RomTag for the library, and MUST BE THE FIRST
OBJECT MODULE LISTED. The source to libent.o (libent.a) is
in the SOURCE subdirectory of disk 4 of the compiler
distribution. You do not need to modify this file for
your library, and probably should not.
libinit.o contains the system-required library entry points Open,
Close and Expunge as well as other initialization routines,
and MUST BE THE SECOND OBJECT MODULE LISTED. The source to
libinit.o (libinit.c) is in the SOURCE subdirectory of
disk 4 of the compiler distribution. You may modify this
file to add custom initialization code if you like, but
you are not required to.
modules are your module names. They may be in any order as long
as they are specified after libent.o and libinit.o.
======================================================================
How to call the library:
======================================================================
Create pragmas for your library with the FD2PRAGMA program, provided on
disk 3 of the compiler distribution. FD2PRAGMA will output a .h file
containing #pragma statements for all the externally-callable functions
in your library. Code that would like to call your library should
#include this .h file before referencing any of the library's functions.
When one of the library functions is called, the compiler will look at
the #pragma for that function and determine which registers the library
function wants the parameters in. It will load the proper registers, load
your library base in register A6, and call your function.
The user code should declare a variable of type 'struct Library *' named
after your library base. For example, if your library is called
'mylib.library', and you have chosen to name your library base 'MyLibBase',
the declaration in the user's code would look like:
struct Library *MyLibBase;
The library base can be an automatic or a global variable. Before calling
any function in your library, the user must initialize the library base
by calling the OpenLibrary function:
MyLibBase = OpenLibrary("mylib.library", version);
where version is less that equal to the number in the version
field of the struct Library (see libinit.c). A version of 0
will open any version of the library.
The user should always check to make sure that MyLibBase is not NULL,
which would indicate that the library could not be loaded or that the
revision was not acceptable.
Once the library base pointer is loaded, the user program can call your
library functions by name just like any other function. When the program
is finished with your library, it should call CloseLibrary:
CloseLibrary(MyLibBase);
======================================================================
How It Works:
======================================================================
1) What the compile options do
Modules compiled with -ml do not use register A6, except when calling
other libraries, in which case it is restored immediately upon return.
Therefore A6 always has a pointer to the current library base. Further,
when __saveds is specified, the compiler generates the instruction
LEA LinkerDB(A6),A4
in the function prolog. LinkerDB is a symbol generated by Blink that
specifies the offset from the library base at which user global data
may be stored. Thus, the above instruction sets A4 to point to the
library's global data. Notice that the standard executable startup
code, c.o, contains a reference to LinkerDB as well. When Blink is
linking a library, it knows to interpret LinkerDB differently than
when linking a normal program.
2) What the initialization code does
The job of the LibInit function in a shareable library is to set up
the library base. The LibInit() function defined in libinit.c will
in addition copy global data from the place where LoadSeg loaded it
(as defined by the Blink-generated symbol _Libmergeddata) to the end
of the library base structure. Once there, any data relocations are
patched up. From this point on, global data may be referenced relative
to A4 since A4 has been set to point at the global data.
2) What Blink does
Blink first reads the .fd file and determines the names and number
of functions to the library. It creates a jump table of the form:
+---------------------------------+
| __LibOpen |
| __LibClose |
| __LibExpunge |
| ROMTAG - 2 |
| user defined functions. |
+---------------------------------+
The names of the user-defined functions are created by prepending the
specified LIBPREFIX to the function names in the .fd file. The symbol
_LibFuncTab points to the table, which is placed into the data section.
Blink also defines the following symbols for libinit.o to use when
initializing the library:
_LibName name of library, as specified by the TO option to
BLINK.
_LibID id for library, as specified by the LIBID option to
BLINK. This is a null string if no LIBID option is
specified.
RESLEN length of data section to be allocated as part of
the Library structure.
NEWDATAL length of initialized data section.
======================================================================
Library Format:
======================================================================
The library that blink produces looks like this:
Code Hunk 1: (comes from libent.o)
moveq #0,d0 ; This is in case someone tries
rts ; to run the library as a program
RomTag
dc.w RTC_MATCHWORD ; RomTag information for the library
dc.l _LibRomTag ; as described in the Rom Kernel manual
dc.l endtag ; |
dc.b RTF_AUTOINIT ; |
dc.b VERSION ; |
dc.b NT_LIBRARY ; |
dc.b PRI ; |
dc.l _LibName ; |
dc.l _LibID ; v
dc.l _LibInitTab ; End of RomTag information
Code Hunk 2 - n: (comes from libinit.o and user modules)
_LibInit
<code for LibInit>
_LibOpen
<code for LibOpen>
_LibClose
<code for LibClose>
_LibExpunge
<code for LibExpunge>
user functions
MERGED DATA
_Libmergeddata ; symbol that tells LibInit where the merged
; data is initially loaded.
_LibInitTab ; struct LibInitTab as specified in libinit.c
length of global data
pointer to function jump table
NULL
pointer to initialization code (_LibInit)
USER GLOBAL DATA
For a quick example, refer to the readme file.