home *** CD-ROM | disk | FTP | other *** search
- ======================================================================
- 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.
-