home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / libraries / library.lha / LIBRARY.TXT
Encoding:
Text File  |  1994-08-01  |  61.7 KB  |  1,781 lines

  1.                         (Version 1.0 "Mon Aug 1 16:33:46 1994")
  2.  
  3.                         Guide to AmigaDOS Shared Libraries
  4.                         ==================================
  5.  
  6.   This article is Copyright (C) by Daniel Stenberg (dast@sth.frontec.se) 1994.
  7. FidoNet 2:201/328, IRC: 'Bagder'.
  8.  
  9.   An early version of this article was published by the american Amiga
  10. technical magazine called "AC's Tech", issue #2 1994. This version is updated,
  11. revised and reformatted for ASCII. Major updates to this document will be found
  12. in various places, but most like on AmiNet sites.
  13.  
  14.  
  15. NOTE:
  16.      The examples of this article are written in assembler and C and
  17. require some knowledge of the languages to fully understand what they are
  18. all about. They are written only to illustrate the explanations and are
  19. only parts of larger source codes. They may not be accurate and I take no
  20. responsibility for the correctness or function of the examples.
  21.  
  22. Table of contents:
  23. ##################
  24.  
  25. 1                           Shared Library Overview
  26.   1.1 Shared Library
  27.   1.2 Link Library
  28.   1.3 ROM Based/Disk Based Libraries
  29.   1.4 Memory Usage
  30.   1.5 Other Operating Systems
  31.   1.6 Advantages
  32.  
  33. 2                       Calling Shared Library Functions
  34.   2.1 Address Library Functions
  35.   2.2 Library Base
  36.   2.3 Index
  37.   2.4 Parameters
  38.   2.5 Access Libraries
  39.     2.5.1 OpenLibrary()
  40.     2.5.2 CloseLibrary()
  41.     2.5.3 RemLibrary()
  42.   2.6 Return Code
  43.   2.7 Glue Code
  44.   2.8 C and Register Parameters
  45.     2.8.1 SAS/Dice pragmas
  46.     2.8.2 Aztec/Maxon pragmas
  47.     2.8.3 How to create pragma files
  48.   2.9 Near Data Effects
  49.   2.10 Registers
  50.  
  51. 3                  Parts of an AmigaDOS Shared Library Image
  52.   3.1 Prevent Execution
  53.   3.2 ROMTag Structure
  54.   3.3 Init Table
  55.   3.4 Function Pointer Table
  56.   3.5 Data Table
  57.   3.6 Init Routine
  58.   3.7 Functions
  59.  
  60. 4                           Libraries in the System
  61.   4.1 Library Opening Details
  62.   4.2 Library List
  63.   4.3 Patching Libraries
  64.  
  65. 5                                 Programming
  66.   5.1 Functions
  67.     5.1.1 Open()
  68.     5.1.2 Close()
  69.     5.1.3 Expunge()
  70.     5.1.4 Extfunc()
  71.   5.2 Function Descriptor File
  72.   5.3 Glue Code
  73.   5.4 Compiling
  74.   5.5 Linking
  75.   5.6 Debugging
  76.   5.7 Hints
  77.  
  78. 6                        Support library calls from ARexx
  79.   6.1 How ARexx access the library
  80.   6.2 ARexx calls a library function
  81.   6.3 ARexx function
  82.  
  83.                                      Appendix
  84. A. Version numbers and shared libraries
  85. B. Further reading
  86. C. Library source examples
  87.  
  88. 1.                           Shared Library Overview
  89. -------------------------------------------------------------------------------
  90.  
  91.      To be able to learn how to make a shared library, it's important to
  92. have the knowledge about what it is all about. In this article I'll take
  93. you through all steps, from the most basic ones down to the ones dealing
  94. with low level library programming.
  95.  
  96. 1.1 Shared Library
  97. ------------------
  98.      First, an answer to the question: what is a shared library? As the
  99. name says, it is a function library shared by several simultaneous tasks
  100. and processes. The shared library code is not present in the executable
  101. image on disk, but is a separate file. The shared code is not loaded
  102. together with the executable. It is loaded into memory only when a program
  103. requires it.
  104.      On Amiga, the naming convention says that a shared library should be
  105. in lowercase letters with a ".library" ending, and the directory to put
  106. public libraries in is "LIBS:".
  107.  
  108. 1.2 Link Library
  109. ----------------
  110.      A link library is not to be mixed up with a shared library. A link
  111. library is a function library that is linked into the executable at compile
  112. time. A link library becomes a part of an executable image.
  113.  
  114. 1.3 ROM Based/Disk Based Libraries
  115. ----------------------------------
  116.      The AmigaDOS system consists of several shared libraries, whose names
  117. you recognize: dos.library, exec.library, graphics.library, only to mention
  118. a few. These libraries won't be found in the LIBS: directory, they reside
  119. in ROM. Whether in ROM or on disk, shared libraries work and are used the
  120. same way.
  121.  
  122. 1.4 Memory Usage
  123. ----------------
  124.      As mentioned, shared libraries are loaded when a program requests,
  125. i.e. opens, it. When the program has finished using the library, it closes
  126. the library. The library remains in memory even though no process is using
  127. it, until the operating system requires the memory it occupies (or is
  128. forced to remove itself by a program, such as "avail FLUSH" on the shell
  129. prompt in AmigaDOS 2.0 or later).
  130.  
  131. 1.5 Other Operating Systems
  132. ---------------------------
  133.      Shared libraries are not AmigaDOS specific. Such are also found under
  134. different UNIXes, OS/2, Microsoft Windows, OS-9, OS-9000 and others. They
  135. are though not always called "shared libraries", but their concepts are
  136. very similar.
  137.  
  138. 1.6 Advantages
  139. --------------
  140.      The reasons why so many systems are using shared libraries are among
  141. others: less disk space is used because the shared library code is not
  142. included in the executable programs, less memory is used because the shared
  143. library code is only loaded once, load time may be reduced because the
  144. shared library code may already be in memory when a program wants it, and
  145. that programs using shared libraries are very easily updated.
  146.  
  147.  
  148. 2.                       Calling Shared Library Functions
  149. -------------------------------------------------------------------------------
  150.  
  151.      We've been looking at what a shared library is, a little about how it
  152. works and some of its advantages. Now it's time to see how a library is
  153. used and accessed.
  154.  
  155. 2.1 Address Library Functions
  156. -----------------------------
  157.      To be able to handle library calls, we must know how to call shared
  158. library functions. I'll describe it with a small comparsion to standard
  159. non-shared functions.
  160.  
  161.      The most significant difference is in the way the functions are
  162. addressed. A standard function within a program is more or less an address
  163. to which the program counter is set when we want to jump to it. A shared
  164. library function is on the other hand addressed by adding a number to the
  165. address of the library's base.
  166.      When using standard function calls, the compiler or assembler arrange
  167. so that e.g. the function "getname" is associated with the particular
  168. static address in memory where the "getname" function starts.  If the same
  169. "getname" function would be a shared library function, the compiler
  170. wouldn't know the actual address of it, but dynamically add a certain
  171. number (index) to the library's base address to access it.
  172.      As you see, we must know the index of the function and the library's
  173. base address to be able to call a shared library function.
  174.  
  175. 2.2 Library Base
  176. ----------------
  177.      To find out the library base of a shared library, you must call
  178. OpenLibrary() which will return the library base of the spcified library in
  179. register D0. All library bases are found like that except exec.library's,
  180. which is found by reading the pointer stored at the absolute address 4.
  181.  
  182. 2.3 Index
  183. ---------
  184.      Whenever you want to call a function in a shared library you (or the
  185. compiler) have to know the index to add to the library's base address. That
  186. 'index' is sometimes reffered to as 'vector' or 'offset'.
  187.      E.g., to call OpenLibrary() you must know the index of the function
  188. and the library base itself (OpenLibrary() is an exec.library function and
  189. we know that exec.library's base address is found at address 4). A call to
  190. OpenLibrary() could look like this in assembler:
  191.  
  192.      move.l  SysBase,a6        ; SysBase is the name of
  193.                                ; exec.library's base pointer
  194.      ; >>> Parameters left out in this example <<<
  195.      jsr     -552(a6)          ; We'll jump straight into the jump
  196.                                ; table at the certain index. The index
  197.                                ; is -552 in this case
  198.  
  199. 2.4 Parameters
  200. --------------
  201.      Ok, we know how to call a library function and we know that we must
  202. call OpenLibrary() to get a library's base address. To inform e.g
  203. OpenLibrary() which library we want to open, we must send it some
  204. parameters. The documentation tells us that OpenLibrary() wants the library
  205. name in A1 and the lowest acceptable version in D0.  Parameters to the
  206. library functions are always stored in registers. See the library reference
  207. documentation for closer information exactly which registers.
  208.  
  209.      This example opens a library with the name at libName with
  210. version 33 or higher:
  211.  
  212.      Include "exec/funcdef.i"     ; _LVO macro constructs
  213.      Include "exec/exec_lib.i"    ; exec function index
  214.      VERSION equ 33
  215.  
  216.      move.l   SysBase,a6          ; exec library base
  217.      lea.l    libName,a1          ; library name
  218.      move.l   #VERSION,d0         ; lowest usable version
  219.      jsr      _LVOOpenLibrary(a6) ; OpenLibrary()
  220.  
  221. 2.5 Access Libraries
  222. --------------------
  223.      The operating system provides facilities for the creation, use and
  224. access of shared libraries. The functions that let the programmer construct
  225. and access libraries are of different levels to give different
  226. possibilities. Low level function where you can change every single
  227. parameter and more high level functions that do a lot without the
  228. programmers exact specification.
  229.  
  230.      I'll describe the functions of the highest level that also are the
  231. most frequently used:
  232.  
  233. 2.5.1 OpenLibrary()
  234.      Gains access to a named library of a given version number. The library
  235.      will be search for in ROM, in LIBS: and at last in current directory.
  236.      You can also specify a library with an absolute path.
  237.      Always open libraries with the lowest version which includes the
  238.      functions you need. To open intuition.library for 2.0+ (version 36)
  239.      only, try something like:
  240.  
  241.      #include <proto/exec.h>
  242.      #define LIB_VERSION 36
  243.      struct ExecBase *SysBase;
  244.      struct IntuitionBase *IntuitionBase;
  245.      void main(void)
  246.      {
  247.        /*
  248.         * The SysBase should be in order to perform this.
  249.         * (Using any C startup module will do this for you.)
  250.         */
  251.        IntuitionBase=(struct IntuitionBase *)
  252.          OpenLibrary("intuition.library", LIB_VERSION);
  253.        if(!IntuitionBase) {
  254.          printf("Couldn't open intuition version %d+\n", LIB_VERSION);
  255.          exit(10);
  256.        }
  257.        /*
  258.         * The program using intuition.library V36+ follows here!
  259.         */
  260.      }
  261.  
  262.      AmigaDOS file names are not case sensitive, but Exec lists are.
  263.      If the library name is specified in a different case than it exists on
  264.      disk, unexpected results may occur.
  265.  
  266.      The library base returned from OpenLibrary() is not sharable between
  267.      tasks! The only library base allowed to share is Exec's. If your
  268.      program starts more tasks or processes, they all have to open their
  269.      own libraries. This is subject to a lot of discussions where people
  270.      state that all libraries, *except* those that are especially documented
  271.      as non-shareable, are shareable. Although, this is what the library
  272.      bible says about it:
  273.  
  274.      "Sharing Library Pointers: Although in most cases it is possible
  275.      for a parent task to pass a library base to a child task so the child
  276.      can use that library, for some libraries, this is not possible.
  277.      For this reason, the only library base shareable between tasks is
  278.      Exec's library base." (from RKRM Libraries 3rd ed., p. 467)
  279.   
  280. 2.5.2 CloseLibrary()
  281.      Concludes access to a library. Whenever your program has
  282.      finished using the functions of a shared library, there should be a
  283.      call to CloseLibrary() for every call to OpenLibrary(). Simply like
  284.      this:
  285.  
  286.      CloseLibrary((struct Library *)IntuitionBase);
  287.  
  288. 2.5.3 RemLibrary()
  289.      Calls the Expunge() function of the specified library. If the library
  290.      isn't open, it will delete itself from memory. This is not typically
  291.      called by user code.
  292.  
  293.       /* Attempts to flush the named library out of memory. */
  294.       #include <exec/types.h>
  295.       #include <exec/execbase.h>
  296.  
  297.       void FlushLibrary(STRPTR name)
  298.       {
  299.         struct Library *result;
  300.  
  301.         Forbid();
  302.         if(result=(struct Library *)FindName(&SysBase->LibList,name))
  303.            RemLibrary(result);
  304.         Permit();
  305.       }
  306.  
  307. With these three functions in mind, we'll continue.
  308.  
  309. 2.6 Return Code
  310. ---------------
  311.      The return code of a shared library function call is always received
  312. in a register. (Today, I don't think there is a single function not using
  313. D0 for that purpose.)
  314.  
  315. 2.7 Glue Code
  316. -------------
  317.      The parameter storage in registers is not that comfortable in all
  318. occasions and many compilers (in all kinds of programming languages) don't
  319. even have the ability to store parameters in (pre-decided) registers. Then,
  320. glue code is required. Glue code (also known as "stub functions" or simply
  321. "stubs") is simply a set of functions that you can call instead of the
  322. shared library functions. The stub function reads the parameters from the
  323. stack and stores them in registers and then calls the shared library
  324. function. That makes the use of the glue code functions identical to other
  325. functions. Glue code is compiled into a kind of object file, using the
  326. suffix ".lib", and is stored in LIB: (not to be mixed up with LIBS: where
  327. the shared libraries are stored). All stub functions for the standard
  328. AmigaDOS libraries are found in the "amiga.lib" file that comes with most
  329. compilers or can be bought straight from Commodore.
  330.  
  331. 2.8 C and Register Parameters
  332. -----------------------------
  333.      C language compilers are in general using the stack to pass parameters
  334. between functions, but to be able to use shared libraries smoothly, several
  335. compilers offer ways to force parameters in registers and automatically use
  336. the right library base and function index.
  337.      The SAS, Dice, Aztec C and Maxon compilers, all provide such solutions
  338. by special pragma instructions. A pragma instruction is a line starting
  339. with "#pragma", which is a compiler instruction keyword, followed by the
  340. compiler specific text.  Such a pragma defines the function, which library
  341. base it needs and in which registers the parameters must be stored. By
  342. using such pragmas you don't have to call or link any glue code within your
  343. program.
  344.      The GNU C compiler, which is a freely distributable C and C++
  345. compiler, has a very complicated way to solve this problem. It declares and
  346. uses inlined functions that use the GNU compiler's own __asm() instruction
  347. to set the proper registers to the right values.
  348.  
  349.      When using this information, a compiled result uses SysBase, the index
  350. and the parameters in registers just as we did in the assembler examples
  351. above. C language usage:
  352.  
  353.      #include <pragmas/exec_pragmas.h>
  354.      #define libName "foobar.library"
  355.      #define VERSION 33
  356.      OpenLibrary(libName, VERSION);
  357.  
  358. 2.8.1 SAS/Dice pragmas
  359. ----------------------
  360.      The library call pragmas available in the SAS compiler are built-up
  361. ike this (Dice supports most of this too):
  362.  
  363.      #pragma <kind of call> <lib base> <name> <index> <registers>
  364.  
  365.      which means:
  366.  
  367.  <kind of call>
  368.      Which kind of library call this pragma should generate. There are
  369.      three different ones:
  370.      `libcall' makes a standard library call
  371.      `tagcall' makes a standard library call where the last parameter
  372.      points to a taglist
  373.      `syscall' makes a call to exec.library
  374.  
  375.  <lib base>
  376.      The library base name to use. Not specified for `syscall' calls.
  377.      Example: "DiskfontBase" (The name of diskfont.library's library
  378.      base.)
  379.  
  380.  <name>
  381.      Function name identifier. Example: "MyFunction".
  382.  
  383.  <index>
  384.      Function index of the library. A hexadecimal, positive number
  385.      (which is turned negative by the compiler when it generates the
  386.      indexed library call). Example: "1A" (The first library function
  387.      index of all normal libraries.)
  388.  
  389.  <registers>
  390.      Register/parameter information in a special format, a sequence of
  391.      hexadecimal numbers. Reading from the *right*, each digit has the
  392.      following meaning:
  393.      1. Number of parameters.
  394.      2. Result code register (0-6 means register D0-D6 and 8-9, A-E
  395.      means register A0-A6)
  396.      3+. The parameter registers, read from the left (!). The numbers
  397.      are associated with the same registers as in paragraph 2 above.
  398.  
  399.      Example:
  400.  
  401.      #pragma libcall SysBase OpenLibrary 228 0902
  402.  
  403. 2.8.2 Aztec/Maxon pragmas
  404. -------------------------
  405.      The library call pragmas available in the Aztec and Maxon compilers
  406. are built-up ike this:
  407.  
  408.      #pragma amicall(<lib base>,<index>,<name>(<parameters>))
  409.  
  410.      which means:
  411.  
  412.  <lib base>
  413.      The library base name to use.
  414.  
  415.  <index>
  416.      Function index of the library. A hexadecimal, positive number
  417.      (which is turned negative by the compiler when it generates the
  418.      indexed library call) with a "0x" prefix. Example: "0x1a" (The first
  419.      library function index of all normal libraries.)
  420.  
  421.  <name>
  422.      Function name identifier. Example: "MyFunction".
  423.  
  424.  <parameters>
  425.      Register/parameter information. It should be written as 'register,
  426.      register,register'. Example: "a1,d0"
  427.  
  428.      Example:
  429.  
  430.      #pragma amicall(SysBase,0x228,OpenLibrary(a1,d0))
  431.  
  432. 2.8.3 How to create pragma files
  433. --------------------------------
  434.      Most compilers have the pragma files included, and then there's no
  435. problem. But if you want to produce them for yourself, for your own library
  436. or for new versions of other libraries, most compilers have a utility
  437. called 'fd2pragma'. That utility uses function descriptor files (more
  438. details about those follow) as sources and generates pragma files. There is
  439. also a freely distributable program that can generate pragmas for Aztec,
  440. SAS, Dice and Maxon.
  441.  
  442.   
  443. 2.9 Near Data Effects
  444. ---------------------
  445.      Compilers of different programming languages often create machine
  446. language instructions that address data indexed by a 16-bit register,
  447. instead of straight 32-bit addressing, to increase execution speed and
  448. decrease the code size.
  449.  
  450.      Some libraries might request or offer a "callback function", a
  451. function supplied by you in the form of a function pointer that might get
  452. called from inside the library. A call from within a library may not have
  453. that index register set properly and therefore you must set it before you
  454. can access any data that requires that register!
  455.  
  456.      In SAS/C, this is simply done by defining the function like:
  457.  
  458.      void __saveds callback( void );
  459.  
  460.      if using DICE, __saveds must be replaced with __geta4.
  461.  
  462.      (In the SAS and Aztec compilers, it can also be done by calling
  463. geta4() first in the callback function.)
  464.  
  465.      From version 36 some of the AmigaDOS system library functions feature
  466. hook abilities, which is a kind of callback function. They are also called
  467. from inside a library and then of course also demand loading of the index
  468. register the same way.
  469.  
  470. 2.10 Registers
  471. --------------
  472.      Library functions should preserve the a2-a7 and d2-d7 registers. The
  473. rest must be stored in a safe place and then brought back after the library
  474. call if you want to be sure of their contents.
  475.  
  476.  
  477. 3.                  Parts of an AmigaDOS Shared Library Image
  478. -------------------------------------------------------------------------------
  479.  
  480.      If we were content with only using shared libraries, we would have
  481. enough information by now to use all kinds of library calls.
  482.      Only scratching the surface isn't enough if we want to create someting
  483. by ourselves. We must instead start digging into detailed information. How
  484. is a shared library constructed? Of which parts? How do you combine those
  485. parts to make your own shared library?
  486.  
  487.      A shared library image is built up by a few different parts:
  488.      - Code preventing execution
  489.      - ROMTag structure with sub data:
  490.      - Init table
  491.      - Function pointer table
  492.      - Data table
  493.      - Init routine
  494.      - Functions
  495.  
  496. 3.1 Prevent Execution
  497. ---------------------
  498.      The first thing the disk image contains is a piece of code that
  499. prevent users from trying to execute the library as an executable file.
  500. That piece of code should preferably return an error code to the calling
  501. environment (that most possibly is a shell).
  502.  
  503.      Example:
  504.  
  505.      moveq     #-1,d0
  506.      rts
  507.  
  508. 3.2 ROMTag Structure
  509. --------------------
  510.      Coming up next is a ROMTag structure. ROMTags are used to link system
  511. resident modules together. The ROMTag looks like:
  512.  
  513.      (found in <exec/resident.h>)
  514.  
  515.      struct Resident {
  516.        UWORD rt_MatchWord;
  517.        struct Resident *rt_MatchTag;
  518.        APTR  rt_EndSkip;
  519.        UBYTE rt_Flags;
  520.        UBYTE rt_Version;
  521.        UBYTE rt_Type;
  522.        BYTE  rt_Pri;
  523.        char  *rt_Name;
  524.        char  *rt_IdString;
  525.        APTR  rt_Init;
  526.      };
  527.  
  528.   rt_MatchWord -    Used by exec to find this structure when it is about
  529.                     to link us into the ROMTag list. This must contain
  530.                     RTC_MATCHWORD (the hexadecimal number 4AFC, which is
  531.                     a MC68000 "ILLEGAL" instruction).
  532.   rt_MatchTag -     This must contain a pointer to this struct.
  533.   rt_EndSkip -      Pointer to end of library init code.
  534.   rt_Flags -        RTF_AUTOINIT informs exec that this structure's
  535.                     'rt_Init' member points to an init table.
  536.   rt_Version -      Library version number
  537.   rt_Type -         Should contain NT_LIBRARY (found in <exec/nodes.h>),
  538.                     which informs exec about the fact that this is a
  539.                     shared library image.
  540.   rt_Pri -          Initialization priority. 0 (zero) is perfectly ok.
  541.   rt_Name -         Pointer to the zero terminated library name.
  542.   rt_IdString -     Standard name/version/date ID string. Example:
  543.                     "myown.library 1.0 (21.11.93)"
  544.   rt_Init -         This data points to an init table if
  545.                     RTF_AUTOINIT is set in structure member
  546.                     rt_Flags.
  547.  
  548.      As you can see, this structure requires some more information stored.
  549. You must have the library name and a standard ID string stored, and the
  550. last structure member should point to a "init table".
  551.  
  552. 3.3 Init Table
  553. --------------
  554.      The init table is a table of four longwords. I try to visualize them
  555. in a structure like this:
  556.  
  557.      (A struct of this kind is not found in any standard include file, this
  558. is written by me.)
  559.  
  560.      struct InitTable {
  561.        ULONG it_LibBaseSize;
  562.        APTR  it_FuncTable;
  563.        ULONG *it_DataTable;
  564.        APTR  it_InitRoutine;
  565.      };
  566.  
  567.   it_LibBaseSize -  Size of your library base structure. In common
  568.                     situations it is no point in using anything else but
  569.                     a straight struct Library as library base. It must not
  570.                     be smaller than that!
  571.   it_FuncTable -    This should contain a pointer to an array of
  572.                     function pointers.
  573.   it_DataTable -    Pointer to a data table in exec/InitStruct format for
  574.                     initialization of the Library base structure.
  575.   in_InitRoutine -  Pointer to a library initialization routine or NULL.
  576.  
  577.      Once again we have a structure that needs more data. The function
  578. pointer table, the data table and the init routine is left.
  579.  
  580. 3.4 Function Pointer Table
  581. --------------------------
  582.      This should be a table of function pointers to the different functions
  583. in the library. It can be specified in two ways:
  584.  
  585.   1) By setting the first word (16 bits) in the list to -1, you specify that
  586.      the table is a list with 16-bit addresses relative to the start of the
  587.      list. End the table with a -1 word.
  588.  
  589.   2) By storing absolute 32-bit pointers to the functions and ending
  590.      with a -1 longword (32 bits).
  591.  
  592.      My examples will use the second way.
  593.  
  594.      The pointers should point to the functions of the library. All
  595. libraries should still have a few standard functions used by exec and must
  596. not be left out. The first four entries are dedicated to such functions.
  597.  
  598.      The list must look like:
  599.  
  600.      - Open()     - Open library routine.
  601.      - Close()    - Close library routine.
  602.      - Expunge()  - Delete library from memory routine.
  603.      - Extfunc()  - Reserved for future expansion.
  604.      - own1()     - Our first function
  605.      - own2()     - Our second function
  606.      - ...        - The rest of our functions
  607.      - -1         - End of table
  608.  
  609.      How to program such functions is discussed further on. Let's continue,
  610. we have the data table and the init routine left to look at.
  611.  
  612. 3.5 Data Table
  613. --------------
  614.      The data table is used to initialize the library base structure when
  615. it's linked into the system list of shared libraries. The table is in the
  616. so called "exec/InitStruct" format. A data table is controlling a number of
  617. different initializing methods. In our case we just use a number of offsets
  618. (relative to the library base) and their initialization values.
  619.  
  620.      #include <exec/libraries.i>
  621.      #include <exec/initializers.i>
  622.      #include <exec/nodes.i>
  623.  
  624.      INITBYTE     LN_TYPE,NT_LIBRARY
  625.           ; Init type: Library.
  626.      INITLONG     LN_NAME,LibName
  627.           ; Init name of the library
  628.      INITBYTE     LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
  629.           ; Set the flags that tells exec we have changed
  630.           : the library and that we allow checksumming.
  631.      INITWORD     LIB_VERSION,VERSION
  632.           ; Init version
  633.      INITWORD     LIB_REVISION,REVISION
  634.           ; Init revision
  635.      INITLONG     LIB_IDSTRING,IDString
  636.           ; Init IDString
  637.      DC.L 0     ; End of InitStruct() command table
  638.  
  639.      If you have a larger library base than a Library struct, you might
  640. want to add more initialize entries to this table. The only thing left now
  641. to complete our ROMTag structure is the init routine.
  642.  
  643. 3.6 Init Routine
  644. ----------------
  645.      This routine gets called after the library has been allocated by
  646. exec. The library base pointer is in D0, the segment list is in A0 and
  647. SysBase in A6. This function must return the library base in D0 to be
  648. linked into the library list. If this initialization function fails, the
  649. library memory must be manually deallocated, then NULL returned in D0.
  650.  
  651.      Deallocate library memory by using something like:
  652.  
  653.      move.l    d0,a5
  654.      moveq     #0,d0
  655.      move.l    a5,a1
  656.      move.w    LIB_NEGSIZE(a5),d0
  657.  
  658.      sub.l     d0,a1
  659.      add.w     LIB_POSSIZE(a5),d0
  660.  
  661.      jsr       _LVOFreeMem(a6)
  662.  
  663.      The segment list, that we receive in A0, should be stored somewhere
  664. for later access. We'll need it when the library is to be removed from
  665. memory. Note that this routine will be called only once for every time the
  666. library is being loaded into memory. That makes it perfectly ok to store
  667. the segment list simply like:
  668.  
  669.      lea       anywhere(pc),a1
  670.      move.l    a0,(a1)
  671.      rts
  672.  
  673.      anywhere: DC.L 0
  674.  
  675.      A nice way to store this data is to extend the library base structure
  676. to hold the segment list pointer too.
  677.  
  678. This was the last of the initialization part. The ROMTag structure is
  679. complete. Left in the library are the functions that it should contain.
  680.  
  681. 3.7 Functions
  682. -------------
  683.      As mentioned before, there are four required functions that should be
  684. in all shared libraries. The rest of the functions are up to you to decide,
  685. design and make sure they receive proper data. How to code the functions
  686. and what to think of when doing so, is discussed in a chapter below.
  687.  
  688.  
  689. 4.                           Libraries in the System
  690. -------------------------------------------------------------------------------
  691.  
  692.      We know what shared libraries are and we are familiar with all data
  693. stored in the library image. We know what functions to use when we want to
  694. access libraries and we know how to call library functions.  What about low
  695. level information? What is done in the system when we call OpenLibrary()?
  696. How can I check if library already is loaded and which version number that
  697. library has? How can I patch a function of an already loaded library?
  698.  
  699. 4.1 Library Opening Details
  700. ---------------------------
  701.      When a single OpenLibrary() is called, a lot of things happen:
  702.  
  703.  1.  Exec checks the already loaded libraries to see if the requested
  704.      library is there. If it is, go to step 6.
  705.  
  706.  2.  If the library name is specified without path, it is searched for in
  707.      ROM, LIBS: and then current directory, otherwise simply in the
  708.      specified path. The first directory that holds a library with the
  709.      name it searches for, will be the one it loads from. If the library
  710.      wasn't found, return NULL. If the library was found anywhere
  711.      else but in ROM, it's LoadSeg()'ed into memory. ROM libraries
  712.      are already accessible.
  713.  
  714.  3.  Exec scans the library for the 4AFC word with a following 32-bit
  715.      pointer back to it. That word is the beginning of a ROMTag
  716.      structure!
  717.  
  718.  4.  InitResident() is called, which hopefully finds the
  719.      RTF_AUTOINIT flag set in the rt_Init member of the ROMTag
  720.      structure and therefore calls MakeLibrary() which performs:
  721.  
  722.      Memory is allocated to fit a jump table and the library base
  723.      structure. The size of the library base structure is found in the first
  724.      longword of the data table. The jump table is created by a call to
  725.      MakeFunctions() and is placed just before the library base in
  726.      memory. The size of the allocation can be read in the library base
  727.      structure (lib_NegSize + lib_PosSize).
  728.  
  729.      The library base structure is initialized using the data table list and
  730.      an InitStruct() call.
  731.  
  732.      The init routine is called with the library base pointer in D0,
  733.      SysBase in A6 and the segment list pointer in A0. If NULL is
  734.      returned, the entire OpenLibrary() fails and returns NULL.
  735.  
  736.      Notice that any kind of failure in InitResident() means that the
  737.      library is never added to the system.
  738.  
  739.  5.  AddLibrary() adds the library to the system list, making it
  740.      available to programs. The checksum of the library entries will be
  741.      calculated.
  742.  
  743.  6.  The OpenLibrary() call's version number parameter is checked
  744.      against the version number of the library base (lib_Version). If the
  745.      requested number is higher than the library version, OpenLibrary()
  746.      fails and returns NULL.
  747.  
  748.  7.  The open function of the library is called. If that fails NULL is
  749.      returned, otherwise the library base is returned in D0.
  750.  
  751.      If the same library exists in LIBS: with one version and in current
  752. directory with a later version, OpenLibrary() will always go for the one
  753. that it finds first. In this case that is the library in LIBS:. If that
  754. library has a too low version number, OpenLibrary() fails.
  755.  
  756.      As you can see, OpenLibrary() is a rather high level function. By
  757. using the other mentioned functions you can add a library to the system
  758. without going the way I describe in this article. But that wouldn't make it
  759. a standard shared library.
  760.  
  761. 4.2 Library List
  762. ----------------
  763.      Exec keeps track of all libraries that are opened. We can take part of
  764. exec's library list information by studying the linked list starting at
  765. SysBase->LibList. That pointer points to a `struct List', whose `struct
  766. Node' pointers point to the `struct Library' of all libraries that are
  767. currently in memory. This sounds more difficult than it is. Take a look at
  768. this small example.
  769.  
  770.      To find a certain library name in the library list, we can write:
  771.  
  772.      struct Library *findlib(char *name)
  773.      {
  774.        struct Library *lib;
  775.        Forbid();
  776.        lib = (struct Library *)FindName( SysBase->LibList, name );
  777.        Permit();
  778.        return( lib );
  779.      }
  780.  
  781. 4.3 Patching Libraries
  782. ----------------------
  783.      All libraries that are opened get a jump table created. That means
  784. that even ROM based libraries get a jump table in RAM. When using functions
  785. in any library, we always go through that jump table which consists of
  786. nothing but a number of JMP #ADDRESS instructions. As you understand, these
  787. jumps are supposed to jump into the library to perform whatever they are to
  788. perform.  By changing an entry in that jump table, we can make a certain
  789. library call to call our own function instead of the original! But to
  790. change an entry is more than just storing in the list (since there are
  791. checksums and things that have to be correct). The correct way to do it, is
  792. to use SetFunction(), which can make one of those JMPs jump to our own
  793. code.
  794.  
  795.      To replace OpenLibrary() with our own function, we can do it like:
  796.  
  797.      #include <exec/types.h>
  798.      #include <exec/protos.h>
  799.  
  800.      #ifdef SAS
  801.      /*
  802.       * Things to set for the SAS/C compiler:
  803.       */
  804.      #define ASM __asm
  805.      #define DREG(x) register __d ## x
  806.      #define AREG(x) register __a ## x
  807.  
  808.      #else
  809.      /*
  810.       * Defines for the Dice compiler:
  811.       */
  812.      #define ASM /* not used */
  813.      #define DREG(x) __D ## x
  814.      #define AREG(x) __A ## x
  815.  
  816.      #endif
  817.  
  818.      int ASM OurOpenLibrary(AREG(1) char *, DREG(0) int);
  819.      void patch(void)
  820.      {
  821.        APTR oldfunc;
  822.  
  823.        oldfunc = SetFunction((struct Library *)SysBase,
  824.                              -552,
  825.                              (APTR)OurOpenLibrary );
  826.  
  827.        /*
  828.         * Now, all following calls to OpenLibrary() will
  829.         * call our own function instead.
  830.         */
  831.  
  832.        /*
  833.         * To swap back, we simply use SetFunction()
  834.         * again. We really should be careful before
  835.         * doing so, because someone else might have
  836.         * patched the function after us, and if we
  837.         * simply restore our original we would ruin
  838.         * that patch!
  839.         */
  840.  
  841.        SetFunction( SysBase, -552, oldfunc );
  842.      }     
  843.  
  844.      int ASM OurOpenLibrary(AREG(1) char *libName,
  845.                             DREG(0) int version)
  846.      {
  847.      /*
  848.       * Code our own library opener. Do remember that
  849.       * our index register is not initialized now, and
  850.       * if you want it, make sure you can restore the
  851.       * previous value before returning from this
  852.       * function. We don't want to crash any programs,
  853.       * do we?
  854.       */
  855.  
  856.       /* Preserve used registers! */
  857.  
  858.      }
  859.  
  860.      Patching libraries are often used when creating debugging tools (such
  861. as the well-known `Mungwall' which patches AllocMem and FreeMem, `Snoopdos'
  862. which hangs on to most of dos.library's functions and others) and for
  863. programs that enhances or somehow changes the functionality of a function
  864. system wide (such as `Explodewindows' which patches OpenWindow() and
  865. beautifies window openings, `RTpatch' and `reqchange' which patches
  866. different requester calls to bring up reqtools.library requesters
  867. instead).
  868.  
  869. NOTE: SetFunction() cannot be used on non-standard libraries like pre-V36
  870. dos.library! If you want to patch such a library, you must manually Forbid(),
  871. preserve all 6 original bytes of the jump table entry, SumLibrary() (to
  872. evaluate the new checksum) and then Permit().
  873.  
  874.  
  875. 5.                                 Programming
  876. -------------------------------------------------------------------------------
  877.  
  878. 5.1 Functions
  879. -------------
  880.      Shared libraries must be programmed by someone. Until now, you've
  881. learned how to control, play around and change already existing libraries.
  882. Now, we'll check out more of what there is to know to be able to program a
  883. library. The ROMTag initializing is of course required when programming a
  884. library, but the biggest part and the part that really makes the library,
  885. is still the functions.
  886.  
  887.      You're not restricted to anything when it comes to the function of the
  888. routines you want to put in a shared library. What must be thought of when
  889. creating functions for a shared library using a compiler, is that there is
  890. no main function and no startup modules, and therefore no one of the
  891. symbols declared in those modules will be declared if you don't do it
  892. yourself.
  893.  
  894.      There are always four functions required that have to be in every
  895. library. They are Open(), Close(), Expunge() and Extfunc() and are called
  896. by exec when the library is to be opened, closed and removed from memory
  897. (the fourth is reserved for future use). Exec turns off task switching
  898. while executing these routines (via Forbid), so we should make them not
  899. take too long. (When using SAS/C these functions won't be necessary to
  900. code, see the "Compiling" and "Linking" chapters.)
  901.  
  902. 5.1.1 Open()     - (Library base:a6, version:d0)
  903.      This routine is called by exec when OpenLibrary() (or more
  904.      correct InitResident()) is called. Open should return the library
  905.      pointer in D0 if the open was successful. If the open fails, NULL
  906.      should be returned. It might fail in cases where we allocate
  907.      memory on each open, or if the library only can be open once at
  908.      a time...
  909.      Example:
  910.  
  911.      ; Increase the library's open counter
  912.      addq.w     #1,LIB_OPENCNT(a6)
  913.  
  914.      ; Switch off delayed expunge
  915.      bclr       #LIBB_DELEXP,LIB_FLAGS(a6)
  916.  
  917.      ; Return library base
  918.      move.l     a6,d0
  919.      rts
  920.  
  921. 5.1.2 Close()     - (Library base:a6)
  922.      This routine is called by exec when CloseLibrary() is called. If the
  923.      library is no longer open and there is a delayed expunge, then
  924.      Expunge! Otherwise Close should return NULL.
  925.      Example:
  926.  
  927.      ; Decrease the library's open counter
  928.      subq.w     #1,LIB_OPENCNT(a6)
  929.  
  930.      ; If there is anyone still open, return
  931.      bne.s      retlabel
  932.  
  933.      ; Is there a delayed expunge waiting?
  934.      btst       #LIBB_DELEXP,LIB_FLAGS(a6)
  935.      beq.s      retlabel
  936.  
  937.      ; Do the expunge!
  938.      bsr        Expunge
  939.  
  940.      retlabel:
  941.      ; set the return value
  942.      moveq      #0,d0
  943.  
  944.      rts
  945.  
  946. 5.1.3 Expunge()     - (Library base:a6)
  947.      This routine is called by exec when RemLibrary() is called, or
  948.      from Close when there was a delayed expunge. If the library is no
  949.      longer open then Expunge should Remove() itself from the library
  950.      list, FreeMem() the InitResident()'s allocation and return the
  951.      segment list (which was given to the Init routine). Otherwise
  952.      Expunge should set the delayed expunge flag and return NULL.
  953.  
  954.      Because Expunge might be called from the memory allocator, it
  955.      may NEVER Wait() or otherwise take long time to complete.
  956.  
  957.      Example:
  958.  
  959.      ; Is the library still open?
  960.      tst.w     LIB_OPENCNT(a6)
  961.      beq       notopen
  962.  
  963.      ; It is still open. set the delayed expunge flag
  964.      ; and return zero
  965.      bset      #LIBB_DELEXP,LIB_FLAGS(a6)
  966.      moveq     #0,d0
  967.      rts
  968.  
  969.      notopen: ; Get rid of us!
  970.  
  971.      movem.l   d2/a5/a6,-(sp)     ; save some registers
  972.      move.l    a6,a5
  973.  
  974.      ; Store our segment list in d2
  975.      lea     anywhere(pc),a6
  976.      move.l    (a6),d2
  977.  
  978.      move.l    4,a6     ; get SysBase
  979.  
  980.      ; Unlink from library list
  981.      move.l    a5,a1
  982.      jsr       _LVORemove(a6)     ; This removes our node from the list
  983.  
  984.      ; Free our memory
  985.      moveq     #0,d0
  986.      move.l    a5,a1
  987.      move.w    LIB_NEGSIZE(a5),d0 ; jump table size
  988.  
  989.      sub.l     d0,a1
  990.      add.w     LIB_POSSIZE(a5),d0 ; the size of the rest of the library.
  991.  
  992.      jsr       _LVOFreeMem(a6)
  993.  
  994.      ; Return the segment list
  995.      move.l    d2,d0
  996.  
  997.      movem.l   (sp)+,d2/a5/a6     ; Get back the registers
  998.      rts
  999.  
  1000. 5.1.4 Extfunc()     - (we don't know about any registers!)
  1001.      This routine is reserved for future use and should return 0 in
  1002.      register D0.
  1003.  
  1004.      Example:
  1005.  
  1006.      moveq #0,d0
  1007.      rts
  1008.  
  1009.  
  1010. 5.2 Function Descriptor File
  1011. ----------------------------
  1012.      To easily use the SAS/C options for creating a shared library or using
  1013. the pragma construction utilities, a standard AmigaDOS function descriptor
  1014. file is required. It describes the functions in a library like:
  1015.  
  1016.      ##base _OwnBase
  1017.      ##bias 30
  1018.      ##public
  1019.      * ---- Here follows the public functions ----
  1020.      OwnFunction(name,age)(A0/D2)
  1021.      OwnFoobar(daynumber,dayname)(D1/A3)
  1022.      ##private
  1023.      * ---- Private! Hands off
  1024.      OwnPrivate(things)(a1)
  1025.      ##end
  1026.  
  1027.      Where:
  1028.  
  1029.      ##base -  The library base identifier
  1030.  
  1031.      ##bias -  Index base position. The first function specified
  1032.                will use this index, which should be positive
  1033.                (turned negative later by the compiler) and in all
  1034.                normal cases starts on the first free jump table
  1035.                entry: 30.
  1036.  
  1037.      ##public -    The functions following are public functions that
  1038.                    everybody is allowed to use.
  1039.  
  1040.      ##private -   Private functions follow. Such functions should
  1041.                    not be messed with and we won't get any information
  1042.                    on those.
  1043.  
  1044.      * -           All lines starting with an asterisc '*' are treated
  1045.                    as comments.
  1046.  
  1047.      functionname(name1,name2)(register1/register2) -
  1048.           Describes the parameters and in which registers the function
  1049.           received the parameters in. The entire line should be written
  1050.           without whitespaces as in the example above. The registers
  1051.           should be written like: d0/a1/d2. The parameter names are only
  1052.           for documentation use.
  1053.  
  1054.      ##end -   end of function descriptor file
  1055.  
  1056. 5.3 Glue Code
  1057. -------------
  1058.      Glue code is written to be called with the parameters on the stack
  1059. instead of the registers as it should. The glue functions should pick
  1060. parameters from the stack and assign to the proper registers.
  1061.  
  1062.      Example:
  1063.  
  1064.      move.l     a1,-(sp)  ; Store register A1 on stack
  1065.      move.l     a6,-(sp)  ; Store register A6 on stack
  1066.      move.l     12(sp),a1 ; Get first argument from stack to a1
  1067.      move.l     16(sp),d0 ; Get second argument from stack to d0
  1068.      move.l     4,a6      ; Get SysBase in A6.
  1069.      jsr     _LVOOpenLibrary(a6) ; Call OpenLibrary()
  1070.           ; Now d0 contains the result code from the
  1071.           ; library call
  1072.      move.l     (sp)+,a6  ; Restore A6 from stack
  1073.      move.l     (sp)+,a1  ; Restore A1 from stack
  1074.      rts
  1075.  
  1076. 5.4 Compiling
  1077. -------------
  1078.      Things to think of when compiling library code:
  1079.  
  1080.  *   Always make the function called from another process (the
  1081.      outside) a "__saveds" function as the index register has to be
  1082.      properly initialized before continuing. __saveds should be replaced
  1083.      with __geta4 when using Dice and an initial 'geta4()' call when
  1084.      using Aztec C.
  1085.  
  1086.  *   Whether to use global symbols unique or shared by every task.
  1087.      SAS/C features easy changing between these two, but other
  1088.      compilers might have trouble creating unique global variables for
  1089.      each library open.
  1090.  
  1091.  *   Options when compiling a library may include some of the
  1092.      following. (These are the SAS/C options, but all compilers of
  1093.      today offer simlar functionalities.):
  1094.  
  1095.      LIBCODE        Forces all index addressing to use
  1096.                     the library base pointer (a6) instead
  1097.                     of the standard a4.
  1098.  
  1099.      NOSTANDARDIO   Do not use any of the C standard io
  1100.                     functions such as printf() or
  1101.                     fprintf(stderr, ...) since they rely on
  1102.                     global symbols declared and
  1103.                     initialized in the startup module.
  1104.  
  1105.      OPTIMIZE       Optimize the output code.
  1106.  
  1107. 5.5 Linking
  1108. -----------
  1109.      Linking a library often causes many problems, at least it has done so
  1110. for me. You must remember that no compiler startup symbols will exist
  1111. unless you declare them (or use a compiler that enables such things, like
  1112. SAS/C v6.50 and later)! Things like stack expansions can't be made to work,
  1113. and routines like fopen() and others are using startup module symbols
  1114. (which can be declared by us though).
  1115.  
  1116.      With the symbols in mind, we continue! All the talk about the library
  1117. initializer structures is no problem of a SAS/C programmer's mind. By
  1118. including the following flags in your `slink' line, all such problems are
  1119. solved:
  1120.  
  1121. * LIBPREFIX <prefix>
  1122.      Default is `_' (underscore). This is the prefix added to the
  1123.      functions specified in the function descriptor file to match the
  1124.      symbols of the object file(s).
  1125.  
  1126. * LIBFD <function desc file>
  1127.      Tells where the function descriptor file is.
  1128.  
  1129. * FROM lib:libent.o lib:libinit.o
  1130.      Two nice object files holding code that we would have to code by
  1131.      ourselves otherwise. If you are using global variables in your
  1132.      code, "libinit.o" will make all currently open sessions of the
  1133.      library access the same, shared, variable. By using "libinitr.o" all
  1134.      globals will be copied at the library open, thus each open library
  1135.      has its own global variables.
  1136.  
  1137. * LIBID
  1138.      Sets the IdString of the library
  1139.  
  1140. * LIBVERSION <number>
  1141.      Sets the version number of the library
  1142.  
  1143. * LIBREVISION <number>
  1144.      Sets the revision number of the library
  1145.  
  1146. 5.6 Debugging
  1147. -------------
  1148.      Using SAS/C, shared libraries can be run time debugged (including
  1149. variable checking, break-pointing and so on) just like any other program
  1150. using the "step into reslib" option in `cpr'. Break any library function by
  1151. writing "b myown.library:foobar" (where foobar is the name of the function
  1152. we want cpr to stop in when we enter) on the command prompt of `cpr'. When
  1153. creating debug code, remember to debug the library that exists in the same
  1154. directory as the code does, or specify the compiler flag SOURCEIS= and the
  1155. name of your source file.
  1156.  
  1157. 5.7 Hints
  1158. ---------
  1159.      I have been programming and developing shared libraries for some time
  1160. by now, and there are a few things to pay certain attention to when dealing
  1161. with this stuff.
  1162.  
  1163.   - Flush before retry
  1164.      Libraries don't go away simply because you close them, you
  1165.      know that. If you run your library once, close it and recompile it
  1166.      with a few changes, there will still be the older version remaining
  1167.      in memory that will be opened. When debugging libraries, always
  1168.      make sure that your library isn't already in memory before
  1169.      debugging a new version!
  1170.  
  1171.      I made a small program that resets the open counter and then
  1172.      RemLibrary() a named library. It is not at all a nice thing to do,
  1173.      but there really is a problem when you open your library and
  1174.      something crashes before you have had the chance to close it.
  1175.      There is no "nice" way of removing such a library from memory!
  1176.  
  1177.   - Globals
  1178.      By using the SAS/C object files libinit.o or libinitr.o you can
  1179.      make your global variables to be shared by all processes or unique
  1180.      for each OpenLibrary() call. If you want to mix the two versions
  1181.      or create something different, I advise you to code the library
  1182.      initial code by yourself.
  1183.  
  1184.   - Stack usage
  1185.      When your library is called and runs, it uses the same stack as the
  1186.      caller. If the caller has a very small stack, so do you. Built-in
  1187.      stack check routines are not available since they need irreplaceable
  1188.      symbols. For advanced users, allocating and using an own stack
  1189.      while the library is running could be the only and best way to
  1190.      solve a problem like this.
  1191.  
  1192.   - Symbols
  1193.      I've written it earlier and I do it again: high level language
  1194.      functions often use symbols initialized and declared in the startup
  1195.      modules. Declare them by yourself if possible or avoid using such
  1196.      functions!
  1197.  
  1198.   - Register preservation
  1199.      I think it's a good habit to always preserve all registers (except
  1200.      for D0 that holds the return code) when your library routines are
  1201.      called. Remember that your library code index register is
  1202.      un-initialized when called from the library opener.
  1203.  
  1204.  
  1205. 6                       Support library calls from ARexx
  1206. -------------------------------------------------------------------------------
  1207.     ARexx is since the introduction of AmigaDOS 2.0 a part of the operating
  1208. system, and is for earlier releases available as a separate product.
  1209.  
  1210.     ARexx can access and call functions in shared libraries, if the shared
  1211. libraries support it. This section will describe the actions that have to
  1212. be taken to make your library support function invokes from ARexx.
  1213.  
  1214.  
  1215. 6.1 How ARexx access the library
  1216. --------------------------------
  1217.     To access a custom shared library from ARexx, the ARexx program must
  1218. call 'addlib' specifying library, version and "ARexx entry index". That
  1219. third parameter is the index relative the librarybase to the function that
  1220. is used for ARexx communication.
  1221.  
  1222. 6.2 ARexx calls a library function
  1223. ----------------------------------
  1224.     When a function is used within an ARexx program which the ARexx
  1225. interpreter does not recognize, ARexx will call all libraries, one at a
  1226. time, to see if the library recognizes the function. The first library that
  1227. recognizes the function runs it!
  1228.  
  1229. 6.3 ARexx function
  1230. ------------------
  1231.     The function that gets called from ARexx will receive a RexxMsg(1)
  1232. pointer in register A0. The ARG0 member of the RexxMsg holds the name of
  1233. the function that ARexx wants to run (the comparison should be case
  1234. independent), and the parameters to the function is put in ARG1-ARG15. If
  1235. your library doesn't recognize the function, you should return with 1 set
  1236. in register D0, otherwise you should run the function with the specified
  1237. parameters and return error in D0 (0=OK, 5=WARN etc). When returning OK,
  1238. you can return a result string by putting a pointer to an ArgString(2) in
  1239. A1, otherwise set A1 to 0 (zero).
  1240.  
  1241. (1) = See proper ARexx header file for "struct RexxMsg" definition.
  1242. (2) = See documentation for rexxsyslib.library/CreateArgstring().
  1243.  
  1244.  
  1245.                                      Appendix
  1246. -------------------------------------------------------------------------------
  1247.  
  1248. A. Version numbers and shared libraries
  1249. ---------------------------------------
  1250.  
  1251.      Commodore has introduced a general standard for shared library version
  1252. numbering. The libversion number is the number of the library version. The
  1253. librevision number is expected to be a counter from 0 and upwards, without
  1254. any kind of preceding zero. This makes the first library version 1.0 and
  1255. such as 1.9 is followed by 1.10, 1.11 and so on all the way to the maximum,
  1256. of the same version, 1.65535.
  1257.  
  1258.      Failing in the version number check of a library opening leaves the
  1259. library in memory. For example, when you want to open "myown.library", it's
  1260. loaded into memory. If the version number check fails and you get a NULL in
  1261. return, "myown.library" will still remain loaded. The 'FILE' command line
  1262. option does tell 'version' to explicitly use the file specified.
  1263.  
  1264.      There are utilities which automatically updates a source file with the
  1265. version number, revision number and the IDstring on every invoke.
  1266. `bumprev' is one.
  1267.  
  1268. B. Further reading
  1269. ------------------
  1270.  
  1271.     * Amiga ROM Kernel Reference Manual: Libraries, 3rd edition.
  1272.  
  1273.     * Amiga ROM Kernel Reference Manual: Includes & Autodocs, 3rd edition.
  1274.  
  1275.  
  1276. C. Library source examples
  1277. --------------------------
  1278.  
  1279.     Here follows a few example source codes. These are put here as simple
  1280. examples of how it can be done. It may not be the best or most suitable
  1281. solution for your imaginary project, but gives you a hint about how things
  1282. can be done. The library created with the sources below is called
  1283. "myown.library"
  1284.     The sources are:
  1285.  
  1286.    * Makefile A -       A makefile written as a SAS/C v6+ user would have
  1287.                         written it when compiling a library.
  1288.  
  1289.    * Makefile B -       A more general makefile. Change it to fit your
  1290.                         particular compiler and assembler.
  1291.  
  1292.    * myownass.a -       An library entry source code in assembler. This
  1293.                         contains all important initial structures and the
  1294.                         four required functions.
  1295.  
  1296.    * sasanddice.h -     A header file to include in the following C sources
  1297.                         to enable compilings under both SAS/C and Dice.
  1298.  
  1299.    * myowninit.c -      A C source version of the four required functions.
  1300.                         These are included for those not too familiar with
  1301.                         assembler.
  1302.  
  1303.    * myown.h -          Header file for the myown.library functions.
  1304.  
  1305.    * myown.c -          myown.library function source.
  1306.  
  1307.    * myown.fd -         Function descriptor file for myown.library.
  1308.  
  1309.    * myown_pragmas.h -  SAS/C pragmas for the library functions.
  1310.  
  1311.    * uselibrary.c -     A small program that uses the functions in
  1312.                         myown.library.
  1313.  
  1314.  
  1315.      Makefile A
  1316.      ==========
  1317.  
  1318.      # This makefile uses the standard way of making a
  1319.      # shared library with SAS/C. Using the already
  1320.      # created object files SAS supports us with.
  1321.  
  1322.      CC      = sc
  1323.      CHEADER = myown.h
  1324.      CSOURCE = myown.c
  1325.      OBJ     = myown.o
  1326.      LIBRARY = myown.library
  1327.      FLAGS   = STRINGMERGE NOSTKCHK NOSTANDARDIO\
  1328.             DATA=NEAR NOVERSION LIBCODE\
  1329.             OPTIMIZE
  1330.  
  1331.      $(LIBRARY): $(OBJ)
  1332.            slink with <<
  1333.           LIBFD myown.fd
  1334.           to $(LIBRARY)
  1335.           FROM lib:libent.o lib:libinit.o $(OBJ)
  1336.           noicons
  1337.           SD SC
  1338.           libid "myown.library 2.1 (18.04.93)"
  1339.           libversion 2 librevision 1
  1340.      <
  1341.      copy $(LIBRARY) LIBS: CLONE # Copy library to LIBS:
  1342.  
  1343.      $(OBJ): $(CSOURCE) $(CHEADER)
  1344.           $(CC) $(FLAGS) $*.c
  1345.  
  1346.      Makefile B
  1347.      ==========
  1348.      # This makefile compiles everything and uses no
  1349.      # pre-compiled files.
  1350.      # Easy changed to fit DICE, Aztec or other
  1351.      # compilers and assemblers.
  1352.  
  1353.      CC      = sc
  1354.      CHEADER = myown.h
  1355.      CSOURCE = myown.c
  1356.      ASOURCE = myownass.a
  1357.      OBJS    = myown.o myownass.o
  1358.      LIBRARY = myown.library
  1359.      FLAGS   = STRINGMERGE NOSTKCHK NOSTANDARDIO\
  1360.             DATA=NEAR NOVERSION LIBCODE\
  1361.             OPTIMIZE
  1362.      ASM     = asm
  1363.      ASMFLAGS= -iINCLUDE:
  1364.  
  1365.      $(LIBRARY): $(OBJS)
  1366.            slink to $(LIBRARY) FROM $(OBJS) noicons SD SC
  1367.            copy $(LIBRARY) LIBS: CLONE # Copy library to LIBS:
  1368.  
  1369.      myown.o: $(CSOURCE) $(CHEADER)
  1370.           $(CC) $(FLAGS) $*.c
  1371.  
  1372.      myownass.o: $(ASOURCE)
  1373.           $(ASM) $(ASMFLAGS) $*.a
  1374.  
  1375.  
  1376.      myownass.a
  1377.      ===========
  1378.  
  1379.      ************************************************
  1380.      *
  1381.      * myown.library assembler source code
  1382.      *
  1383.      ************************************************
  1384.      * Author: Daniel Stenberg (dast@sth.frontec.se)
  1385.      ************************************************
  1386.  
  1387.         SECTION     code
  1388.  
  1389.         NOLIST
  1390.         INCLUDE "exec/exec_lib.i"
  1391.         INCLUDE "exec/types.i"
  1392.         INCLUDE "exec/initializers.i"
  1393.         INCLUDE "exec/libraries.i"
  1394.         INCLUDE "exec/lists.i"
  1395.         INCLUDE "exec/alerts.i"
  1396.         INCLUDE "exec/resident.i"
  1397.         INCLUDE "libraries/dos.i"
  1398.  
  1399.         LIST
  1400.  
  1401.         XDEF InitTable
  1402.         XDEF Open
  1403.         XDEF Close
  1404.         XDEF Expunge
  1405.         XDEF LibName
  1406.  
  1407.         XREF _SysBase
  1408.  
  1409.         XREF _LVOOpenLibrary
  1410.         XREF _LVOCloseLibrary
  1411.         XREF _LVOAlert
  1412.         XREF _LVOFreeMem
  1413.         XREF _LVORemove
  1414.      
  1415.         XREF _Min
  1416.         XREF _Abs
  1417.      
  1418.         ; Prevent library execution:
  1419.      
  1420.      Prevent:
  1421.         MoveQ #-1,d0
  1422.         rts
  1423.      
  1424.      ;-----------------------------------------------
  1425.      ; The romtag structure is next:
  1426.      ;-----------------------------------------------
  1427.      
  1428.      MYPRI EQU 0     ; priority zero...
  1429.  
  1430.      VERSION EQU 2   ; version 2
  1431.  
  1432.      REVISION EQU 1  ; revision 1
  1433.  
  1434.      RomTag:
  1435.                ;STRUCTURE RT,0
  1436.         dc.w RTC_MATCHWORD ; UWORD RT_MATCHWORD
  1437.         dc.l RomTag        ; APTR  RT_MATCHTAG
  1438.         dc.l EndCode       ; APTR  RT_ENDSKIP
  1439.         dc.b RTF_AUTOINIT  ; UBYTE RT_FLAGS
  1440.         dc.b VERSION       ; UBYTE RT_VERSION
  1441.         dc.b NT_LIBRARY    ; UBYTE RT_TYPE
  1442.         dc.b MYPRI         ; BYTE  RT_PRI
  1443.         dc.l LibName       ; APTR  RT_NAME
  1444.         dc.l IDString      ; APTR  RT_IDSTRING
  1445.         dc.l InitTable     ; APTR  RT_INIT
  1446.      
  1447.      ; the name of our library
  1448.      LibName:
  1449.         dc.b 'myown.library',0
  1450.      
  1451.      ; standard name/version/date ID string
  1452.      IDString:
  1453.         dc.b 'myown.library 2.1 (21.11.93)',13,10,0
  1454.      
  1455.      ; force word alignment
  1456.         ds.w 0
  1457.      
  1458.      ; The init table
  1459.      InitTable:
  1460.         dc.l LIB_SIZEOF  ; size of library base data, sizeof(struct Library)
  1461.         dc.l funcTable   ; pointer function pointer table below
  1462.         dc.l dataTable   ; pointer to the library data initializer table
  1463.         dc.l initRoutine ; routine to run
  1464.      
  1465.      funcTable:
  1466.      
  1467.         ;----- standard system routines
  1468.         dc.l Open
  1469.         dc.l Close
  1470.         dc.l Expunge
  1471.         dc.l Extfunc
  1472.      
  1473.         ;----- our library functions
  1474.         ;The function names get those `_' in the
  1475.         ;beginning when compiling in C.
  1476.         dc.l _Min
  1477.         dc.l _Abs
  1478.      
  1479.         ;----- function table end marker
  1480.         dc.l -1
  1481.      
  1482.      
  1483.      ; The data table initializers static data structs.
  1484.      dataTable:
  1485.         INITBYTE     LN_TYPE,NT_LIBRARY
  1486.         INITLONG     LN_NAME,LibName
  1487.         INITBYTE     LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
  1488.         INITWORD     LIB_VERSION,VERSION
  1489.         INITWORD     LIB_REVISION,REVISION
  1490.         INITLONG     LIB_IDSTRING,IDString
  1491.         dc.l 0
  1492.      
  1493.      ; The init routine.
  1494.      initRoutine:     ; (segment list:a0)
  1495.         move.l a5,-(sp)       ; save a5
  1496.         lea    seglist(pc),a5 ; get address of our seglist storage
  1497.         move.l a0,(a5)        ; store segment list pointer
  1498.         move.l (sp)+,a5       ; restore previous a5
  1499.         move.l #0,d0          ; return zero
  1500.         rts
  1501.      
  1502.      seglist:
  1503.         dc.l 0
  1504.  
  1505.      ;---------------------------------------------
  1506.      ; The four required functions:
  1507.      ; ****Assembler source code version****
  1508.      ;---------------------------------------------
  1509.      
  1510.      Open:     ; (libptr:A6, version:D0)
  1511.      
  1512.        ; Increase the library's open counter
  1513.        addq.w   #1,LIB_OPENCNT(a6)
  1514.  
  1515.        ; Clear delayed expunges (standard procedure)
  1516.        bclr     #LIBB_DELEXP,LIB_FLAGS(a6)
  1517.  
  1518.        ; Return library base
  1519.        move.l   a6,d0
  1520.        rts
  1521.      
  1522.      Close:     ; (libptr:a6)
  1523.      
  1524.        ; set the return value
  1525.        moveq    #0,d0
  1526.  
  1527.        ; Decrease the library's open counter
  1528.        subq.w   #1,LIB_OPENCNT(a6)
  1529.  
  1530.        ; If there is anyone still open, return
  1531.        bne.s    retlabel
  1532.  
  1533.        ; Is there a delayed expunge waiting?
  1534.        btst     #LIBB_DELEXP,LIB_FLAGS(a6)
  1535.        beq.s    retlabel
  1536.  
  1537.        ; Do the expunge!
  1538.        bsr      Expunge ; returns the segment list
  1539.  
  1540.        retlabel:
  1541.        rts
  1542.      
  1543.      Expunge:     ; (libptr:a6)
  1544.      
  1545.        ; Is the library still open?
  1546.        tst.w    LIB_OPENCNT(a6)
  1547.        beq      notopen
  1548.  
  1549.        ; It is still open. set the delayed expunge flag
  1550.        ; and return zero
  1551.        bset     #LIBB_DELEXP,LIB_FLAGS(a6)
  1552.        moveq    #0,d0
  1553.        rts      ; return
  1554.  
  1555.        notopen: ; Get rid of us!
  1556.  
  1557.        movem.l  d2/a5/a6,-(sp) ; save some registers
  1558.        move.l   a6,a5
  1559.  
  1560.        ; Store our segment list in d2
  1561.        lea      seglist(pc),a6
  1562.        move.l   (a6),d2
  1563.  
  1564.        move.l   4,a6     ; get SysBase
  1565.  
  1566.        ; Unlink from library list
  1567.        move.l   a5,a1
  1568.        jsr      _LVORemove(a6) ; This removes our node from the list
  1569.  
  1570.        ; Free our memory
  1571.        moveq    #0,d0
  1572.        move.l   a5,a1
  1573.        move.w   LIB_NEGSIZE(a5),d0
  1574.  
  1575.        sub.l    d0,a1
  1576.        add.w    LIB_POSSIZE(a5),d0
  1577.  
  1578.        jsr      _LVOFreeMem(a6) ; This frees the memory we occupied
  1579.  
  1580.        ; Return the segment list
  1581.        move.l   d2,d0
  1582.  
  1583.        movem.l  (sp)+,d2/a5/a6 ; Get back the registers
  1584.        rts
  1585.      
  1586.      Extfunc:     ; should return zero
  1587.         moveq   #0,d0
  1588.         rts
  1589.      
  1590.         ; EndCode is a marker that show the end of our
  1591.         ; code.
  1592.      EndCode:
  1593.         END
  1594.  
  1595.  
  1596.      sasanddice.h
  1597.      ============
  1598.  
  1599.      /**********************************************
  1600.      *
  1601.      * Set some defines to enable either SAS or Dice
  1602.      * compilings.
  1603.      *
  1604.      ***********************************************/
  1605.  
  1606.      #ifdef SAS
  1607.      /*
  1608.       * Things to set for the SAS/C compiler:
  1609.       */
  1610.      #define ASM __asm
  1611.      #define DREG(x) register __d ## x
  1612.      #define AREG(x) register __a ## x
  1613.  
  1614.      #else
  1615.      /*
  1616.       * Defines for the Dice compiler:
  1617.       */
  1618.      #define ASM /* not used */
  1619.      #define DREG(x) __D ## x
  1620.      #define AREG(x) __D ## x
  1621.      #endif
  1622.  
  1623.      myowninit.c
  1624.      ===========
  1625.  
  1626.      /**********************************************
  1627.      *
  1628.      * The four required library functions
  1629.      * C source code version (SAS and Dice)
  1630.      *
  1631.      ***********************************************/
  1632.  
  1633.      #include "sasanddice.h"
  1634.  
  1635.      long ASM Open(AREG(6) struct Library *MyBase)
  1636.      {
  1637.        /* Increase the library's open counter */
  1638.        MyBase->lib_OpenCnt++;
  1639.  
  1640.        /* Clear delayed expunges (standard procedure) */
  1641.        MyBase->lib_Flags &= ~LIBF_DELEXP;
  1642.  
  1643.        return MyBase; /* return library base */
  1644.      }
  1645.  
  1646.      struct Library * ASM Close(AREG(6) struct Library *MyBase)
  1647.      {
  1648.         struct Library *ret=NULL;
  1649.  
  1650.         /* Decrease the library's open counter */
  1651.         MyBase->lib_OpenCnt--;
  1652.  
  1653.         if(!MyBase->lib_OpenCnt) {
  1654.           /* not opened any more */
  1655.  
  1656.           if(MyBase->lib_Flags & LIBF_DELEXP)
  1657.             /* There is a delayed expunge waiting */
  1658.             ret = Expunge( MyBase );
  1659.         }
  1660.         return ret;
  1661.      }
  1662.  
  1663.      ULONG ASM Expunge( AREG(6) struct Library *MyBase )
  1664.      {
  1665.         ULONG ret=NULL;
  1666.         long size;
  1667.         if(MyBase->lib_OpenCnt == 0) {
  1668.           /* we are not opened */
  1669.  
  1670.           ret = seglist; /* the 'seglist' we stored in the assembler init
  1671.                             routine! */
  1672.           /* remove us from the list */
  1673.           Remove ( (struct Node *) MyBase);
  1674.  
  1675.           /* get size to FreeMem() */
  1676.           size = MyBase->lib_NegSize + MyBase->lib_PosSize;
  1677.  
  1678.           /* FreeMem() */
  1679.           FreeMem( (char *) MyBase-MyBase->lib_NegSize, size );
  1680.  
  1681.         } else
  1682.           /* we are opened */
  1683.           MyBase->lib_Flags |= LIBF_DELEXP;
  1684.      }
  1685.  
  1686.      long ExtFunc()
  1687.      {
  1688.        /* reserved for future use, should return 0 */
  1689.        return 0;
  1690.      }
  1691.  
  1692.      myown.h
  1693.      =======
  1694.  
  1695.      /***********************************************
  1696.      *
  1697.      * myown.library header file
  1698.      *
  1699.      ************************************************
  1700.  
  1701.      /* Library function prototypes */
  1702.  
  1703.      int Min(int, int); /* return minimum value */
  1704.      int Abs(int);      /* return absolute value */
  1705.  
  1706.  
  1707.      myown.c
  1708.      =======
  1709.  
  1710.      /***********************************************
  1711.      *
  1712.      * myown.library functions source code
  1713.      *
  1714.      ************************************************
  1715.  
  1716.      #include "sasanddice.h"
  1717.  
  1718.      int ASM Min(DREG(0) int a,
  1719.                  DREG(1) int b)
  1720.      {
  1721.        int c = a < b ? a : b;
  1722.  
  1723.        return (c);
  1724.      }
  1725.  
  1726.      int ASM Abs(REG(0) int a)
  1727.      {
  1728.        int c = a < 0 ? -a : a;
  1729.  
  1730.        return (c);
  1731.      }
  1732.  
  1733.      myown.fd
  1734.      ========
  1735.  
  1736.      ##base _MyBase
  1737.      ##bias 30
  1738.      ##public
  1739.      Min(num,num)(D0/D1)
  1740.      Abs(num)(D0)
  1741.      ##end
  1742.  
  1743.  
  1744.      myown_pragmas.h
  1745.      ===============
  1746.  
  1747.      /* pragmas */
  1748.  
  1749.      #if defined(SAS) || defined(DICE)
  1750.  
  1751.      #pragma libcall MyBase Min 1E 1002 /* d0 and d1 */
  1752.      #pragma libcall MyBase Abs 24 001  /* only d0 */
  1753.  
  1754.      #elif defined(MAXON) || defined(AZTEC)
  1755.  
  1756.      #pragma amicall(MyBase,0x1e,Min(d0,d1))
  1757.      #pragma amicall(MyBase,0x24,Abs(d0))
  1758.  
  1759.      #endif
  1760.  
  1761.      uselibrary.c
  1762.      ============
  1763.  
  1764.      #include "myown_pragmas.h" /* if using SAS/C or Aztec C */
  1765.      #include "myown.h"
  1766.      struct Library *MyBase=NULL;
  1767.  
  1768.      void main(void)
  1769.      {
  1770.        int min, abs;
  1771.        MyBase=OpenLibrary("myown.library", 2);
  1772.  
  1773.        if(MyBase) {
  1774.          min = Min( 3, 2 ); /* library Min() function */
  1775.          abs = Abs( -12 );  /* library Abs() function */
  1776.  
  1777.          CloseLibrary( MyBase );
  1778.        } else
  1779.          printf("Couldn't open myown.library!\n");
  1780.      }
  1781.