home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / programm / programi / saslib.lzh / saslib.doc < prev    next >
Text File  |  1992-02-02  |  19KB  |  500 lines

  1.  
  2. Amiga shared libraries under SAS/C - the easy way
  3. =================================================
  4.  
  5. Questions, comments, etc. can be directed to:
  6.  
  7.     David Jones
  8.     6730 Tooney Drive
  9.     Orleans, Ont.
  10.     K1C 6R4
  11.     CANADA
  12.     
  13.     dej@qpoint.amiga.ocunix.on.ca
  14.     David_Jones@p8,f109.n163.z1.fidonet.org
  15.     David Jones @ Fidonet#1:163/109.8
  16.  
  17.  
  18. IMPORTANT NOTICE:
  19. ----------------
  20.  
  21. The files in this archive are released under the terms and conditions
  22. of the Free Software Foundation's General Library Public License.
  23. Release 2 (June 1991) or any later version shall apply.
  24. This license is included in this archive under the name "gpll.doc".
  25. Read the terms and conditions of this license before using this archive!
  26.  
  27. In particular, there is NO WARRANTY of any kind associated with this
  28. software.
  29.  
  30.  
  31. The problem:
  32. -----------
  33.  
  34. You want to create a library that can be opened by OpenLibrary - an
  35. Amiga shared library.  You've looked in the RKMs and you investigated
  36. the ability of the SAS compiler to make libraries.  And you've pulled
  37. your hair out.  And screamed.  And...
  38.  
  39. Stop.  This is what you've been looking for.  It's foolproof.  The routines
  40. in this file have been designed to be easy to interface to.  The library
  41. code isn't the most compact or the most efficient, but the process is
  42. PAINLESS.
  43.  
  44. Read on and I guarantee you'll have a library easier than you've ever
  45. had it before.  NO knowledge of assembly language is required, although
  46. it helps for debugging.  If you have any problems, feel free to vent your
  47. frustrations to the mail addresses above.
  48.  
  49. One final thing: ignore everything about library generation in the
  50. SAS manual unless I say otherwise.  It's a jungle in there.
  51.  
  52.  
  53. Before you start:
  54. ----------------
  55.  
  56. You will need the following in addition to the files in this archive:
  57.  
  58.     SAS/C compiler for AmigaDOS, Version 5.x
  59.     A68K, by Charlie Gibbs
  60.  
  61. I would have liked to use the SAS assembler, but it is my opinion that
  62. it is broken.  So is A68K, but at least it's usable.  The SAS assembler
  63. isn't.
  64.  
  65.  
  66. Some hints when writing your code:
  67. ---------------------------------
  68.  
  69. Try to write the code as a linker library first.  As long as it's
  70. incorporated into the body of programs that call it, CPR can list
  71. its source and you can easily debug it.  Once it's resident in the
  72. Exec library list, it can be VERY difficult to do source level debugging.
  73. Get your functions working BEFORE making it into a shared library.
  74.  
  75. Remember that you're not writing an application; you're writing a library.
  76. Don't call any of the SAS I/O or memory functions unless you know what
  77. you are doing.  They depend on globals that are in the standard SAS/C
  78. startup code but are not in the library code, and for good reason.
  79. Libraries aren't processes.  If the linker complains about globals that
  80. you've never heard of, then look for calls to SAS library functions.
  81.  
  82. By the same token, be kind to the OS.  Do not assume that you're a
  83. process free to call DOS functions unless you specifically want your
  84. library to be callable from processes.  Do not call ANY functions that may
  85. directly or indirectly do a Wait() inside the init and expunge functions
  86. (discussed later).
  87.  
  88.  
  89. Now, to create the library:
  90. --------------------------
  91.  
  92. The files in this archive constitute the support required to create
  93. shared libraries.  Here is the contents of the archive:
  94.  
  95.     dejmac.i
  96.     exec.offsets
  97.     libhdr.a
  98.         These files are assembler files that create the library interface
  99.         code.  You do not need to change any of these.
  100.  
  101.     libinf.a
  102.         This is the file that you will need to change.  It gives ALL of
  103.         the information about the library.  Although it's assembly, I
  104.         will take you through it step by step.
  105.     makefile
  106.         This is the makefile for LMK.  It gives the necessary compiler
  107.         flags and link files.
  108.  
  109.     demo.fd
  110.     demo.library
  111.     demotest
  112.     demotest.c
  113.     demo_pragmas.h
  114.     squareme.c
  115.         These files form a demonstration library.
  116.  
  117.  
  118. Designing your library interface - register selection
  119. -----------------------------------------------------
  120.  
  121. Assuming that you have the routines for your library already written
  122. (you DO have a linker version, don't you?), you will now have to choose
  123. 68000 microprocessor registers for the arguments in your functions.
  124. That's the way the Amiga libraries work - in registers.
  125.  
  126. If you know 68000 assembler well, then go ahead and assign registers to
  127. your arguments.  If you don't, read on.
  128.  
  129. The 68000 has two sets of registers: address registers and data registers.
  130. The address registers are named A0 through A7 and the data registers are
  131. D0 to D7.  As a general rule, data registers D0-D5 and address registers
  132. A0-A3 are good choices for library arguments.  To assign registers to
  133. your functions, follow these rules.
  134.  
  135. 1. Assign registers to your arguments starting from the lowest numbered
  136.    registers and working up.
  137.  
  138. 2. If the argument is a pointer to something, then use an address register.
  139.    It is best not to use address registers for BPTRs.
  140.  
  141. 3. If the argument is a byte, word or longword, then use a data register.
  142.    Single-precision floating point numbers require one data register.
  143.    Double-precision numbers cannot be passed directly, as far as I can
  144.    determine.  Pass them by reference (using pointers).
  145.  
  146. 4. If you exceed the recommended register allocation (more than six
  147.    data arguments and/or more than four pointer arguments) then maybe
  148.    you should write less complex functions!  You CAN use data registers
  149.    D6 and D7 and you CAN use A4 and A5 if you are running SAS/C 5.10
  150.    or better.
  151.  
  152. 5. Be sure your compiler is passing what you think it's passing!
  153.    Take arithmetic promotion into account.
  154.    
  155.  
  156. For example, let's say I have the function
  157.  
  158. int foo(struct bar *a, int b, char *c, int e, int f)
  159.  
  160. I would assign registers as follows:
  161.  
  162.   argument  register
  163.   ------------------
  164.   a         A0
  165.   b         D0
  166.   c         A1
  167.   e         D1
  168.   f         D2
  169.  
  170.  
  171. Preparing the prototype and .fd files
  172. -------------------------------------
  173.  
  174. It is a good idea to prepare prototype files for your functions.
  175. Prototypes allow the compiler to do type checking for you.  If you
  176. aren't using prototypes, try it.  You'll probably like it.
  177.  
  178. When it comes to libraries, you have to be careful with prototypes.
  179. There are two ways that you can call a function in your library
  180. from within your library: through the library register interface
  181. (through A6) and directly, as a normal C program would.  It is best for
  182. you to call your function through the library.
  183.  
  184. Note that you may have functions in your library code that are not
  185. directly callable from a client of your library.  These functions can
  186. be prototyped in the normal way.
  187.  
  188. For functions callable from outside the library, prototype them like
  189. you normally would.  Do NOT put any register designations in the
  190. prototypes.  For examples on how to do library prototypes, examine
  191. your include files from Commodore.
  192.  
  193. The next file you will need to prepare is the .fd file.  The .fd file
  194. is what the fd2pragma program uses to construct the pragmas that the
  195. SAS/C compiler uses to interface directly to the library.  In addition,
  196. the .fd file is the Amiga standard now for defining library functions.
  197. If you include the .fd file in your library release, then users of any
  198. compiler system that reads .fd files can use your library.  It's so
  199. easy to prepare a .fd file that I strongly recommend you do so.
  200.  
  201. As an example of an .fd file, see "demo.fd".  You can also use the
  202. .fd files that come on the 1.3 Extras disk if you have them.
  203.  
  204. Any line in a .fd file that begins with '*' is a comment.
  205.  
  206. The first line in the .fd file begins with '##base'.  This line tells
  207. the system what the name of your library base variable is.  The
  208. system libraries all have standard base variable names, such as SysBase,
  209. DOSBase, GfxBase, etc.  Pick a name for your library's base and put
  210. it on this line.  I have '_DemoBase'.  Note that the base name should
  211. start with an underscore, as your C compiler prepends an underscore
  212. to all variable names.
  213.  
  214. The next line in the file is '##bias 30'.  Don't change this unless you
  215. know what you are doing.
  216.  
  217. What follows is a list of the functions in the library in the format
  218.  
  219. Name(arg,arg,arg)(reg/reg/reg)
  220.  
  221. where:
  222.  
  223.    Name    is the name of the function.
  224.    arg     is a name for the argument.  This name is never used, it is
  225.            only for documentation purposes.
  226.    reg     is the 68000 machine register that you assigned to the
  227.            argument.
  228.  
  229. Notes:
  230.  
  231.    The value a function returns (if any) is not given in the .fd file.
  232.    Argument descriptors are separated with commas.
  233.    Register names are separated with slashes or commas.  To determine
  234.       whether a slash or a comma is required, do the following:
  235.       
  236.       "Compare" the registers numerically.  Any address register is
  237.       "greater" than any data register.  For example, D5 > D2, A3 > A1,
  238.       and A0 > D7.
  239.       
  240.       If the register on the right is greater than the register on the
  241.       left, then use a slash.  Otherwise, use a comma.  See the example
  242.       below.
  243.       
  244.    Register names are in uppercase (A0, not a0).
  245.    Don't use any spaces on the line.
  246.  
  247. As an example, here's our foo function from above:
  248.  
  249. foo(a,b,d,e,f)(A0,D0/A1,D1/D2)
  250.  
  251.  
  252. The last line in the .fd file should be '##end'.
  253.  
  254. To test your .fd file, try using fd2pragma.  Just give the command line:
  255.  
  256. fd2pragma <fd file> <pragma file>
  257.  
  258. If there's a serious problem with your .fd file, fd2pragma will tell
  259. you about it.
  260.  
  261.  
  262. Preparing your source code
  263. --------------------------
  264.  
  265. I suggest you create a C source file to handle the interface to the
  266. Exec library system.  The file squareme.c is a working example.
  267.  
  268. Although the library code opens Exec and Dos for you, you must still
  269. declare the library bases.  This is different from application programming
  270. (where the bases are declared in the startup code).  In addition, you
  271. must declare LibBase as a pointer to a Library.  LibBase is used by
  272. the interface code so don't change its name.
  273.  
  274. If your library calls itself, then also declare your base variable,
  275. using the same name you used in the .fd file (but without the
  276. underscore).
  277.  
  278. In addition to the functions in your library, you will have to write
  279. the following functions.  Declare them EXACTLY as you see here.  The
  280. file squareme.c contains examples of these functions.  Failure to follow
  281. these instructions or any that follow could lead to aggravating bugs.
  282.  
  283. struct Library *__saveds LibInit(void)
  284.  
  285.    This function is called when your library is first loaded by the
  286.    system.  All of the Amiga library housekeeping stuff is done by
  287.    my startup code.  What this function is for is if you have to
  288.    initialize things before the library is used.  For example, if you
  289.    maintain a linked list of something, then NewList() it here.
  290.    
  291.    What this function MUST do is return the library base if your
  292.    initialization performed successfully.  The library base is stored
  293.    in LibBase, which is set up correctly before this function is called.
  294.    If you call your own library from within itself, then you should
  295.    set up your library base to the value of LibBase.  In my example,
  296.    I have set up DemoBase to the value of LibBase.  Then I return LibBase.
  297.    
  298.  
  299. struct Library *__saveds LibOpen(void)
  300.  
  301.    This function is called when the library is opened by someone.  All
  302.    Amiga housekeeping is already done, so all this function does is
  303.    perform any process-specific initialization.  For example, you might
  304.    want to record the process structures of your openers so that you
  305.    can maintain a separate data area for each.
  306.    
  307.    What this function MUST do is return the library base if any
  308.    initialization completed successfully.  See my example.
  309.  
  310.  
  311. void __saveds LibClose(void)
  312.  
  313.    This function is called when someone closes your library.  Again,
  314.    all Amiga housekeeping is done for you.  This function is used to
  315.    clean up after anything you set up in LibOpen.
  316.    
  317.    This function doesn't have to do anything if it doesn't want to!
  318.    All it has to do is return!  But it DOES have to be in the file,
  319.    even if all it does is return.
  320.  
  321.  
  322. BOOL __saveds LibExpunge(void)
  323.  
  324.    This function is called when Exec wants to remove you from the system.
  325.    My startup code will free the resources associated with the library
  326.    base.  All you have to do is free the stuff you allocated in
  327.    LibInit.
  328.    
  329.    This version of LibExpunge allows you to abort the expunge if
  330.    necessary.  For example, some libraries may maintain data that must
  331.    be flushed to disk before an expunge.  In this case, you may not
  332.    want to expunge, even if Exec thinks you can.  In this case, return
  333.    FALSE from this function.  If you can expunge, return TRUE.
  334.    
  335.    Again, if there is nothing to free, this function is allowed to
  336.    simply return TRUE!
  337.  
  338.  
  339. Notes:
  340.  
  341.    All these functions are declared using __saveds.  THIS IS ESSENTIAL!
  342.  
  343.  
  344. *** IMPORTANT NOTICE RE: FORBID IN LIBRARIES ***
  345.  
  346. Exec performs a Forbid() before calling the Init, Open, Close or Expunge
  347. functions.  However, the Operating Systems Development Group at Commodore
  348. has indicated that it has never been guarenteed that a library will not
  349. break a Forbid() in open or close.  The exception to this rule is the ROM
  350. library set - any ROM library that existed in 1.3 or earlier will not break
  351. a Forbid().
  352.  
  353. This means that you cannot open or close a non-ROM library (ARexx included)
  354. if you do not want to break Forbid() yourself.  In particular, since
  355. Expunge is never allowed to break a Forbid, you must not close a non-ROM
  356. library inside Expunge.
  357.  
  358. Breaking a Forbid inside a library's Open or Close functions requires
  359. careful mutual exclusion management.  The library controller included
  360. in this release of saslib performs such management for you.
  361.  
  362. Whether you break Forbid or not is up to you, but be aware of it if your
  363. code depends on Forbid!  Saslib doesn't care.  The end result is that
  364. operations which were previously forbidden, such as flushing a queue
  365. out to disk, no longer are.
  366.  
  367.  
  368.  
  369. Now to prepare the source code itself.  You will have to code your
  370. functions to use assembly language interfaces.  Assuming that you
  371. already have these functions written and that register assignment has
  372. been done, this is easy:
  373.  
  374. 1. Prepend a 'LIB' to the name of every function callable from outside
  375.    the library.  If you call functions from within your library, this
  376.    will prevent problems associated with having assembler registers in
  377.    the prototypes and pragmas at the same time.  If you don't know
  378.    what I'm talking about, then you are lucky.  As an example, I have
  379.    named the SquareMe function 'LIBSquareMe'.
  380.  
  381. 2. Immediately after the return type of your function, but before
  382.    its name, put the keywords '__saveds __asm' exactly as you see them
  383.    here.  See my example for details.
  384.  
  385. 3. Before each argument in the function header, put the keywords
  386.    'register __xx' where xx is replaced with the register name you
  387.    assigned earlier to that argument.  Note that the letter in the
  388.    register name MUST be in lowercase.
  389.  
  390. Here's our foo function as an example:
  391.  
  392. int __saveds __asm foo(register __a0 struct bar *a, register __d0 int b,
  393.   register __a1 char *c,
  394.   register __d1 int e, register __d2 int f)
  395.  
  396. Repeat the above for each function callable from a client of your
  397. library.  You do not need to change private functions called from
  398. within your library.
  399.  
  400.  
  401. Preparing libinf.a
  402. ------------------
  403.  
  404. lininf.a is the file that describes your library.  Yes, it's in assembler,
  405. but you don't need to know assembly to modify it.  Just do the following:
  406.  
  407. 1. On the line with '_LibName', replace 'demo.library' with the name
  408.    you want your library to be opened with.
  409.  
  410. 2. On the line with '_LibID', replace the ID string with a string
  411.    identifying your library.  The format is
  412.    
  413.    nameof.library major.minor (dd.mm.yy)
  414.    
  415.    See the example.
  416.  
  417. 3. On the LibVersion and LibRevision lines, place version and revision
  418.    numbers.  For example, if you want your library to be version 4.2,
  419.    set LibVersion to 4 and LibRevision to 2.  If you don't know
  420.    what version you want, use 1.0.
  421.  
  422. 4. Where it says 'put pointers to your functions here', do just that.
  423.    Create a line that says 'DEF <name>' where name is the name of
  424.    your function, not including the 'LIB'.  IMPORTANT!!!! The names of your
  425.    functions must appear here IN THE SAME ORDER as they appear in the
  426.    .fd file!
  427.  
  428.  
  429. Preparing the makefile
  430. ----------------------
  431.  
  432. Now on to the makefile.  I have defined lines for the compiler and
  433. assembler.  You should replace the path to the assembler 'Bin:a68k/a68k'
  434. with what it is on your machine.  If you know how to use the assembler,
  435. then you can tweak the command line arguments but they work fine as
  436. they are.
  437.  
  438. For the compiler, I have disabled stack checking.  This is important.
  439. Your library will be called from many processes each with its own stack.
  440. Which stack do you expect to check?  Other than this, you can define
  441. most other C flags any way you want.
  442.  
  443. The make instrucions for demo.library link the object file (squareme.o)
  444. to libhdr.o and libinf.o IN THAT ORDER.  Replace squareme.o with the
  445. name(s) of the object files you will be producing.  Leave the other
  446. object file names as they are.  If you have any linker libraries you
  447. would like to use, feel free to use them.
  448.  
  449. The dependency for squareme.o can be anything you want.  Just be sure
  450. to have stack checking turned off.
  451.  
  452. The dependencies for libhdr.o and libinf.o should be left as they are.
  453.  
  454. Finally, you should make an entry for your pragma file.  Use fd2pragma
  455. to generate the pragma file from the .fd file.  Putting this in the
  456. makefile ensures that the pragma file is kept up to date if you ever
  457. change the .fd file.
  458.  
  459. Of course, you should change all references to demo.library to whatever
  460. you are calling your library.
  461.  
  462. That's it!
  463.  
  464.  
  465. And now the fun part
  466. --------------------
  467.  
  468. Do an LMK.  Ideally, everything should compile, assemble and link just
  469. fine.  If it does not, check your files over for small errors.  If you
  470. still have problems, write me.
  471.  
  472. The result will be a library file that you can copy to libs:.  Try
  473. it out!  If you have xoper or a similar utility, use it to verify that
  474. opening, closing and expunging work correctly.
  475.  
  476. Now, who said it was hard to make an Amiga library?
  477.  
  478.  
  479. ARexx function libraries
  480. ------------------------
  481.  
  482. ARexx allows you to add functions to the language through the use of
  483. libraries.  Details are in the documentation that comes with pre-2.0
  484. versions of ARexx and in the Programmer's Guide to ARexx, published
  485. by Commodore.
  486.  
  487. You can use saslib to create ARexx function libraries.  To do so:
  488.  
  489. 1. Remove the semicolon from the INCLUDE_REXX line at the bottom of
  490.    libinf.a.
  491.  
  492. 2. Declare your query function in C like this:
  493.  
  494. ULONG __saveds __asm LIBRexxQuery(register __a0 struct RexxMsg *rm,
  495.    register __a1 char **rv)
  496.  
  497. 3. Be sure to reserve an offset for the query function in the dispatch
  498.    table.  Usually, the query function resides at offset -30, which
  499.    corresponds to the first entry in the table.
  500.