home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / utilities / utilst / thesdls / !DLLDoc / Manual / manText < prev    next >
Encoding:
Text File  |  1995-03-14  |  99.2 KB  |  3,142 lines

  1.                   ______   ________                   ______
  2.                  /          |      \     |           /
  3.                 (           |       \    |          (
  4.                  \______    |        \   |           \______
  5.                         \   |         )  |                  \
  6.                          )  |        /   |                   )
  7.                 ________/  _|_______/    |________  ________/
  8.  
  9.   T h e   S t r a y l i g h t   D y n a m i c   L i n k i n g   S y s t e m
  10.  
  11. _____________________________________________________________________________
  12.  
  13.  
  14.                          Some notes on this document
  15.  
  16.  
  17.     This text file should contain the complete text of the SDLS manual.
  18.     It has been generated by Impression, and formatted by hand.
  19.     Therefore, there may be come accidental omissions, and the formatting
  20.     may differ from the original document.
  21.  
  22.     This text file should therefore be viewed as a `convenience'.  The
  23.     definitive version of the documentation is the Impression Publisher
  24.     document.
  25.  
  26.     In addition, it is not possible to include all of the figures and
  27.     tables in a text form.  These are supplied in Draw and ArtWorks
  28.     format.  To view the ArtWorks files, use Computer Concepts' AWViewer
  29.     application, available on hensa, and from many other sources.
  30.  
  31.     Note that listings are not formatted, and may extend past the end
  32.     of a line.  This is so that you can extract the listings and use
  33.     them in your own code directly.
  34.  
  35. _____________________________________________________________________________
  36.  
  37.  
  38.     © 1995 Straylight.  All rights reserved.
  39.  
  40.     This documentation refers to the Straylight Dynamic Linking System
  41.     version 1.00.
  42.  
  43.     There is no warranty for the program, to the extent permitted by
  44.     applicable law.  Except when  otherwise stated in writing the
  45.     copyright holders and/or other parties provide the program ‘as  is’
  46.     without warranty of any kind, either expressed or implied, including,
  47.     but not limited to, the  implied warranties of merchantability and
  48.     fitness for a particular purpose.  The entire risk as to  the quality
  49.     and performance of the program is with you.  Should the program prove
  50.     defective,  you assume the cost of all necessary servicing, repair or
  51.     correction.
  52.  
  53.     The product described in this documentation is the subject of
  54.     continual development and,  while all efforts are taken to ensure
  55.     that the information given is correct, Straylight cannot  accept any
  56.     liability for loss or damage resulting from the use or misuse of this
  57.     product.
  58.  
  59. Trademarks
  60.  
  61.     Acorn, Archimedes and RISC PC are trademarks of Acorn Computers Ltd.
  62.     ARM is a trademark of Advanced RISC Machines Ltd.
  63.     All other trademarks acknowledged.
  64.  
  65. _____________________________________________________________________________
  66.  
  67.  
  68.                                  Introduction
  69.  
  70.  
  71. An introduction to dynamic linking
  72.  
  73.     Many current RISC OS applications use common libraries such as
  74.     RISC_OSLib or DeskLib.  Such libraries are usually quite large, and
  75.     currently each application using the library contains its own copy of
  76.     the  library code.  This is wasteful of both disk space and, much
  77.     more  importantly, memory space. Figure 1.1 shows this
  78.     diagrammatically.
  79.  
  80.         Figure 1.1: Applications using common libraries
  81.  
  82.     This document describes a method for libraries to be held as separate
  83.     files, allowing multiple applications to use a single copy of the
  84.     library  held in memory.  In order for this system to work, an
  85.     application must be  able to find the routines it requires at
  86.     run-time.  This process is called  ‘dynamic linking’, by analogy with
  87.     normal ‘static’ linking.  Figure 1.2  shows this improvement applied
  88.     to the situation shown in Figure 1.1.
  89.  
  90.         Figure 1.2: Applications using a shared library
  91.  
  92.     With dynamic linking, our view of what constitutes an application
  93.     must  change.  We must now consider an application to consist of:
  94.  
  95.     •  One main program, which contains the main application code.
  96.        This  main program will normally be contained within an absolute
  97.        image,  although it is also possible for it to be kept in a
  98.        RISC OS relocatable  module.
  99.  
  100.     •  Any number of Dynamic Link Libraries, which may be shared with
  101.        other applications.
  102.  
  103.     For the Straylight Dynamic Linking System (SDLS) to work, a small
  104.     module called the DLLManager is provided.
  105.  
  106.  
  107. Languages supported by the system
  108.  
  109.     The Straylight Dynamic Linking System is designed to support compiled
  110.     languages which conform to the APCS-R calling standard.  This
  111.     includes  most C compilers available for Acorn RISC machines, and
  112.     Acorn’s DDE  Pascal implementation.  It also allows creation of DLLs
  113.     written in  assembler, using any procedure call standard, although in
  114.     this case much  more work is required to implement DLLs.
  115.  
  116.  
  117. Who can use SDLS?
  118.  
  119.     Straylight have decided to make SDLS ‘freeware’.  It remains at all
  120.     times  Copyright © 1995 Straylight; however:
  121.  
  122.     •  Applications using shared or extension DLLs may be distributed
  123.        with  the DLLManager module and !DLLs resource as required.
  124.  
  125.     •  Development kits for shared DLLs may be distributed with parts of
  126.        this package as required.
  127.  
  128.     The above applies to all software products whether or not they are
  129.     commercial.  No charge may be made for any part of SDLS specifically,
  130.     and none of the code or documentation may be altered in any way. You
  131.     may use parts of this documentation within your own manuals for
  132.     shared libraries or applications if you wish.
  133.  
  134.     All products distributed with SDLS or any parts thereof must state in
  135.     the  main documentation such parts are copyright © 1995 Straylight.
  136.  
  137.  
  138. About this manual
  139.  
  140.     This document divided into two parts: a user guide and a reference
  141.     manual.  The user guide gives an overview of the main concepts
  142.     required  to use SDLS.  Further details may be found in the reference
  143.     manual.
  144.  
  145.     The Straylight Dynamic Linking System can be used at two different
  146.     levels: the development of client applications that use existing
  147.     DLLs, and  the creation of new Dynamic Link Libraries.  Both of these
  148.     processes are  dealt with individually in the user guide.
  149.  
  150.     It isn’t necessary to learn how to create your own DLLs if you’re
  151.     only  going to be using existing libraries, although it may give some
  152.     additional  insight into how the system works.  It is necessary to be
  153.     familiar with  both sections if you will be developing DLLs yourself.
  154.  
  155.  
  156. Terminology
  157.  
  158.     The following terms are used throughout this document:
  159.  
  160.     Dynamic Link Library    A collection of routines, usually with a
  161.                 common  purpose, which may be shared by any
  162.                 number of  applications running at the same
  163.                 time.  ‘Dynamic Link Library’ is often
  164.                 abbreviated as  ‘DLL’.
  165.  
  166.     Client application    An application which makes use of a Dynamic
  167.                 Link Library.
  168.  
  169.     External procedure call    A call from a client application to a DLL,
  170.                 from a  DLL to a client application, or from
  171.                 one DLL to  another.
  172.  
  173.  
  174. Package contents
  175.  
  176.     The Straylight Dynamic Linking System consists of several parts:
  177.  
  178.     •  A !DLLs shared resource, which will contain Dynamic Link
  179.        Libraries,  and allow applications to locate them when required.
  180.  
  181.     •  The !DLLMerge application, which allows users to update their
  182.        !DLLs  resource as part of the installation of a new application.
  183.  
  184.     •  A DLLLib library, which provides support for the dynamic linking
  185.        system.
  186.  
  187.     •  The cdll tool, which generates AOF (Acorn Object Format) files
  188.        useful  in constructing DLLs and client applications.
  189.  
  190.     •  A Tutorials directory, which contains example programs used to
  191.        demonstrate the use of the system.
  192.  
  193. _____________________________________________________________________________
  194.  
  195.  
  196.                    P A R T   I :   U S E R ' S   G U I D E
  197.  
  198. _____________________________________________________________________________
  199.  
  200.  
  201.                              !DLLs and !DLLMerge
  202.  
  203.  
  204.     The Straylight Dynamic Linking System provides a shared resource
  205.     called  !DLLs.  It collects together DLLs and allows client
  206.     applications to easily  locate the ones that they require.  This is
  207.     very similar to the way the  standard !System resource allows
  208.     applications to locate the relocatable  modules that they need.
  209.  
  210.     It is normal to keep the !DLLs and !System resources together.  If
  211.     you have  a Risc PC, you will find the !System resource in the
  212.     directory  $.!Boot.Resources.
  213.  
  214.     The !DLLs resource sets up two system variables:
  215.  
  216.     •  DLL$Dir is the full path name of the !DLLs resource.
  217.  
  218.     •  DLL$Path is a path variable allowing access to all currently
  219.        available  shared DLLs.
  220.  
  221.     Inside the !DLLs resource folder are the following files:
  222.  
  223.     •  !Boot and !Run − set up the system variables properly.
  224.  
  225.     •  DLLManager − the DLLManager module.  It is placed here so that
  226.        client  applications can find it easily.
  227.  
  228.     •  A few small utility programs which are used to set up the system
  229.        variables.
  230.  
  231.     •  A number of subdirectories containing DLLs.
  232.  
  233.     The DLLMerge application is aimed at simplifying the process of
  234.     installing applications which require DLLs.  It works in a
  235.     more-or-less  identical way to Acorn’s SysMerge utility.  To use it,
  236.     double click on the  !DLLMerge icon, and drag your master DLLs
  237.     resource folder to the main  window, followed by the DLLs folder on
  238.     the distribution disk.  DLLMerge  then updates the master DLLs
  239.     resource from the copy on the distribution  disk, and rescans the
  240.     resource folder to update the system variables.
  241.  
  242. _____________________________________________________________________________
  243.  
  244.  
  245.                              Using existing DLLs
  246.  
  247.  
  248. Introduction
  249.  
  250.     This chapter will describe how to write client applications which use
  251.     one  or more DLLs in the most common way.  If a library has unusual
  252.     requirements, they will be specified in that library’s documentation.
  253.     In general, using a Dynamic Link Library is very similar to using the
  254.     traditional statically linked kind − all you will need to do is link
  255.     with  some different files.
  256.  
  257.     A DLL will always come in two parts: the actual library code, which
  258.     is  held in the !DLLs resource, and a small ‘stub’, which you link
  259.     into your  application.  If you’re using more than one DLL, you will
  260.     usually just link  with the stubs for each one.  The stub contains
  261.     information which enables  the DLLManager module to load and prepare
  262.     the DLL for use.
  263.  
  264.  
  265. Ensuring library versions
  266.  
  267.     Your application will need to ensure that sufficiently recent
  268.     versions of all  the libraries that it needs are available before it
  269.     starts up.  You can do this  in the application’s !Run file using the
  270.     *command *DLLEnsure as follows:
  271.  
  272.         DLLEnsure <library name> <version>
  273.  
  274.     You will be told the library’s name and version number in the
  275.     library’s  documentation.
  276.  
  277.  
  278. Client applications written in C
  279.  
  280.     If your application makes use of the Shared C Library, then your link
  281.     step  will need to be modified slightly.  In order to correctly load
  282.     the libraries  your application needs, you will need to link with the
  283.     DLLLib library  supplied with the SDLS distribution.  Also, instead
  284.     of linking with the  standard ‘stubs’, you will need to link with an
  285.     alternative Shared C  Library stub, as follows:
  286.  
  287.     •  For a normal application, use ‘astubs’.
  288.  
  289.     •  For a relocatable module, use ‘mstubs’.
  290.  
  291.     These replacement stubs are compatible with those supplied with Acorn
  292.     C Releases 3 and 4.  However, the stubs supplied with C Release 5
  293.     contain  the new routines _swi and _swix.  If your application makes
  294.     use of these  routines, you have two choices:  either you can use the
  295.     stubs described  above, and also link with the file ‘swiv’ provided
  296.     in the distribution, or  you can use the asstubs or msstubs versions
  297.     (note the additional ‘s’).  The  latter alternative will use the
  298.     routines contained in the Shared C Library,  which saves memory, but
  299.     will prevent your program working under  RISC OS 2.  Also, the
  300.     versions of these routines in the Shared C Library  contain a small
  301.     bug which is not present in the swiv program in this  distribution.
  302.     For these reasons, we recommend that you do not use the  versions of
  303.     these routines in the Shared C Library.
  304.  
  305.     We suggest that you add the DLLLib directory to your standard library
  306.     path (which will normally be C$Path).  This will allow you to specify
  307.     the  object and header files within the directory easily from all of
  308.     your project  directories.  In the examples, we will assume that you
  309.     have done this.
  310.  
  311.  
  312. A brief tutorial
  313.  
  314.     In the directory Tutorial.ClicntEx, there is an example of a very
  315.     simple  client application written in C.  You don’t actually need a C
  316.     compiler,  since we’ve already compiled the source code for the
  317.     client.  You will  however need a linker; either Acorn’s link or the
  318.     freely available drlink is  recommended for this purpose.  This
  319.     section will show you how to create  the actual application image.
  320.  
  321.     We have not supplied a makefile for this example, because we feel
  322.     that it  will be more instructive to perform the operation manually.
  323.  
  324.     The example client requires the DLLExample DLL which is already in
  325.     the  !DLLs resource.  The header file h.dllExample describes the
  326.     functions this  very simple library offers.  The DLL’s stub is
  327.     contained in o.dllExample.
  328.  
  329.     To build the client application, all you need to do is:
  330.  
  331.     1.  Make Tutorial.ClientEx your current directory.
  332.  
  333.     2.  Perform the following command:
  334.  
  335.           link o.clientEx o.dllExample c:o.dllLib c:o.astubs -o ClientEx
  336.  
  337.     (We’ve used Acorn’s link here, although you can use drlink in exactly
  338.     the same way.)
  339.  
  340.     The application is now complete.  If you just run the command
  341.     ClientEx,  a greeting and the current time and date should be printed
  342.     on your  screen.
  343.  
  344.     Note that if you want to compile the source code (clientEx.c), you do
  345.     this  in the usual way.
  346.  
  347.     Complications
  348.  
  349.     Usually, creating your client application is as simple as explained
  350.     above.   However, a lot of this simplicity is dependent on the DLLs
  351.     you are using,  and you should watch out for some pitfalls. In order
  352.     for the DLLManager to keep track of which application is  currently
  353.     calling DLL routines, it makes use of the time at which the
  354.     application was started.  Unfortunately, some operating system calls
  355.     alter  this time, and so you must ensure that you restore it
  356.     immediately  afterwards.  Essentially, any operating system call
  357.     which allows another  application to run will alter the start time;
  358.     these calls are: Wimp_Poll,  Wimp_PollIdle, OS_CLI and Wimp_StartTask
  359.     (which calls OS_CLI)¹.   There are DLLManager calls which allow you
  360.     to save and restore this time  value, and you can use these to
  361.     ‘protect’ the offending operating system  routines, as follows:
  362.  
  363.     •  In C (using the DLLLib functions):
  364.  
  365.        {
  366.          int save;
  367.          dll_saveHandle(&save);
  368.          /* Do operation that needs 'protection' */
  369.          dll_restoreHandle(&save);
  370.        }
  371.  
  372.     •  In assembler:
  373.  
  374.         SWI    DLL_SaveHandle        ;Get application handle
  375.         STMFD    R13!,{R0}        ;Save it on the stack
  376.         ; Do operation that needs 'protection'
  377.         LDMFD    R13!,{R0}        ;Get application handle back
  378.         SWI    DLL_RestoreHandle    ;Set it as the current one
  379.  
  380.     DLLlib already includes functions for handling OS_CLI and
  381.     Wimp_StartTask ‘safely’.  A good WIMP library will provide a way of
  382.     calling Wimp_Poll and Wimp_PollIdle.
  383.  
  384.     The other problem, which only applies if your program is written in C
  385.     or  a similar language, is that the DLLManager needs to be able to
  386.     keep track  of which part of an application is currently executing.
  387.     Normally, this will  happen automatically.  Problems only occur when
  388.     your program does not  follow normal function call and return
  389.     discipline.  This will usually  happen as a result of a call to the
  390.     standard C longjmp function.  The  problems occus because the
  391.     DLLManager needs to maintain a stack  containing information about
  392.     external procedure calls, and a longjmp call  causes the DLLManager’s
  393.     stack pointer to become out of sync.  The  solution is to remember
  394.     the stack pointer when you call setjmp and  restore it again when
  395.     setjmp returns, as follows:
  396.  
  397.     {
  398.       int stackptr;
  399.       jmp_buf j;
  400.  
  401.       dll_readStackPtr(&stackptr);
  402.       if (setjmp(j))
  403.       {
  404.  
  405.         /* --- Someone longjmped here --- */
  406.  
  407.         dll_setStackPtr(stackptr);
  408.         /* Other handling */
  409.       }
  410.     }
  411.  
  412.     Module clients written in C
  413.  
  414.     Special care must be taken if your client application is actually a
  415.     relocatable module.  If your module passes function pointers to a
  416.     DLL, then you  should read the sections on The cdll tool and
  417.     Complications in the next  chapter before reading any further.
  418.  
  419.     Due to the way the DLLManager works, a module client must contain
  420.     entry veneers for each function which may be called from a DLL
  421.     through  a function pointer.  These are created by cdll − you must
  422.     create a  definition file containing only the ‘extEntry’ and
  423.     ‘objects’ sections.  You  can generate an object file containing the
  424.     entry veneers for the functions  named in the ‘extEntry’ section by
  425.     using the command:
  426.  
  427.         cdll -def <defn file> -ext <output file>
  428.  
  429.     Note that the entry veneer for a function foobar will be
  430.     _extEntry_foobar.
  431.  
  432. _____________________________________________________________________________
  433.  
  434.  
  435.                        Creating Dynamic Link Libraries
  436.  
  437.  
  438. Introduction
  439.  
  440.     This part of the manual will explain how you can write your own
  441.     Dynamic Link Libraries.  It is expected that you have already read
  442.     the  chapter Using existing DLLs.
  443.  
  444.     Creating DLLs can be a considerably more complex task than writing
  445.     client applications − this doesn’t mean that all libraries will be
  446.     hard to  write, but the relative ease of writing clients is mainly
  447.     due to the effort  put in by the library developers.
  448.  
  449.     Whether you are writing an entirely new Dynamic Link Library, or
  450.     converting an existing static library into a DLL, it is vital that
  451.     you have a  reasonable understanding of the concepts introduced here.
  452.     Such  familiarity will make your task as a DLL developer much
  453.     simpler.
  454.  
  455.  
  456. Structure of a DLL
  457.  
  458.     Conceptually, a Dynamic Link Library consists of two parts: the code
  459.     part,  which contains all the routines that client applications will
  460.     use, and the  header, which contains information used by the
  461.     DLLManager module. Each routine that a DLL exports to its clients has
  462.     an entry point − this is  simply the start address of the routine in
  463.     memory.  In order to use a  routine, the client application must find
  464.     its entry point; we will discuss  how this is done below.
  465.  
  466.     The code part of a DLL is usually built from a number of AOF object
  467.     files  or statically linked libraries.  These are generated from your
  468.     library’s  source code in the same way as for a statically linked
  469.     library. Naming of DLLs and entry points
  470.  
  471.     The DLLManager keeps track of Dynamic Link Libraries by use of their
  472.     names.  For this reason, each DLL must have a unique name.  If you
  473.     are  planning to release a DLL, you should read the chapter
  474.     Registering  names.  DLL names may be at most 10 characters long, and
  475.     must be the  same as its leafname.
  476.  
  477.     Each entry point must also be given a name.  Entry point names only
  478.     have to be unique within a particular DLL.  However, you should be
  479.     aware that the linker will not allow multiple definitions of
  480.     identifiers.   This rarely occurs in practice with well-chosen names
  481.     − we recommend  that you group routines with a common purpose by
  482.     giving them a  suitable common prefix.  For example, in a library
  483.     offering WIMP  services, all the routines concerned with dialogue box
  484.     management might  begin with the prefix ‘dbox_’.  Since a client is
  485.     unlikely to use more than  one such library, this naming strategy
  486.     should not cause too many  problems.
  487.  
  488.  
  489. ‘Foreverness’ and version control
  490.  
  491.     One of the main difficulties in designing a Dynamic Link Library is
  492.     version control.  A version of a DLL must try to remain compatible
  493.     with  clients which were written for an earlier version of the
  494.     library.  This  means that the routines provided by your library must
  495.     keep the same  external interfaces, or ones which are compatible with
  496.     earlier releases.   This concept is termed ‘foreverness’.
  497.  
  498.     A full discussion of foreverness is beyond the scope of this
  499.     document.   However, when designing a DLL you should attempt to
  500.     ensure that you  can easily extend your interfaces in a compatible
  501.     way, for example by  making use of reserved fields and flags.
  502.     RISC OS itself contains many  good examples of this sort of design.
  503.  
  504.     The DLLManager goes some way to help you with the problems of version
  505.     control.  You must include a version number in the header of a DLL.
  506.     This  is checked against the version number requested by the client.
  507.     An error is  reported if there is no sufficiently recent version of
  508.     your library available. A complete discussion of version handling is
  509.     given in the reference part  of this document.
  510.  
  511.  
  512. The cdll tool
  513.  
  514.     The DLL header and stubs files have a fairly complex format, and
  515.     building these by hand is difficult and prone to errors.  The cdll
  516.     tool is a  small program which will generate these and other dynamic
  517.     linking- related data structures from simple textual descriptions.  A
  518.     full descrip tion of cdll is given in the chapter The cdll tool in
  519.     the reference section.   Here, we shall only discuss the parts
  520.     relevant to the creation of Dynamic  Link Libraries.
  521.  
  522.     Definition files
  523.  
  524.     You describe your DLL to cdll by means of a definition file, which
  525.     contains  all the information needed to create the DLL’s header and
  526.     stub.  An  annotated example of a definition file for a simple DLL is
  527.     shown in  figure 4.1.
  528.  
  529.     If you are converting an existing statically linked library into a
  530.     DLL, then  the creation of a definition file by hand would be very
  531.     time-consuming.
  532.  
  533.     To help solve this problem, cdll can create a skeleton definition
  534.     file based  on a number of given object files and libraries.  You
  535.     will need to modify  the resulting file by hand before you can use
  536.     it, although cdll will have  done the bulk of the work for you.  To
  537.     do this, use the command
  538.  
  539.         cdll -def <output file> -obj <object/library files>
  540.  
  541.     If you are creating a Dynamic Link Library from scratch, or you have
  542.     a  definition file prepared using the above method, you will need to
  543.     maintain the file by hand as you add new routines to your library.
  544.     This is  unlikely to be difficult.
  545.  
  546.     Creating DLL headers and stubs
  547.  
  548.     Once you have a definition file, you can create the DLL’s header and
  549.     stubs as AOF (object) files using the command:
  550.  
  551.         cdll -def <defn file> -stub <stub name> -hdr <header name>
  552.  
  553.     The stub is ready for inclusion in client applications, as described
  554.     in the  previous chapter.  The header can be used to create the
  555.     finished Dynamic  Link Library as explained below.
  556.  
  557. Linking
  558.  
  559.     Once you have the object files for your DLL’s code and header parts,
  560.     you  can link them together to form the finished DLL:
  561.  
  562.         link -rmf <object files> -o <dll filename>
  563.  
  564.     It is important to notice that the linker’s ‘-rmf’ option is used −
  565.     this will  automatically create the code necessary to relocate the
  566.     DLL when it is  loaded.  The freely available drlink program also has
  567.     this option. The DLL file created by link using the above command has
  568.     its filetype set  to be a relocatable module.  You will probably want
  569.     to change this to be  Data (type &FFD).
  570.  
  571. Writing DLLs in C
  572.  
  573.     There are some special considerations you must bear in mind when
  574.     writing a DLL in C or a similar language.  The compiler options
  575.     described  here are applicable to the Acorn C and Pascal compilers.
  576.     Other compilers  may include equivalent features − check your
  577.     compiler’s documentation  for details.
  578.  
  579.     Compiling
  580.  
  581.     When you compile code for use in a Dynamic Link Library, you must use
  582.     the compiler’s ‘-zM’ option, which requests the compiler to create
  583.     code  suitable for a relocatable module.  Code compiled in this way
  584.     has  properties which make it possible for it be used in DLLs.  If
  585.     your compiler  does not support an equivalent option, you will not be
  586.     able to create  DLLs with it.
  587.  
  588.     The SDLS package contains some replacement C library header files
  589.     (ctype.h, errno.h, math.h and stdio.h) as part of the DLLLib, and you
  590.     must ensure that these are included by your source files, instead of
  591.     the  standard ones.  To activate the modifications made to these
  592.     header files,  you must define the macro _DLL (e.g. using the
  593.     compiler option ’-d_DLL‘) −  this must only be done when compiling
  594.     code for a DLL; do not define this  symbol when creating client
  595.     applications.  Assuming that the replacement  header files are
  596.     contained within the directory c:dlllib.h, you can  ensure that they
  597.     are included correctly by using the option  ’Jc:dlllib.,:mem‘.  This
  598.     overrides the default search mechanism, which  will find copies of
  599.     the header files embedded in the compiler, and instead  locates the
  600.     SDLS versions first.  If your compiler does not support this  type of
  601.     operation, you must use explicit paths in your source code (e.g.
  602.     #include "c:dlllib.h.stdio").
  603.  
  604.     As an example, to compile the file c.hellow, use the command
  605.  
  606.         cc -d_DLL -Jc:dlllib.,:mem -zM -c hellow.c -o hellow.o
  607.  
  608.     The compiler commands can become very complicated − we therefore
  609.     recommend that you use a makefile to manage creation of DLLs.
  610.  
  611.     Linking
  612.  
  613.     When you are linking your object files to create the final Dynamic
  614.     Link  Library, you must also link with the DLLLib library and the
  615.     dstubs Shared  C Library stubs.  For example
  616.  
  617.         link -rmf <object files> c:dlllib.o.dlllib c:dlllib.o.dstubs
  618.             -o <dll filename>
  619.  
  620.     Note that the dstubs do not include the new Shared C Library entry
  621.     points  _swi and _swix − if you require these, you should link with
  622.     the supplied  swiv object file as described in the previous chapter.
  623.  
  624.     Debugging
  625.  
  626.     Unfortunately, it is not possible to include debugging information in
  627.     a  DLL.  If you wish to debug your library, it is wise to allow both
  628.     a  statically and dynamically linked version to be built from the
  629.     same source  code.  You can use the preprocessor macro _DLL described
  630.     above to  conditionally compile the appropriate code for both
  631.     versions.
  632.  
  633.     Complications
  634.  
  635.     All the complications described in the previous chapter, regarding
  636.     Wimp_Poll etc. and longjmp also apply to DLLs.  However, there is a
  637.     further complication if you use function pointers.
  638.  
  639.     The DLLManager must perform some setting-up operations whenever one
  640.     of your DLL’s entry points is called.  This happens automatically
  641.     most of  the time.  However, you must be careful when returning
  642.     pointers to  functions contained within your library to the client
  643.     application. A normal call  to one of your routines is actually
  644.     routed through a small  piece of code called an entry veneer.  This
  645.     allows the DLLManager to  perform its setting up before it passes
  646.     control to the actual routine.  If the  client application were to
  647.     call one of your routines directly through a  function pointer, the
  648.     DLLManager would not be able to set up the  environment correctly for
  649.     the routine, and your program would fail.  The  solution is to ensure
  650.     that you always return the address of the routine’s  entry veneer,
  651.     rather than its actual address.
  652.  
  653.     Each entry veneer is given a name based on its routine’s name − for
  654.     example, the entry veneer for the routine dbox_create would be called
  655.     _dllEntry_dbox_create.  If you want to set up a function pointer with
  656.     the  address of a routine which may be returned to the client
  657.     application, you  must instead use the name of the entry veneer.
  658.  
  659.     Note that if a function pointer will not be used outside of your DLL,
  660.     you  need not use the address of the veneer.  However, no harm will
  661.     be done if  you do.
  662.  
  663.     You may have routines which you do not want to export to the client
  664.     application by name, but you may want to be able to return function
  665.     pointers to them.  You can do this by naming them in your cdll
  666.     definition  file in a section labelled extEntry.  This section is
  667.     otherwise the same as  the exports section already discussed.
  668.  
  669.     To assist in the management of source code being used in both
  670.     statically  and dynamically linked libraries, the DLLLib library
  671.     contains a header file  dll.h which defines the following macros:
  672.  
  673.     _dll_static    When compiling a statically linked library, this
  674.             macro  expands to ‘static’.  When compiling a DLL, it
  675.             does  nothing.  This is useful if you are returning a
  676.             function  pointer to a function, but do not want it
  677.             visible to the client.
  678.  
  679.     _dllEntry(x)    When compiling a statically linked library, this
  680.             macro  expands to just ‘x‘.  When compiling a DLL, it
  681.             expands to  ‘_dllEntry_x’.
  682.  
  683. Writing DLLs in assembler
  684.  
  685.     This section will describe how to write a Dynamic Link Library which
  686.     does not conform to the APCS protocols.  If you are writing a DLL in
  687.     assembler for use with APCS-conforming clients then the previous
  688.     section will be more applicable to you.
  689.  
  690.     If you are writing code which does not conform to APCS, you will not
  691.     be  able to take advantage of a lot of the support offered by the
  692.     DLLManager.   However, by doing this, you will be able to overcome
  693.     the restrictions  imposed by the DLLManager’s APCS support (for
  694.     example, you cannot  implement coroutines using the standard support
  695.     functions because of  the requirement for strict call-return
  696.     discipline).
  697.  
  698.     Re-entrancy
  699.  
  700.     The foregoing discussion of dynamic linking has glossed over one of
  701.     the  important properties which dynamically linked code must have −
  702.     it must  be able to maintain a separate state for each of its client
  703.     applications.  It  will help to define some terminology: we say that
  704.     a routine is threaded  after it has been called, but before it
  705.     returns to its caller.  Since RISC OS is  a multitasking environment,
  706.     it is conceivable that a routine in a DLL is  threaded by more than
  707.     one client simultaneously.  Such a routine must be  able to correctly
  708.     locate its state information for each client.  Code that can  cope
  709.     with this is said to be re-entrant.
  710.  
  711.     A routine will usually keep temporary data in or relative to
  712.     registers.   Since each client will see a different set of register
  713.     values, this causes no  problems for re-entrancy.  The difficulty
  714.     comes in trying to maintain the  library’s persistent state.
  715.  
  716.     The recommended approach is to collect all your library’s data areas
  717.     together, and keep their location in or relative to a register.  This
  718.     location  should be set up when the library is initialised by a
  719.     client.  The client can  then pass this address to the library when
  720.     it makes external calls.
  721.  
  722.     Important points to note
  723.  
  724.     Since you are not using the DLLManager’s APCS support facilities, you
  725.     will not require the entry veneers for your routines.  These entry
  726.     veneers  are normally generated automatically by cdll.  To prevent
  727.     cdll from  generating these veneers, you must put the keyword
  728.     ‘nonAPCS’ in your  DLL definition file, outside of any sections
  729.     enclosed in braces.
  730.  
  731.     You should note that the automatic loading of DLLs is a property of
  732.     the  SDLS Shared C Library stubs.  You should provide a means for
  733.     client  applications to find their DLLs if they are not using these
  734.     stubs.  Details  on how this automatic startup works can be found in
  735.     the reference  section.
  736.  
  737. _____________________________________________________________________________
  738.  
  739.  
  740.                                 Extension DLLs
  741.  
  742.  
  743. Introduction
  744.  
  745.     As well as providing facilities for the implementation of shared
  746.     libraries,  the Straylight Dynamic Linking System provides a method
  747.     by which  applications may easily load extension code if it is
  748.     required.  Such  extensions are called extension DLLs and might
  749.     provide further facilities  which may not always be required.  In
  750.     addition, you might publish the  interface to your application and
  751.     allow extensions to it to be written by  third parties.
  752.  
  753.     A DLL containing a shared library is loaded into the RMA, where it
  754.     can  be accessed by all its clients.  In contrast, extension DLLs are
  755.     loaded into  its client’s application space − it is therefore local
  756.     to that application. This chapter will describe how to write both
  757.     extension DLLs and  applications which make use of them.  It is
  758.     expected that the reader is  familiar with the material presented in
  759.     the previous two chapters.
  760.  
  761.  
  762. Application entry points
  763.  
  764.     In contrast to shared DLLs, where the DLL defines its interface to
  765.     clients,  an application making use of extension DLLs will need to
  766.     define an  interface to its libraries.  It does this by declaring
  767.     named entry points, in a  similar way to a shared library.  Extension
  768.     DLLs will find these entry  points and so be able to communicate with
  769.     the application.
  770.  
  771.     You define an application’s entry points by creating a cdll
  772.     definition file,  containing the ‘exports’ and ‘objects’ sections.
  773.     You can then build a  ‘header’ which you link into your client, which
  774.     defines these entry points  to the DLLManager, and a ‘stub’ which is
  775.     linked into the extension DLLs.  You can build these files using the
  776.     command:
  777.  
  778.         cdll -app -def <defn file> -hdr <header> -stub <stub>
  779.  
  780.     The DLLLib will automatically register the application’s entry points
  781.     with  the DLLManager module when the application starts up.  If you
  782.     are not  using the APCS support offered by the DLLManager, you should
  783.     see the  description of the SWI DLL_RegisterAppEntryTable in the
  784.     reference  section.
  785.  
  786.  
  787. Creating extension DLLs
  788.  
  789.     Creating an extension DLL is not very different from creating a
  790.     shared  DLL.  The main differences are that you do not create a stub
  791.     for the DLL,  and you will need to link in the application’s stub.
  792.     To create only the  DLL header and not the stub, use the command:
  793.  
  794.         cdll -def <defn file> -hdr <header file>
  795.  
  796.     (i.e. omit the ‘-stub’ option).
  797.  
  798.  
  799. Loading extension DLLs
  800.  
  801.     An application is responsible for managing the memory used by its
  802.     extension DLLs.  It must find out how large a block is required for
  803.     each  extension and allocate memory appropriately.  It must also
  804.     allocate  memory for the DLL’s data.  This is actually much easier
  805.     than it sounds,  since DLLLib provides a routine which does all of
  806.     this for you.  If you  aren’t using DLLLib, you should consult the
  807.     reference section, which  contains some example code for doing this.
  808.  
  809.     The DLLLib routine, called _dll_loadExtension, will load a file and
  810.     return  a DLL handle, which you can use to reference the DLL in
  811.     future. Once the DLL is loaded, it will remain idle until you call it
  812.     through an  entry point.  It is usual for an extension DLL to provide
  813.     a single entry  point which is called when it is loaded − the name of
  814.     this entry point will  be fixed by the application.  To find this
  815.     entry point, the application will  call the SWI DLL_FindEntry (or the
  816.     DLLLib routine dll_findEntry) with  the DLL handle and the entry
  817.     point’s name.  The entry point can now be  called − the extension can
  818.     then call routines in the application to register  its services.
  819.  
  820. _____________________________________________________________________________
  821.  
  822.  
  823.                               Registering names
  824.  
  825.  
  826. Why bother registering?
  827.  
  828.     Under this system, many things are given names to try to identify
  829.     them.   It makes sense therefore that some measures are taken to make
  830.     sure the  names are unique.  We’ve chosen to use textual names to try
  831.     and give  users as wide a choice as possible, although problems may
  832.     still occur.   Therefore you should register any names you want to
  833.     use with Straylight  to avoid clashes.
  834.  
  835.  
  836. Who needs to register?
  837.  
  838.     Certainly, any commercial software which uses this system ought to
  839.     register any names it requires.   Authors of ‘alternatively
  840.     distributed’ software (e.g. Public Domain,  Freeware, Shareware,
  841.     Careware) should register DLL names too − it  doesn’t take very much
  842.     to register, and it can save a lot of problems if  there’s a clash.
  843.     They don’t have to register client application names,  although we do
  844.     recommend that they do.
  845.  
  846.  
  847. What needs to be registered?
  848.  
  849.     You need to register any of the following names:
  850.  
  851.     Shared DLL names
  852.  
  853.         Since DLLs are identified by name alone once they’re loaded
  854.         into memory, names must be unique.  The results of a clash
  855.         here could be catastrophic.  All shared DLL names must be
  856.         registered with Straylight.
  857.  
  858.     DLL client names
  859.  
  860.         Applications are identified by name in various *commands,
  861.         and user confusion would be reduced considerably if the
  862.         names were different!
  863.  
  864.         If your client’s application or module name is registered
  865.         with  Acorn, then that should be acceptable for use as a DLL
  866.         client  name.  You should still register in any case.
  867.         Someone else who  hasn’t registered with Acorn may already
  868.         have taken your  name.
  869.  
  870.     DLL resource subdirectories
  871.  
  872.         Shared DLLs are stored in the !DLLs resource folder with one
  873.         subdirectory for each source of DLLs.  The name of the
  874.         subdirectory will typically be the name of the company
  875.         creating the DLLs (e.g. ours is called ‘Straylight’).  In the
  876.         event  of a directory becoming full (77 DLLs allocated to a
  877.         single  source), a new name will be allocated.
  878.  
  879.         ‘Alternatively distributed’ DLLs won’t use this system −
  880.         there  are simply too many sources.  Instead, the names will
  881.         be  allocated as ‘Misc_1’, ‘Misc_2’ etc.  You will be given a
  882.         directory name when you register your shared DLL name. DLL
  883.         entry point names do not need to be registered, since an
  884.         entry point  name is always passed with a DLL handle to
  885.         resolve into an address.   Extension DLL names don’t need to
  886.         be registered either, since the  DLLManager is only
  887.         interested in the DLL’s handle in this case.
  888.  
  889.  
  890. How do I register?
  891.  
  892.     You can register in any of the following ways:
  893.  
  894.     •  Telephone or fax: 01926 452639
  895.  
  896.     •  By mail, to:
  897.  
  898.         Straylight
  899.         16, Portland Street
  900.         Royal Leamington Spa
  901.         Warwickshire
  902.         CV32 5HE
  903.  
  904.        We do not charge a fee for registration.
  905.  
  906. _____________________________________________________________________________
  907.  
  908.  
  909.               P A R T   I I :   R E F E R E N C E   M A N U A L
  910.  
  911. _____________________________________________________________________________
  912.  
  913.                              How the system works
  914.  
  915. Introduction
  916.  
  917.     This section describes how the Straylight Dynamic Linking System
  918.     works.   It is not necessary to understand all of this to use SDLS,
  919.     although you  may find it interesting anyway.
  920.  
  921.     It is assumed that the reader is already fairly familiar with ARM
  922.     assembler and the ARM Procedure Call Standard (APCS). This section
  923.     will re-iterate some of the points made in earlier chapters.
  924.     However, it goes into considerably greater depth.
  925.  
  926.  
  927. The basic idea
  928.  
  929.     Sharing code on its own is not difficult − all that is necessary is
  930.     to put the  code in shared memory (e.g. the RMA) and allow clients to
  931.     find it.  The  difficulty lies in maintaining separate areas of data
  932.     for each application  (the DLL’s instance data for the application).
  933.     Fortunately, the Acorn ANSI  C and ISO Pascal compilers provide a
  934.     facility for relocating data  references at run-time: if the -zM
  935.     option is specified on the compiler  command line, data references
  936.     such as
  937.  
  938.             LDR     a1,dataptr
  939.             ;
  940.             ; Some code...
  941.             ;
  942.  
  943.      dataptr    DCD     data
  944.  
  945.     are replaced by the (slightly) more complex
  946.  
  947.             LDR     a1,dataptr
  948.             LDR     ip,[sl,#_Mod$Reloc$Off]
  949.             ADD     a1,ip,a1
  950.             ;
  951.             ; Some code...
  952.             ;
  953.  
  954.     dataptr        DCD     data
  955.  
  956.     By changing the offset contained at [sl,#_Mod$Reloc$Off], the DLLMana
  957.     ger can make the code reference different areas of data.  Note that
  958.     the  value of _Mod$Reloc$Off is by default −536.
  959.  
  960.     This slight alteration to data referencing code is the only
  961.     difference which  the –zM option makes.
  962.  
  963.     The DLLManager module then keeps a table of these data relocations
  964.     for  each DLL/client pair.  When an external call is made to a DLL,
  965.     control  passes through a small entry veneer called _dll_entry, which
  966.     sets up the  relocation offset correctly, and inserts an exit veneer
  967.     (_dll_exit) to restore  it when the external procedure call returns.
  968.  
  969.  
  970. Handling exceptional control flow
  971.  
  972.     Unfortunately, normal explicit procedure call is not the only way in
  973.     which control is given to functions.  Function pointers must be used
  974.     with  care within DLLs and module clients.  All external calls except
  975.     those to  absolute program images must go through entry and exit
  976.     veneers.  Ways  of ensuring this using the C language are described
  977.     below.
  978.  
  979.     If your program bypasses the normal function return discipline (e.g.
  980.     by  using longjmp) you must ensure that the correct workspace
  981.     relocation is  used.  The DLLManager maintains a stack for each
  982.     client application,  which contains relocations and return addresses.
  983.     If the exit veneer is not  called, the stack becomes invalid.  Hence,
  984.     applications must save the stack  pointer before any return point
  985.     (e.g. setjmp), and restore it if the actual  return point is called
  986.     (by checking the result of setjmp in C).  This is  achieved using the
  987.     _dll_setjmp and _dll_longjmped functions in DLLLib,  or using SWIs
  988.     DLL_ReadStackPtr and DLL_SetStackPtr.  C++ exception  handling will
  989.     not be supported until a way is found to gain control on  entry to a
  990.     destructor during exception handling.
  991.  
  992.  
  993. Identifying applications
  994.  
  995.     For the system to work, it’s necessary for the DLLManager to be able
  996.     to  identify which application is currently executing, so that it can
  997.     substitute  the correct workspace relocation.
  998.  
  999.     Currently, applications are identified by their start time, as
  1000.     returned by  SWI OS_GetEnv.  This method causes a few problems, since
  1001.     RISC OS  only keeps a record of the start time of the most recent
  1002.     application.   Therefore applications must preserve their times over
  1003.     any system calls  which may start up new applications (e.g.
  1004.     Wimp_Poll, OS_CLI etc.)  This  restriction may be lifted if a better
  1005.     way of identifying the current  application is found.  DLLLib
  1006.     provides functions which replace the most  common offending calls
  1007.     (e.g. system).
  1008.  
  1009.  
  1010. Dynamic linking
  1011.  
  1012.     The actual linking process is very simple.  The DLLManager module has
  1013.     a  SWI DLL_FindEntry which locates a named entry point within a
  1014.     specified  DLL, and returns its address.  Data items are not exported
  1015.     directly, but it  is possible to export functions within the DLL
  1016.     which return the addresses  of data items.
  1017.  
  1018.     Looking up entry points by name, however, is a slow process, and not
  1019.     one that is really desirable for every procedure call.  Therefore,
  1020.     the  DLLManager provides a SWI DLL_FindFromTable which, when given
  1021.     pointers to tables of the appropriate format will load the DLLs
  1022.     specified,  and fill in a branch table with branch instructions to
  1023.     the required entry  points.
  1024.  
  1025.     Since looking up entry points by name is a slow process, and the
  1026.     names  take up a considerable amount of memory, you can assign a
  1027.     small integer  value called an ordinal to each routine.
  1028.  
  1029.     The format of the tables used by DLL_FindFromTable are documented in
  1030.     the reference section.
  1031.  
  1032.  
  1033. How the DLL stubs work
  1034.  
  1035.     A DLL stub object file contains three AREAs, all with attributes CODE
  1036.     and  READONLY, called DLL$$ExternalTable, DLL$$Strings and
  1037.     DLL$$Stubs.   Because the linker joins together AREAs with the same
  1038.     name into one big  AREA and provides symbols giving the start and end
  1039.     addresses of the  AREAs, this allows lots of DLL stubs to be linked
  1040.     together to make an  external DLL table (see the information about
  1041.     SWI DLL_FindFromTable). DLL$$ExternalTable contains a single entry in
  1042.     the external DLL table.   DLL$$Strings contains the name of the DLL
  1043.     to load, and the names of the  entry points required by the client.
  1044.     DLL$$Stubs contains a number of  words, into which branch
  1045.     instructions into the actual DLL may be  inserted at run time.  The
  1046.     initial value of the entries are the ordinals for  the routines to
  1047.     link to, where defined.  Otherwise, they contain the value  &E3A0F000
  1048.     − MOV PC,#0 − which will cause a ‘Branch through zero’  error if the
  1049.     table is used before it is set up properly.
  1050.  
  1051. _____________________________________________________________________________
  1052.  
  1053.  
  1054.                                DLL file format
  1055.  
  1056.  
  1057. Introduction
  1058.  
  1059.     This chapter documents version 1.01 of the DLL file format.
  1060.  
  1061.     DLL files consist of three parts:
  1062.  
  1063.     •  A DLL header which describes all the necessary parts of a DLL to
  1064.        the  DLLManager module
  1065.  
  1066.     •  The actual DLL code
  1067.  
  1068.     •  The initialisation values for the DLL’s data
  1069.  
  1070.     These parts appear in order within the file.
  1071.  
  1072.  
  1073. The DLL header
  1074.  
  1075.     A DLL header contains a fixed size part and a variable size part.
  1076.     The fixed  size part contains pointers to different sections of the
  1077.     variable size part. The fixed size part is the first object in the
  1078.     DLL file.  It contains a number  of 4 byte entries, as follows:
  1079.  
  1080.     Offset    Use
  1081.  
  1082.     0    The 4 byte value &004C4C44, which is the string ‘DLL’
  1083.         followed by a null byte.  This is used to identify valid  DLL
  1084.         files.
  1085.  
  1086.     4    The version number of the DLL file format which this
  1087.         DLL file conforms to, multiplied by 100.  Thus, version  1.01
  1088.         is represented as 101.
  1089.  
  1090.     8    The address of the DLL’s name.
  1091.  
  1092.     12    The address of the DLL’s author string.  This allows an
  1093.         author to embed copyright information within a DLL.
  1094.  
  1095.     16    The version number of the DLL, multiplied by 100.
  1096.         Note that this is distinct from the file format version
  1097.         number.
  1098.  
  1099.     20    An ARM instruction, normally a branch, which if
  1100.         excecuted will initialise the DLL, and correctly set up all
  1101.         the absolute addresses within the DLL.  This routine is
  1102.         entered in SVC mode with R13 pointing to the super visor
  1103.         stack and R14 containing a return address and  flags.
  1104.         Registers R0-R3 and R11 may be corrupted.  It is  expected
  1105.         that this is in fact the standard linker routine
  1106.         _Reloc$Code.  If your DLL requires no initialisation, this
  1107.         instruction may just be MOVS PC,R14.
  1108.  
  1109.     24    The address of the DLL’s Shared C Library stubs branch
  1110.         table, which is filled in by the DLLManager when the  DLL is
  1111.         loaded.  If the address is lower than the DLL’s  base
  1112.         address, then it is assumed that there is no Shared  C
  1113.         Library entry table.
  1114.  
  1115.     28    The number of entry points offered by the DLL, and
  1116.         flags.  If bit 31 is set, the entry veneer table (offset 36)
  1117.         is  replaced by a table of addresses of routines.  This is
  1118.         used for non-APCS DLLs.
  1119.  
  1120.     32    Pointer to the names of the DLL’s entry points, in order.
  1121.         The entry point names are each separated by a single  zero
  1122.         byte, and the last name is followed by a zero byte.   Unnamed
  1123.         ‘dummy’ entry points, created by gaps in the  ordinals are
  1124.         indicated by a byte containing the value ‘1’  instead of a
  1125.         null-terminated string.
  1126.  
  1127.     36    Pointer to the entry veneers table or routine address
  1128.         table.  There must be at least one table entry for each
  1129.         named entry point, although there may be more entries  than
  1130.         named entry points.
  1131.  
  1132.         An entry veneer is 16 bytes long.  It must set up the
  1133.         environment for the DLL appropriately and call the  actual
  1134.         code within the DLL to perform the actions  appropriate for
  1135.         that entry point.
  1136.  
  1137.         The routine address table (indicated by bit 31 being set  in
  1138.         the flags word at offset 28) contains a one word  address of
  1139.         each routine, instead of a 16 byte entry  veneer.
  1140.  
  1141.         An ordinal is simply an index into this table − the actual
  1142.         address of a routine is calculated by multiplying the
  1143.         ordinal by the size of the table entries (16 for a veneer
  1144.         table, 4 for an address table).
  1145.  
  1146.     40    Pointer to the base of the external DLL dependency
  1147.         table.  This table has the same format as that described  for
  1148.         the SWI DLL_FindFromTable.  If the pointer is equal  to the
  1149.         pointer at offset 44, then there is no external DLL
  1150.         dependency table.
  1151.  
  1152.     44    Pointer to the limit of the external DLL dependency
  1153.         table.
  1154.  
  1155.     48    Pointer to the base of the DLL’s data initialisation
  1156.         values.  This data is copied to the data area allocated for
  1157.         the DLL’s instance data to initialise it.
  1158.  
  1159.     52    Pointer to the limit of the DLL’s data initialisation
  1160.         values.  Note that this may be higher than the DLL’s  actual
  1161.         limit in memory.
  1162.  
  1163.     56    Pointer to the base of the DLL’s zero-initialised data
  1164.         area.  This value is relocated to point into the DLL’s
  1165.         instance data area and used to allow zero-initialisation  of
  1166.         the data.
  1167.  
  1168.     60    Pointer to the limit of the DLL’s zero-initialised data
  1169.         area.
  1170.  
  1171.     64    Pointer to the DLL’s application entry point branch
  1172.         table.  The format of this table and the table pointed to  by
  1173.         the next word is described with the SWI
  1174.         DLL_SetExtensionTable.
  1175.  
  1176.     68    Pointer to the names of the application entry points
  1177.         required in the previous table. The variable size part of the
  1178.         header contains the entry point names and  branch tables
  1179.         which are set up on loading the DLL.
  1180.  
  1181. _____________________________________________________________________________
  1182.  
  1183.  
  1184.                                 The cdll tool
  1185.  
  1186.  
  1187. Introduction
  1188.  
  1189.     The cdll tool will create AOF files to help you make both Dynamic
  1190.     Link  Libraries and client applications which use them.  It works
  1191.     from a script  file (called a DLL definition file) which itself may
  1192.     be created by cdll.
  1193.  
  1194.  
  1195. Format of DLL definition files
  1196.  
  1197.     The syntax of the definition files required by cdll is described
  1198.     below:
  1199.  
  1200.     definitionFile ::=    {section}
  1201.  
  1202.     section ::=        nameSection | authorSection |
  1203.                 versionSection | exportsSection |
  1204.                 extEntrySection | objectsSection
  1205.  
  1206.     nameSection ::=        ‘name’ string
  1207.  
  1208.     authorSection ::=    ‘author’ string
  1209.  
  1210.     versionSection ::=    ‘version’ {digit} [‘.’ [digit [digit]]]
  1211.  
  1212.     exportsSection ::=    ‘exports’ exportsList
  1213.  
  1214.     extEntrySection ::=    ‘extEntry’ identifierList
  1215.  
  1216.     objectsSection ::=    ‘objects’ identifierList
  1217.  
  1218.     identifierList ::=    ‘{’ {identifier} ‘}’
  1219.  
  1220.     exportsList ::=        ‘{’ {identifier [‘=’ integer]} ‘}’
  1221.  
  1222.     A string is any collection of characters contained within quotation
  1223.     marks  (either single or double − it doesn’t matter).  If you use a
  1224.     single quote to  start the string, it may contain double quotes and
  1225.     vice versa.  If you want  the string to contain the type of quote
  1226.     that it is delimited by, you must  write two quotes in a row.  If you
  1227.     don’t want to include whitespace  characters in the string, you can
  1228.     leave out the quotes altogether.  This  sounds very complicated, but
  1229.     it’s really quite simple.  Some examples of  valid strings will help:
  1230.  
  1231.         "This string doesn't contain any errors"
  1232.  
  1233.         'This string has a "quote"'
  1234.  
  1235.         '"What''s David doing?" said Sarah.'
  1236.  
  1237.         unQuotedString
  1238.  
  1239.     An identifier is any series of characters delimited by whitespace. An
  1240.     integer is a sequence of decimal digits − hex integers are not
  1241.     allowed. Comments may be inserted anywhere in the file.  Comments
  1242.     always  begin with a whitespace character (to distinguish them from
  1243.     strange  identifiers).  There are two types of comments:
  1244.  
  1245.     •  Line comments start with any one of ‘;’, ‘|’, ‘//’ or ‘#’ and
  1246.        extend to  the end of the current line.
  1247.  
  1248.     •  Block comments start with ‘/*’ and end with ‘*/’. Whitespace
  1249.        characters include spaces, newlines, tabs and formfeeds.
  1250.  
  1251.     The length of a single line is not limited.  The size of a single
  1252.     token is  limited by the available memory.
  1253.  
  1254.     Null characters (ASCII 0) are not permitted in the definition file.
  1255.  
  1256.  
  1257. Creating definition files
  1258.  
  1259.     Definition files are probably easiest created by using the cdll tool.
  1260.     You  can create a definition file from any collection of object (AOF)
  1261.     and library  (ALF) files by using the command
  1262.  
  1263.         cdll -def <output file> -o <object file>...
  1264.  
  1265.     This will create a DLL definition file called <output file>
  1266.     containing  declarations of all the external symbols defined by the
  1267.     <object file>s.   The symbols are not output in any particular order
  1268.  
  1269.  
  1270. Definition file sections
  1271.  
  1272.     The name section
  1273.  
  1274.     This section defines the name of the DLL described by the file.  If
  1275.     the file  is not being used to describe a DLL, this section is
  1276.     ignored and may be  omitted.
  1277.  
  1278.     The name may be at most 10 characters long.
  1279.  
  1280.     See the section Registering names for more details about DLL names.
  1281.  
  1282.     The author section
  1283.  
  1284.     This section may contain any string of up to 49 characters, although
  1285.     it is  anticipated that this will be used to contain the author’s
  1286.     copyright notice  or similar string.  It is ignored if the file is
  1287.     not being used to describe a  DLL, and may be omitted under these
  1288.     circumstances.
  1289.  
  1290.     The version section
  1291.  
  1292.     This section defines the version number of the DLL described by the
  1293.     file.   If the file is not being used to describe a DLL, this section
  1294.     is ignored and  may be omitted.
  1295.  
  1296.     The version number contains a major version number, which is any
  1297.     collection of digits, a ‘.’ and between zero and two more digits of
  1298.     minor  version number.
  1299.  
  1300.     It is vitally important that this number is kept up to date, and that
  1301.     it is  increased with every new version released.  Failure to do this
  1302.     can cause  severe problems.
  1303.  
  1304.     The exports section
  1305.  
  1306.     This section declares all the symbols exported by the DLL or
  1307.     application  described by the file.
  1308.  
  1309.     When creating DLL headers or application entry points (see below),
  1310.     this  section defines the symbols whose names are to be placed in the
  1311.     entry  point table.  Entry veneers are also created for each of the
  1312.     symbols  specified.  You should not put symbols which do not need to
  1313.     be exported  to clients in this section − you should use the extEntry
  1314.     section for these  instead.
  1315.  
  1316.     Each name decared in this section may have an ordinal specified with
  1317.     it.   An ordinal is simply an unsigned integer which defines the
  1318.     particular  entry point uniquely within the DLL or application.  Note
  1319.     that the  ordinals should start at 0 and should form a contiguous
  1320.     sequence.  Gaps  in the sequence cause space to be wasted in the
  1321.     entry point table.  Using  ordinals makes application startup faster
  1322.     and uses less memory.   However, you must ensure that the ordinal for
  1323.     each routine stays the  same for all versions of the library.
  1324.  
  1325.     This section is filled in in no particular order by cdll when
  1326.     creating  definition files.  cdll does not automatically assign
  1327.     ordinals to entry point  names.
  1328.  
  1329.     The extEntry section
  1330.  
  1331.     This section declares routines which require veneers to be called
  1332.     externally (e.g. any routine in a DLL which may be called externally
  1333.     through a function pointer).
  1334.  
  1335.     When creating DLL headers (see below), this section defines the
  1336.     symbols  which must have veneers created for them but which should
  1337.     not be  included in the entry point table (i.e. they should not be
  1338.     called directly by  clients).
  1339.  
  1340.     When creating veneers for DLL clients (e.g. module clients), this
  1341.     section  defines the symbols which must have veneers created for them
  1342.     because  they can be called externally.
  1343.  
  1344.     The objects section
  1345.  
  1346.     This section gives the names of the object files (both AOF and ALF)
  1347.     which  contain the symbols declared in the exports and extEntry
  1348.     sections.  This is  so that cdll can check that all of these symbols
  1349.     are valid and defined, in an  attempt to prevent errors.
  1350.  
  1351.  
  1352. Creating DLL headers with cdll
  1353.  
  1354.     DLL headers contain all the information the DLLManager needs to know
  1355.     about a particular DLL.  These can then be linked with the object
  1356.     files  which contain the actual DLL code to create the finished DLL.
  1357.  
  1358.     The command line to create a DLL header from a DLL definition file
  1359.     is:
  1360.  
  1361.         cdll -def <defn file> -hdr <header file>
  1362.  
  1363.     which creates a DLL header from the DLL definition file <defn file>
  1364.     and  outputs the DLL header in an AOF file called <header file>. The
  1365.     entry veneers for the DLL’s entry points are each given symbols
  1366.     formed by prefixing the name of the routine being veneered with the
  1367.     string ‘_dllEntry_’, so that for example the routine wimpt_init has
  1368.     an  entry veneer called _dllEntry_wimpt_init.  This applies to
  1369.     symbols in  both the exports and extEntry sections.
  1370.  
  1371.  
  1372. Creating DLL stubs with cdll
  1373.  
  1374.     In order to automate the process of initialising a program which uses
  1375.     shared DLLs, it is possible to create tables describing the DLLs
  1376.     required  by the program.  These tables are detected by the
  1377.     replacement Shared C  Library stubs, which proceed to find the
  1378.     required DLLs and fill in branch  tables with branches to entry
  1379.     points within the DLLs.  The tables are  contained in AOF files
  1380.     called DLL stubs which may be linked with the  client’s main code.
  1381.     The DLLs are found while the Shared C Library is  initialising (i.e.
  1382.     before main is called), so that the linking process is entirely
  1383.     transparent.
  1384.  
  1385.     The DLL stubs may be linked in place of an equivalent statically
  1386.     linked  library to produce the same result, or both could be linked,
  1387.     in which case  as many external references as possible would be
  1388.     resolved through the  DLL stubs, with any remaining being resolved by
  1389.     the statically linked  library in the usual way.
  1390.  
  1391.     To create a DLL stubs file, use the command
  1392.  
  1393.         cdll -def <defn file> -stub <stub file>
  1394.  
  1395.     This creates a DLL stub AOF file called <stub file> for the DLL
  1396.     described  by <defn file>.
  1397.  
  1398. Creating external entry points for clients with cdll
  1399.  
  1400.     If the client requires that the data relocation be set up correctly
  1401.     (e.g. it is a  module task and needs to be able to access its module
  1402.     workspace), any  external calls to the client must be veneered.
  1403.     Veneers may be set up by  using an abbreviated definition file
  1404.     containing only the extEntry and  objects sections.  The command
  1405.  
  1406.         cdll -def <defn file> -ext <veneer file>
  1407.  
  1408.     then creates an AOF file called <veneer file> which contains the
  1409.     entry  veneers.  These are very small (only 16 bytes each), but they
  1410.     require a  routine in DLLLib for them to work, so remember to link
  1411.     this in. For each symbol name named in the <defn file>, this creates
  1412.     an entry  veneer called _extEntry_name.  We recommend you use the
  1413.     macro  _extEntry defined in dll.h to define these names.
  1414.  
  1415. _____________________________________________________________________________
  1416.  
  1417.  
  1418.                             The DLLManager module
  1419.  
  1420.  
  1421. Overview
  1422.  
  1423.     The DLLManager module offers a simple set of *commands and a
  1424.     selection of SWI calls for handling Dynamic Link Libraries. Notes
  1425.     about the examples
  1426.  
  1427.     All the examples in this sections are written using the syntax of the
  1428.     Acorn  ARM Assembler, rather than that of the standard BASIC
  1429.     assembler.  This  is because programs which use DLLs are more likely
  1430.     to be written using  the ARM Assembler since its output may be linked
  1431.     with programs  written in high-level languages.
  1432.  
  1433.     Most of the examples are given in the form of complete source files
  1434.     except  that definitions of register names and SWI numbers are
  1435.     omitted.   You may use the example code in your own programs if you
  1436.     want to −  that’s what it’s there for.
  1437.  
  1438. SWI calls
  1439.  
  1440.     Some standard conventions should be observed when communicating  with
  1441.     the DLLManager:
  1442.  
  1443.     •  All strings passed to the DLLManager should be 0-terminated.  The
  1444.        addresses of such strings do not have to be word aligned.
  1445.  
  1446.     •  All other pointers passed to the DLLManager must be word-aligned.
  1447.  
  1448.     •  Version numbers are expressed as integers by multiplying by 100
  1449.        (so  version 7.24 would be represented as 724).
  1450.  
  1451.     •  Unless otherwise stated, R0 is always corrupted on exit from a SWI
  1452.        call, and other registers are preserved.
  1453.  
  1454.     •  All the SWIs execute in SVC mode, they run with FIQs enabled and
  1455.        do not alter the IRQ status.  The re-entrancy of the SWI routines
  1456.        is not  defined, and they should not be used from an interrupt
  1457.        routine.
  1458.  
  1459.     Each SWI call (except DLL_Prologue) has a corresponding function in
  1460.     DLLLib which allows the SWI to be used from C.  These are documented
  1461.     with the SWI here, rather than in the section on DLLLib.  All these
  1462.     functions have names beginning with ‘dll_’, followed by the name of
  1463.     the  SWI (without the ‘DLL_’ prefix) with a lower-case first letter.
  1464.     They all  return a pointer to an os_error structure, which either is
  1465.     NULL to indicate  that the SWI was successful, or contains error
  1466.     information returned by  DLLManager.
  1467.  
  1468.  
  1469.                             DLL_Find (SWI &4A300)
  1470.  
  1471.     Links an application to a named shared DLL
  1472.  
  1473. From assembler
  1474.  
  1475.     On entry    R0 = pointer to DLL name
  1476.             R1 = version number required
  1477.  
  1478.     On exit        R0 = DLL handle for the DLL
  1479.  
  1480. From C
  1481.  
  1482.     Prototype    os_error *dll_find(const char *name,
  1483.                                int version,
  1484.                                dll *d)
  1485.  
  1486.     Arguments    name = pointer to the DLL name (R0)
  1487.             version = version number of DLL to load
  1488.             dll = pointer to DLL handle to set
  1489.  
  1490. Use
  1491.  
  1492.     This SWI loads the specified DLL into memory if necessary, and
  1493.     returns a  handle to it.
  1494.  
  1495.     The name pointed to by R0 (name) must be either a DLL name (up to 10
  1496.     characters long, case-insensitive) or a fully qualified file name (in
  1497.     which  case the leafname is used as the DLL name).
  1498.  
  1499.     Only DLLs whose version number is greater than or equal to that given
  1500.     in  R1 (version) are found.
  1501.  
  1502.     If the DLL is not currently in memory, it is loaded into the RMA in a
  1503.     way  similar to that performed by DLL_Load.  The file loaded is
  1504.     determined by  the name pointed to by R0:
  1505.  
  1506.     •  If R0 points to a leafname only, the file loaded is given by
  1507.        prefixing  the name with ‘DLL:’ (i.e. the variable DLL$Path is
  1508.        searched, as set up  by the DLLs resource.
  1509.  
  1510.     •  If R0 points to a fully qualified path name, it is assumed that
  1511.        this is the  name of the file to load.  Therefore it is essential
  1512.        that the leafname of  the DLL file matches the name specified in
  1513.        its header. Note that after Finding a DLL, you must supply some
  1514.        space for its  instance variables using DLL_InstanceVars.
  1515.  
  1516. Example of use
  1517.  
  1518.     The example below shows the loading of a single DLL named ‘Steel’.
  1519.  
  1520.             ADR    R0,steelName
  1521.             LDR    R1,=104
  1522.             SWI    DLL_Find
  1523.             STR    R0,steelHnd
  1524.             ;
  1525.             ; Carry on with initialisation...
  1526.             ;
  1527.  
  1528.     steelName    DCB    "Steel",0
  1529.             ALIGN
  1530.     steelHnd        DCD    0
  1531.  
  1532.  
  1533.  
  1534.                            DLL_FindFromTable (SWI &4A301)
  1535.  
  1536. Links an application to a number of DLLs
  1537.  
  1538. From assembler
  1539.  
  1540.     On entry    R0 = pointer to start of external DLL block
  1541.             R1 = pointer to limit (end+1) of external DLL block
  1542.  
  1543.     On exit        –
  1544.  
  1545. From C
  1546.  
  1547.     Prototype    os_error *dll_findFromTable(const dll_table *t,
  1548.                             int entries)
  1549.  
  1550.     Arguments    table = a pointer to an array of dll_table entries
  1551.             entries = the number of entries in this table
  1552.  
  1553. Use
  1554.  
  1555.     Registers your application as wanting to use DLLs, and finds (using
  1556.     DLL_Find) the DLLs specified in the external DLL block.  R0 and R1
  1557.     may  be equal, in which case no attempt to find any DLLs is made. The
  1558.     entries in the table are as follows:
  1559.  
  1560.         Table 10.1
  1561.  
  1562.     The entry point name table consists of a number of 0-terminated
  1563.     strings  concatenated together.  The table is terminated by a
  1564.     zero-length string.   Each word in the branch table is filled in turn
  1565.     with a branch instruction to  the address of the next named entry
  1566.     point.
  1567.  
  1568.     If the initial value of a word in the branch table is a valid ordinal
  1569.     value  (i.e. it is lower than the number of entry points declared by
  1570.     the DLL), it is  interpreted as such and the entry is resolved
  1571.     without looking up a name.   If the final entry is a valid ordinal,
  1572.     there must be an additional out-of- range value on the end (e.g.
  1573.     &FFFFFFFF).
  1574.  
  1575.     The name table should contain a name for each word in the branch
  1576.     table  which is not an ordinal.
  1577.  
  1578. Example of use
  1579.  
  1580.     The example code is very similar to that used by the DLLLib library
  1581.     to  load in any DLLs specified in cdll-created DLL stubs files.
  1582.  
  1583.             IMPORT    |DLL$$Data$$Base|
  1584.             IMPORT    |DLL$$Data$$Limit|
  1585.             IMPORT    |x$stack_overflow|
  1586.             IMPORT    giveMemory
  1587.  
  1588.             AREA    |Example$$Code|,CODE,READONLY
  1589.  
  1590.     ; linkAll
  1591.     ;
  1592.     ; On entry:    --
  1593.     ; On exit:    a1 == 0 for success, or pointer to error block
  1594.  
  1595.             EXPORT    linkAll
  1596.     linkAll        ROUT
  1597.  
  1598.             ; --- Standard APCS header ---
  1599.  
  1600.             MOV    ip,sp
  1601.             STMFD    sp!,{fp,ip,lr,pc}
  1602.             CMP    sp,sl
  1603.             BLLT    |x$stack_overflow|
  1604.             SUB    fp,ip,#4
  1605.  
  1606.             ; --- Load DLLs as required ---
  1607.  
  1608.             LDR    a1,|DLL$$Data$$Base|    ;Find base of the DLL table
  1609.             LDR    a2,|DLL$$Data$$Limit|    ;Find the end of the table
  1610.             SWI    XDLL_FindFromTable    ;Load the DLLs we want
  1611.             LDMVSDB    fp,{fp,sp,pc}^        ;If it failed, return error
  1612.  
  1613.             ; --- Now allocate workspace for them ---
  1614.             ;
  1615.             ; We use the giveMemory code shown in the
  1616.             ; example for SWI DLL_InstanceVars for this
  1617.  
  1618.             BL    giveMemory        ;Set up DLL instance vars
  1619.             LDMDB    fp,{fp,sp,pc}^        ;Return with that error code
  1620.  
  1621.             LTORG
  1622.  
  1623.             END
  1624.  
  1625.  
  1626.  
  1627.                             DLL_Load (SWI &4A302)
  1628.  
  1629.     Loads a DLL into an application’s memory (for extendible applications)
  1630.  
  1631. From assembler
  1632.  
  1633.     On entry    R0 = pointer to block of memory
  1634.             R1 = pointer to filename of DLL
  1635.  
  1636.     On exit        –
  1637.  
  1638. From C
  1639.  
  1640.     Prototype    os_error *dll_load(void *buffer,
  1641.                                const char *name)
  1642.  
  1643.     Arguments    buffer = pointer to a block in which to load the DLL
  1644.             name = the name of the file containing the DLL
  1645.  
  1646. Use
  1647.  
  1648.     Loads a dynamic link library into a block of memory. This low-level
  1649.     operation is for occasions when you don’t want a DLL to be shared
  1650.     (e.g. if  it contains user-provided extensions to a specific
  1651.     application). The block pointed to by R0 (buffer) needs to be 20
  1652.     bytes larger than the  DLL itself (you should have already found the
  1653.     size of the DLL file using  OS_File).  This call will load, check and
  1654.     relocate the DLL.  Note that you  will need to supply the DLL with
  1655.     its workspace using DLL_Info and  DLL_SetInstanceVars.
  1656.  
  1657.     You can free the space used by the DLL at any time if you don’t want
  1658.     to  use it any more – no data structures are set up by the
  1659.     DLLManager. Note that the DLL loaded may cause other DLLs to be
  1660.     loaded using  DLL_Find, and so, after calling DLL_Load, you should
  1661.     enter a  DLL_InstanceVars loop to allocate instance variables for
  1662.     them.
  1663.  
  1664. Example of use
  1665.  
  1666.     The example below is very similar to the implementation of the
  1667.     _dll_loadExtension function in DLLLib.  It demonstrates how to load
  1668.     an  extension DLL and initialise it properly.
  1669.  
  1670.             IMPORT    |x$stack_overflow|
  1671.             IMPORT    malloc
  1672.             IMPORT    free
  1673.             IMPORT    giveMemory
  1674.  
  1675.             AREA    |Example$$Code|,CODE,READONLY
  1676.  
  1677.     ; loadLocal
  1678.     ;
  1679.     ; On entry:    a1 == pointer to name of DLL to load
  1680.     ; On exit:    a1 == DLL handle for DLL, or 0 for failure
  1681.  
  1682.             EXPORT    loadLocal
  1683.     loadLocal    ROUT
  1684.  
  1685.             ; --- APCS header ---
  1686.  
  1687.             MOV    ip,sp
  1688.             STMFD    sp!,{v1-v3,fp,ip,lr,pc}
  1689.             SUB    fp,ip,#4
  1690.             CMP    sp,sl
  1691.             BLLT    |x$stack_overflow|
  1692.  
  1693.             ; --- Find the size of the DLL file ---
  1694.  
  1695.             MOV    v3,a1            ;Keep the name pointer safe
  1696.             MOV    a2,a1            ;Point to the filename
  1697.             MOV    a1,#17            ;Get information on file
  1698.             SWI    XOS_File        ;Get the information
  1699.             BVS    %10loadLocal        ;If it failed, return
  1700.             CMP    a1,#1            ;Make sure it found a file
  1701.             BNE    %10loadLocal        ;If not, make an error
  1702.  
  1703.             ; --- Allocate a block for the DLL ---
  1704.  
  1705.             ADD    a1,v1,#20        ;Allow space for DLLManager
  1706.             BL    malloc            ;Allocate the memory
  1707.             CMP    a1,#0            ;Was there enough memory?
  1708.             BEQ    %10loadLocal        ;No -- return unhappy
  1709.             MOV    v2,a1            ;Keep hold of the pointer
  1710.  
  1711.             ; --- Load the DLL into the block ---
  1712.  
  1713.             MOV    a2,v3            ;Point to the filename
  1714.             SWI    XDLL_Load        ;Load the DLL and set it up
  1715.             BVS    %11loadLocal        ;If it failed, tidy up
  1716.  
  1717.             ; --- Allocate workspace for the DLL ---
  1718.  
  1719.             MOV    a1,v2            ;Get the 'DLL handle'
  1720.             SWI    XDLL_Info        ;Find out about the DLL
  1721.             MOV    a1,v1            ;Get the workspace size
  1722.             BL      malloc            ;Allocate the memory
  1723.             CMP    a1,#0            ;Was there enough?
  1724.             BEQ    %11loadLocal        ;No -- tidy everything up
  1725.             MOV    v1,a1            ;Look after the pointer
  1726.             MOV    a2,a1            ;Point to this new block
  1727.             MOV    a1,v2            ;Point to the DLL block
  1728.             SWI    XDLL_SetInstanceVars    ;Attach the workspace
  1729.  
  1730.             ; --- Allocate space for new DLLs loaded ---
  1731.             ;
  1732.             ; Here we use the giveMemory function shown
  1733.             ; in the example code for DLL_InstanceVars
  1734.  
  1735.             BL    giveMemory        ;Set up new shared DLLs
  1736.             CMP    a1,#0            ;Did that fail?
  1737.             BNE    %12loadLocal        ;Yes -- tidy everything up
  1738.  
  1739.             ; --- Return the DLL handle to the caller ---
  1740.  
  1741.             MOV    a1,v2            ;Point to the DLL block
  1742.             LDMDB    fp,{v1-v3,fp,sp,pc}^    ;Return to the caller
  1743.  
  1744.             ; --- Free DLL's instance vars ---
  1745.  
  1746.     12loadLocal    MOV    a1,v1            ;Point to the workspace
  1747.             BL    free            ;Free the block
  1748.             ; Drop through to free DLL block
  1749.  
  1750.             ; --- Free DLL block and return to caller ---
  1751.  
  1752.     11loadLocal    MOV    a1,v2            ;Point to the DLL block
  1753.             BL    free            ;Free that up nicely
  1754.             ; Drop through to exit failed
  1755.  
  1756.             ; --- Return to caller -- we failed ---
  1757.  
  1758.     10loadLocal    MOV    a1,#0            ;Return a NULL pointer
  1759.             LDMDB    fp,{v1-v3,fp,sp,pc}^    ;Return to caller
  1760.  
  1761.             LTORG
  1762.  
  1763.             END
  1764.  
  1765.  
  1766.  
  1767.                             DLL_Lose (SWI &4A303)
  1768.  
  1769. Informs DLLManager that an application no longer needs a shared DLL
  1770.  
  1771. From assembler
  1772.  
  1773.     On entry    R0 = DLL handle of DLL to remove
  1774.  
  1775.     On exit        –
  1776.  
  1777. From C
  1778.  
  1779.     Prototype    os_error *dll_lose(dll d)
  1780.  
  1781.     Arguments    d = DLL handle of DLL to remove
  1782.  
  1783. Use
  1784.  
  1785.     Removes your application from the list of those using the specified
  1786.     DLL.   If your application was the only one using the DLL, then it
  1787.     will be  removed from memory.
  1788.  
  1789. Example of use
  1790.  
  1791.     The example shows how the DLL loaded in the example for DLL_Find
  1792.     might be disposed of later.
  1793.  
  1794.             ;
  1795.             ; Finalisation code...
  1796.             ;
  1797.             LDR    R0,steelHnd
  1798.             SWI    DLL_Lose
  1799.             ;
  1800.             ; More code...
  1801.             ;
  1802.  
  1803.                             DLL_AppDying (SWI &4A304)
  1804.  
  1805.     Informs the DLLManager that the application is quitting
  1806.  
  1807. From assembler
  1808.  
  1809.     On entry    –
  1810.  
  1811.     On exit        –
  1812.  
  1813. From C
  1814.  
  1815.     Prototype    os_error *dll_appDying(void)
  1816.  
  1817.     Arguments    −
  1818.  
  1819. Use
  1820.  
  1821.     Makes the DLLManager forget about your application, Losing any DLLs
  1822.     it  Found for you etc.
  1823.  
  1824.  
  1825.                         DLL_GiveCLibData (SWI &4A305)
  1826.  
  1827.     Informs the DLLManager where the application’s C Library data is
  1828.  
  1829. From assembler
  1830.  
  1831.     On entry    R0 = pointer to start of C Library data
  1832.  
  1833.     On exit        –
  1834.  
  1835. From C
  1836.  
  1837.     Prototype    os_error *dll_giveCLibData(void *data)
  1838.  
  1839.     Arguments    data = pointer to start of C Library data
  1840.  
  1841. Use
  1842.  
  1843.     Declares to the DLLManager the position of the C Library data for
  1844.     this  application.  This information is used by DLL_FindCLibData to
  1845.     locate  exported CLib data from within a DLL.
  1846.  
  1847.     The Shared C Library data area is considered to begin at the address
  1848.     of  __errno.  Thus it is the address of __errno that should be passed
  1849.     in R0.
  1850.  
  1851. Example of use
  1852.  
  1853.     The example code fragment below just sets up the Shared C Library
  1854.     address for the current application.
  1855.  
  1856.         LDR    R0,=|__errno|
  1857.         SWI    XDLL_GiveCLibData
  1858.         ;
  1859.         ; Continue with initialisation...
  1860.         ;
  1861.  
  1862.  
  1863.                         DLL_FindCLibData (SWI &4A306)
  1864.  
  1865.     Finds the C Library data for the current application
  1866.  
  1867. From assembler
  1868.  
  1869.     On entry    –
  1870.  
  1871.     On exit        R0 = pointer to start of C Library data
  1872.  
  1873. From C
  1874.  
  1875.     Prototype    os_error *dll_findCLibData(void **p)
  1876.  
  1877.     Arguments    p = *p is set up to point to C Library data
  1878.  
  1879. Use
  1880.  
  1881.     Finds the client’s C Library data, as set up with DLL_GiveCLibData.
  1882.     It is  an error to call this SWI without the application having
  1883.     called  DLL_GiveCLibData.
  1884.  
  1885.     The Shared C Library data is considered to begin at the address of
  1886.     __errno, and thus this call actually gives the address of __errno.
  1887.     It is  mainly used by the DLLLib functions _dll_errno, _dll_iob,
  1888.     _dll_ctype  and _dll_hugeval to locate items of the client’s C
  1889.     Library data from within  a DLL.
  1890.  
  1891.  
  1892.                         DLL_InstanceVars (SWI &4A307)
  1893.  
  1894.     Sets up workspace for the shared DLLs linked to the current
  1895.     application
  1896.  
  1897. From assembler
  1898.  
  1899.     On entry    R0 = First call:    −
  1900.                  Subsequent calls:     pointer to a block of
  1901.                         size given by  previous
  1902.                         call, or 0 if not enough
  1903.                         memory was available
  1904.             R4 = First call:    0 for first call
  1905.                  Subsequent calls:    R4 value from previous call
  1906.  
  1907.     On exit        R0 = size of block required for instance variables
  1908.             R4 = 0 (no more DLLs to allocate for) or value to
  1909.                  pass to  next call
  1910.  
  1911. From C
  1912.  
  1913.     Prototype    os_error *dll_instanceVars(void *buffer,
  1914.                    int *size,
  1915.                    int *magic)
  1916.  
  1917.     Arguments    buffer = a pointer to a block of memory whose size is
  1918.                       size  as returned by the previous call
  1919.             size = pointer to an integer to fill in with the size
  1920.                    of the next block to allocate
  1921.             magic = pointer to an integer, initially zero, to
  1922.                 pass back to  the next call.  magic will be
  1923.                 reset to 0 to indicate the  end of the loop.
  1924.  
  1925. Use
  1926.  
  1927.     The call should be used in a loop.  Each time the call returns R4
  1928.     non-zero,  R0 bytes of data should be allocated and passed to the
  1929.     next call.  R4 is  used here because it is preserved over calls to
  1930.     APCS routines (e.g. malloc).   See the flowchart in figure 10.1 for
  1931.     the recommended sequence.
  1932.  
  1933.         Figure 10.1: Flowchart for calling DLL_InstanceVars
  1934.  
  1935.     If you cannot allocate enough memory, you have two choices:
  1936.  
  1937.     •  Abort the loop and report an error
  1938.  
  1939.     •  Pass R0 (buffer) back to DLL_InstanceVars as 0.  DLL_InstanceVars
  1940.        will return an error.
  1941.  
  1942.     Note that this call will only allocate space for instance variables
  1943.     loaded  using DLL_Find.  You have to use DLL_SetInstanceVars for DLLs
  1944.     loaded  by DLL_Load.
  1945.  
  1946. Example of use
  1947.  
  1948.     The example below shows the implementation of the giveMemory function
  1949.     used in the examples for DLL_Load and DLL_FindFromTable.
  1950.  
  1951.             IMPORT    |x$stack_overflow|
  1952.             IMPORT    malloc
  1953.  
  1954.             AREA    |Example$$Code|,CODE,READONLY
  1955.  
  1956.     ; giveMemory
  1957.     ;
  1958.     ; On entry:    --
  1959.     ; On exit:    a1 == 0 for success, or pointer to error
  1960.  
  1961.             EXPORT    giveMemory
  1962.     giveMemory    ROUT
  1963.  
  1964.             MOV    ip,sp
  1965.             STMFD    sp!,{v1,fp,ip,lr,pc}
  1966.             SUB    fp,ip,#4
  1967.             CMP    sp,sl
  1968.             BLLT    |x$stack_overflow|
  1969.  
  1970.             MOV    v1,#0            ;R4 starts off as 0
  1971.     00giveMemory    SWI    XDLL_InstanceVars    ;Get another block size
  1972.             LDMVSDB    fp,{v1,fp,sp,pc}^    ;If it failed, return
  1973.             CMP    v1,#0            ;Is that the end now?
  1974.             MOVEQ    a1,#0            ;Yes -- exit with no error
  1975.             LDMEQDB    fp,{v1,fp,sp,pc}^    ;Return to caller
  1976.             BL    malloc            ;Allocate the block
  1977.             B    %00giveMemory        ;And go round for another
  1978.  
  1979.             LTORG
  1980.  
  1981.             END
  1982.  
  1983.  
  1984.                          DLL_SetInstanceVars (&4A308)
  1985.  
  1986.     Sets up workspace for a non-shared DLL
  1987.  
  1988. From assembler
  1989.  
  1990.     On entry    R0 = DLL handle
  1991.             R1 = pointer to block for instance variables
  1992.  
  1993.     On exit        –
  1994.  
  1995. From C
  1996.  
  1997.     Prototype    os_error *dll_setInstanceVars(dll d,void *workspace)
  1998.  
  1999.     Arguments    d = the DLL handle
  2000.             workspace = pointer to block for instance variables
  2001.  
  2002. Use
  2003.  
  2004.     Provides instance variables for a DLL which was loaded using DLL_Load
  2005.     (not DLL_Find or DLL_FindFromTable).  The DLL handle of such a DLL
  2006.     is the block pointer passed to DLL_Load to load it. You should read
  2007.     the required size of the workspace block using  DLL_Info.
  2008.  
  2009. Example of use
  2010.  
  2011.     See DLL_Load for an example of using this SWI.
  2012.  
  2013.  
  2014.                              DLL_AppData (SWI &4A309)
  2015.  
  2016.     Informs the DLLManager of the location of the current application’s
  2017.     workspace
  2018.  
  2019. From assembler
  2020.  
  2021.     On entry    R0 = stack limit pointer (R10 under APCS-R)
  2022.  
  2023.     On exit        –
  2024.  
  2025. From C
  2026.  
  2027.     Prototype    os_error *dll_appData(void)
  2028.  
  2029.     Arguments    −
  2030.  
  2031.     dll_appData finds the stack limit pointer automatically.  You do not
  2032.     need  to specify it yourself.
  2033.  
  2034. Use
  2035.  
  2036.     Declares the application’s data relocation to the DLLManager, so that
  2037.     it  may be found using DLL_Prologue with a null DLL handle.  This is
  2038.     required by module tasks which have external entry veneers.
  2039.  
  2040. Example of use
  2041.  
  2042.     This example shows how a typical module might declare its own data
  2043.     pointer.
  2044.  
  2045.         MOV    al,sl            ;Pass pointer to stack limit
  2046.         SWI    DLL_AppData        ;Register with DLLManager
  2047.  
  2048.  
  2049.                             DLL_Prologue (&4A30A)
  2050.  
  2051.     Part of the standard DLL entry veneer code
  2052.  
  2053. From assembler
  2054.  
  2055.     On entry    R0 = return address of this routine
  2056.             R1 = pointer to stack limit structure
  2057.             R2 = pointer to base of DLL code, or 0
  2058.  
  2059.  
  2060.     On exit        R0 = new return address (pointer into DLLManager
  2061.                  code)
  2062.             R1 preserved
  2063.             R2 preserved
  2064.  
  2065. From C
  2066.  
  2067.     Use of this SWI from C is not supported.
  2068.  
  2069. Use
  2070.  
  2071.     Used in the DLL prologue code to patch up accesses to instance
  2072.     variables.   You shouldn’t need to worry about this one too much.  R2
  2073.     is not a DLL  handle, and the relationship between a DLL handle and
  2074.     the DLL’s code  base address is not defined.  This value of R2 is
  2075.     chosen because it allows a  DLL to find a value which identifies
  2076.     itself to DLLManager efficiently. An R2 value of 0 indicates that you
  2077.     want to find the variables for the base  application (usually a
  2078.     module) as registered by DLL_AppData.
  2079.  
  2080. Example of use
  2081.  
  2082.     The example below illustrates how the veneers generated by cdll work.
  2083.  
  2084.             ; --- Common part of veneers ---
  2085.  
  2086.     |_dll_common|    MOV    R0,lr
  2087.             MOV    R1,sl
  2088.             ADR    R2,|_dll_base|
  2089.             SWI    DLL_Prologue
  2090.             MOV    lr,R0
  2091.             LDMFD    sp!,{R0-R2}
  2092.             MOV    pc,ip
  2093.  
  2094.             ; --- Example entry point ---
  2095.  
  2096.             EXPORT    |_dllEntry_foo|
  2097.             IMPORT    foo
  2098.  
  2099.     |_dllEntry_foo|    STMFD    sp!,{R0-R2}
  2100.             LDR    ip,[pc]
  2101.             B    |_dll_common|
  2102.             DCD    foo
  2103.  
  2104.  
  2105.                         DLL_ReadStackPtr (SWI &4A30B)
  2106.  
  2107.     Reads the DLL stack pointer to allow for exceptional flow control
  2108.  
  2109. From assembler
  2110.  
  2111.     On entry    −
  2112.  
  2113.     On exit        R0 = a number suitable for passing to DLL_SetStackPtr
  2114.  
  2115. From C
  2116.  
  2117.     Prototype    os_error *dll_readStackPtr(int *sp)
  2118.  
  2119.     Arguments    sp = *sp is set to a value which may be passed to
  2120.             dll_setStackPtr.
  2121.  
  2122. Use
  2123.  
  2124.     When a call is made through a DLL or application external entry
  2125.     point,  the caller’s workspace pointer is saved on a special stack.
  2126.     During normal  procedure return, this stack is handled transparently
  2127.     by the DLLManager.   However, if control flow is abnormal (e.g. if
  2128.     you use setjmp and longjmp),  the jump target may have the wrong data
  2129.     pointer.
  2130.  
  2131.     By saving the stack pointer immediately before a longjmp target (or
  2132.     similar), and restoring it after a return via longjmp, this problem
  2133.     may be  circumvented.
  2134.  
  2135.     This routine will read a stack pointer in a form which may be later
  2136.     passed  to DLL_SetStackPtr.
  2137.  
  2138. Example of use
  2139.  
  2140.     _dll_setjmp (see the section on DLLLib below) provides a better way
  2141.     of  calling this SWI, and you should see that call for an example of
  2142.     its use.
  2143.  
  2144. DLL_SetStackPtr (&4A30C)
  2145.  
  2146.     Sets the DLL stack pointer on return via exceptional control flow
  2147.  
  2148. From assembler
  2149.  
  2150.     On entry    R0 = a number returned by DLL_ReadStackPtr
  2151.             R1 = current stack limit value
  2152.  
  2153.     On exit        −
  2154.  
  2155. From C
  2156.  
  2157.     Prototype    os_error *dll_setStackPtr(int sp)
  2158.  
  2159.     Arguments    sp = an integer set up by dll_readStackPtr.
  2160.  
  2161.     dll_setStackPtr finds the current stack limit automatically.  You do
  2162.     not  need to specify it yourself.
  2163.  
  2164. Use
  2165.  
  2166.     This routine will set the DLL workspace stack pointer from a value
  2167.     set up  by an earlier call to DLL_ReadStackPtr (q.v. for more
  2168.     information).  It also  sets up the data relocation correctly for the
  2169.     stack pointer position.  If the  stack is returned to top-level, the
  2170.     relocation is set from the client’s original  relocation (set through
  2171.     DLL_AppData).
  2172.  
  2173. Example of use
  2174.  
  2175.     _dll_longjmped (see the section on DLLLib below) provides a better
  2176.     way of  calling this routine.  See _dll_setjmp for an example of the
  2177.     use of this  routine.
  2178.  
  2179.  
  2180.                              DLL_NameApp (SWI &4A30D)
  2181.  
  2182.     Gives a name to the current application
  2183.  
  2184. From assembler
  2185.  
  2186.     On entry    R0 = pointer to application name
  2187.  
  2188.     On exit        –
  2189.  
  2190. From C
  2191.  
  2192.     Prototype    os_error *dll_nameApp(const char *name)
  2193.  
  2194.     Arguments    name = pointer to the application’s name.
  2195.  
  2196. Use
  2197.  
  2198.     Sets up the current application as having the given name.  This name
  2199.     is  used by various DLLManager *commands.
  2200.  
  2201.     The name may be up to 10 characters long, it must not contain spaces
  2202.     or  control characters and it must be unique in a case-insensitive
  2203.     way.
  2204.  
  2205.     For details on the requirements for names, see the chapter
  2206.     Registering  names.
  2207.  
  2208.  
  2209. DLL_Info (SWI &4A30E)
  2210.  
  2211.     Find information about a specified DLL
  2212.  
  2213. From assembler
  2214.  
  2215.     On entry    R0 = DLL handle
  2216.  
  2217.     On exit        R0 preserved
  2218.             R1 = pointer to DLL’s name
  2219.             R2 = version number of DLL
  2220.             R3 = pointer to DLL’s copyright string
  2221.             R4 = size of DLL’s instance variable requirements
  2222.  
  2223. From C
  2224.  
  2225.     Prototype    os_error *dll_info(dll d,dll_infostr *i)
  2226.  
  2227.     Arguments    d = the handle of the DLL about which to find
  2228.                 information
  2229.             i = a pointer to an information structure to fill in
  2230.  
  2231.     dll_infostr fields
  2232.         dll d = the DLL handle passed as d above
  2233.         char *name = pointer to the DLL’s name
  2234.         int version = version number of the DLL
  2235.         char *author = pointer to the DLL’s author string
  2236.         unsigned instSize = size in bytes of the DLL’s workspace
  2237.  
  2238. Use
  2239.  
  2240.     Gives pieces of information of varying usefulness about the specified
  2241.     DLL.
  2242.  
  2243. Example of use
  2244.  
  2245.     See DLL_Load for an example of using this SWI.
  2246.  
  2247.  
  2248.                            DLL_FindEntry (SWI &4A30F)
  2249.  
  2250.     Find a named entry point in a DLL
  2251.  
  2252. From assembler
  2253.  
  2254.     On entry    R0 = DLL handle
  2255.             R1 = pointer to entry point name
  2256.  
  2257.     On exit        R0 = pointer to entry point in DLL
  2258.  
  2259. From C
  2260.  
  2261.     Prototype    os_error *dll_findEntry(dll d,
  2262.                         const char *name,
  2263.                         void (**entry)())
  2264.  
  2265.     Arguments    d = the DLL in which to find an entry point
  2266.             name = pointer to the name of the entry point to find
  2267.             entry = *entry is set to point to the entry point
  2268.  
  2269.     If the entry point has a non-void return value, you will need to
  2270.     typecast  your entry argument.
  2271.  
  2272. Use
  2273.  
  2274.     Finds a named entry point in a specified DLL.  This is useful if your
  2275.     application uses DLLs to allow user extensions – you could require
  2276.     that  all DLLs used for this purpose export an entry point (say
  2277.     ‘app_main’) and  use this call to find and call it, possibly
  2278.     supplying your own set of entry  points.
  2279.  
  2280.     Entry point names are case-sensitive, in support of case-sensitive
  2281.     languages like C.
  2282.  
  2283. Example of use
  2284.  
  2285.     The example below locates a named entry point and calls it, passing a
  2286.     single integer argument.
  2287.  
  2288.         AREA    |Example$$Code|,CODE,READONLY
  2289.  
  2290.     ; callEntry
  2291.     ;
  2292.     ; On entry:    a1 == DLL handle containing entry point
  2293.     ;         a2 == name of entry point
  2294.     ;        a3 == parameter to pass to entry in a1
  2295.     ; On exit:    a1 == pointer to an error block if the entry
  2296.     ;              point could not be found, or value of a1
  2297.     ;              on return from entry point
  2298.  
  2299.             EXPORT    callEntry
  2300.     callEntry    ROUT
  2301.  
  2302.             ; --- Locate the entry point ---
  2303.  
  2304.             MOV    ip,lr            ;Look after the link register
  2305.             SWI    XDLL_FindEntry        ;Locate entry point address
  2306.             MOVVS    pc,ip            ;If it failed, return error
  2307.  
  2308.             ; --- Call the entry point ---
  2309.  
  2310.             MOV    lr,ip            ;Restore return address
  2311.             MOV    a2,a1            ;Keep entry point address
  2312.             MOV    a1,a3            ;Put argument in a1
  2313.             MOV    pc,a2            ;And exit via the entry point
  2314.  
  2315.             LTORG
  2316.  
  2317.             END
  2318.  
  2319.                           DLL_SaveHandle (SWI &4A310)
  2320.  
  2321.     Finds the current application’s handle so that it can be restored
  2322.     later
  2323.  
  2324. From assembler
  2325.  
  2326.     On entry    −
  2327.  
  2328.     On exit        R0 = the current application’s handle
  2329.  
  2330. From C
  2331.  
  2332.     Prototype    os_error *dll_saveHandle(int *handle)
  2333.  
  2334.     Arguments    handle = *handle is filled in with the application
  2335.                  handle
  2336.  
  2337. Use
  2338.  
  2339.     This SWI allows an application to make sure that its handle is
  2340.     preserved  over OS calls which might otherwise corrupt it.  The
  2341.     application handle  must be valid during any calls to DLLManager with
  2342.     the single exception  of DLL_RestoreHandle.
  2343.  
  2344.     The requirement to save the handle may be dropped if an alternative
  2345.     method of identifying applications is used instead.
  2346.  
  2347. Example of use
  2348.  
  2349.     The example below shows how to call an arbitrary *command while
  2350.     ensuring that the application handle is preserved.
  2351.  
  2352.             IMPORT    |x$stack_overflow|
  2353.             IMPORT    system
  2354.  
  2355.     ; safeCommand
  2356.     ;
  2357.     ; On entry:    a1 == pointer to command string to call safely
  2358.     ; On exit:    a1 == 0 if all went well, or a system-style
  2359.     ;              return code otherwise
  2360.  
  2361.             EXPORT    safeCommand
  2362.     safeCommand    ROUT
  2363.  
  2364.             ; --- Create a new stack frame ---
  2365.  
  2366.             MOV    ip,sp
  2367.             STMFD    sp!,{v1,fp,ip,lr,pc}
  2368.             SUB    fp,ip,#4
  2369.             CMP    sp,sl
  2370.             BLLT    |x$stack_overflow|
  2371.  
  2372.             ; --- Get my current handle ---
  2373.  
  2374.             MOV    a2,a1            ;Look after command string
  2375.             SWI    DLL_SaveHandle        ;Get my application handle
  2376.             MOV    v1,a1            ;Save that away for a bit
  2377.  
  2378.             ; --- Perform the command ---
  2379.  
  2380.             MOV    a1,a2            ;Restore the command pointer
  2381.             BL    system            ;Execute the command
  2382.             MOV    a2,a1            ;Save the return code away
  2383.  
  2384.             ; --- Restore my application handle ---
  2385.  
  2386.             MOV    a1,v1            ;Get the application handle
  2387.             SWI    DLL_RestoreHandle    ;Restore to previous value
  2388.  
  2389.             ; --- Return to caller ---
  2390.  
  2391.             MOV    a1,a2            ;Reinstate system return val
  2392.             LDMDB    fp,{v1,fp,sp,pc}^    ;Return to caller
  2393.  
  2394.             LTORG
  2395.  
  2396.             END
  2397.  
  2398.  
  2399.                            DLL_RestoreHandle (SWI &4A311)
  2400.  
  2401.     Sets the current application’s handle from an earlier saved copy
  2402.  
  2403. From assembler
  2404.  
  2405.     On entry    R0 = the application handle to set
  2406.  
  2407.     On exit        −
  2408.  
  2409. From C
  2410.  
  2411.     Prototype    os_error *dll_restoreHandle(int *handle)
  2412.  
  2413.     Arguments    handle = pointer to an integer set up by
  2414.                  dll_saveHandle
  2415.  
  2416. Use
  2417.  
  2418.     This SWI allows an application to restore its handle after OS calls
  2419.     which  might have corrupted it.  The application handle must be valid
  2420.     during  any calls to DLLManager with the single exception of
  2421.     DLL_RestoreHandle.
  2422.  
  2423.     The requirement to save the handle may be dropped if an alternative
  2424.     method of identifying applications is used instead.
  2425.  
  2426. Example of use
  2427.  
  2428.     See SWI DLL_SaveHandle for an example of using this SWI.
  2429.  
  2430.  
  2431.                         DLL_FindInstanceVars (SWI &4A312)
  2432.  
  2433. From assembler
  2434.  
  2435.     On entry    R0 = DLL handle
  2436.  
  2437.     On exit        R0 = pointer to the DLL’s instance variable area
  2438.  
  2439. From C
  2440.  
  2441.     Prototype    os_error *dll_findInstanceVars(dll d,int **addr)
  2442.  
  2443.     Arguments    d = a DLL handle
  2444.             size = address to store the instance variable area
  2445.                    pointer
  2446.  
  2447. Use
  2448.  
  2449.     Finds the address of an extension DLL’s instance variables.  This
  2450.     saves  you from having to store this address separately so you can
  2451.     free it again  later.
  2452.  
  2453.                        DLL_RegisterAppEntryTable (SWI &4A313)
  2454.  
  2455. From assembler
  2456.  
  2457.     On entry    R0 = pointer to an entry point address list
  2458.             R1 = pointer to the entry point name list
  2459.  
  2460.     On exit        −
  2461.  
  2462. From C
  2463.  
  2464.     Prototype    os_error *dll_registerAppEntryTable(void (**btable)(),
  2465.                                     char *names)
  2466.  
  2467.     Arguments    btable = pointer to address table
  2468.             names = pointer to entry point name list
  2469.  
  2470. Use
  2471.  
  2472.     Registers an application’s entry point table with the DLLManager, so
  2473.     that  DLLs can call entry points within the client.
  2474.  
  2475.     The name list contains the names of the entry points, in order,
  2476.     separated  by single null bytes.  Dummy entries, for unused entry
  2477.     points, may be  indiciated by a single byte containing the value ‘1’.
  2478.     The whole list is  terminated by a zero length entry.  The address
  2479.     table contains the  addresses of the entry points in order.
  2480.  
  2481.     The entry point table contains four byte addresses of the actual
  2482.     routines.   Ordinals are simply indices into this table.
  2483.  
  2484.  
  2485.                         DLL_FindAppEntry (SWI &4A314)
  2486.  
  2487. From assembler
  2488.  
  2489.     On entry    R0 = pointer to entry point name
  2490.  
  2491.     On exit        R0 = pointer to entry point address
  2492.  
  2493. From C
  2494.  
  2495.     Prototype    os_error *dll_findAppEntry(char *name,void (**func)())
  2496.  
  2497.     Arguments    name = pointer to entry point name
  2498.             func = address to store the entry point address
  2499.  
  2500. Use
  2501.  
  2502.     Looks up a named entry point within the currently executing client
  2503.     application.
  2504.  
  2505.  
  2506.                        DLL_SetExtensionTable (SWI &4A315)
  2507.  
  2508. From assembler
  2509.  
  2510.     On entry    R0 = pointer to branch table to fill in
  2511.             R1 = pointer to name list
  2512.  
  2513.     On exit        −
  2514.  
  2515. From C
  2516.  
  2517.     Prototype    os_error *dll_setExtensionTable(void (**btable)(),
  2518.                                 char *names)
  2519.  
  2520.     Arguments    btable = pointer to branch table to fill in
  2521.             names = pointer to name list
  2522.  
  2523. Use
  2524.  
  2525.     Fills in an area of memory with branch instructions to specified
  2526.     entry  points within the currently executing client application.
  2527.  
  2528.     Each entry in the branch table initially lower than &1000 is
  2529.     considered to  be the ordinal of the entry point to find, thus
  2530.     bypassing the normal name  lookup.  Entries greater than &1000 are
  2531.     filled in by finding the entry point  whose name matches the next
  2532.     entry in the name table.
  2533.  
  2534.     The name list contains entry point names each separated by a single
  2535.     zero  byte, one for each entry in the branch table not interpreted as
  2536.     an ordinal.   The whole list is terminated by a zero-length entry.
  2537.     If the branch table  initially only contains ordinals, it must be
  2538.     terminated by a value greater  than &1000 and the name list contains
  2539.     only a zero byte.
  2540.  
  2541.  
  2542. *Commands
  2543.  
  2544.                                     *DLLs
  2545.  
  2546.     Lists the shared DLLs currently in memory
  2547.  
  2548. Syntax
  2549.  
  2550.     *DLLs [<application name>]
  2551.  
  2552. Parameters
  2553.  
  2554.     application name = the name of an application (as shown by *DLLApps)
  2555.  
  2556. Use
  2557.  
  2558.     Shows a list of either all shared DLLs currently loaded if no
  2559.     application name is specified or just those associated with the named
  2560.     application, together with a small quantity of information about
  2561.     each.
  2562.  
  2563.     Application names are not case-sensitive.
  2564.  
  2565. Examples
  2566.  
  2567.     *DLLs        (shows all shared DLLs loaded)
  2568.  
  2569.     *DLLs Glass    (shows the shared DLLs used by the application
  2570.             ‘Glass’)
  2571.  
  2572.  
  2573.                                      *DLLApps
  2574.  
  2575.     Shows the current DLL client applications.
  2576.  
  2577. Syntax
  2578.  
  2579.     *DLLApps [<DLL name>]
  2580.  
  2581. Parameters
  2582.  
  2583.     DLL name = the name of a DLL (as shown by *DLLs)
  2584.  
  2585. Use
  2586.  
  2587.     Lists either the names of all DLL client applications (if no DLL name
  2588.     is specified) or the applications using the named DLL. If you specify
  2589.     a DLL name, the version of the DLL used by each client is also
  2590.     displayed (since multiple versions of a DLL may in memory
  2591.     simultaneously).
  2592.  
  2593.     If a client application has not registered a name with the
  2594.     DLLManager, its name is shown as ‘<Untitled>’.
  2595.  
  2596.     DLL names are not case-sensitive.
  2597.  
  2598. Examples
  2599.  
  2600.     *DLLApps    (shows names of all DLL client apps currently
  2601.             running)
  2602.  
  2603.     *DLLApps Steel    (shows the names of the current clients of the DLL
  2604.             called ‘Steel’, together with the versions of Steel
  2605.             which they are using)
  2606.  
  2607.  
  2608.                                      *DLLInfo
  2609.  
  2610.     Shows information about a named DLL
  2611.  
  2612. Syntax
  2613.  
  2614.     *DLLInfo <DLL name>
  2615.  
  2616. Parameters
  2617.  
  2618.     DLL name = the name of a shared DLL (as shown by *DLLs)
  2619.  
  2620. Use
  2621.  
  2622.     Shows a large quantity of information about the latest version of a
  2623.     DLL currently loaded:
  2624.  
  2625.     •  Its name
  2626.  
  2627.     •  Its author/copyright string
  2628.  
  2629.     •  Its version number
  2630.  
  2631.     •  The number of clients it has
  2632.  
  2633.     •  The names of all its entry points (this can be quite a long list)
  2634.  
  2635.     DLL names are not case-sensitive.
  2636.  
  2637. Example
  2638.  
  2639.     *DLLInfo Steel    (shows vast quantities of information about Steel)
  2640.  
  2641.  
  2642.                                   *DLLKillApp
  2643.  
  2644.     Informs the DLLManager that an application has quit
  2645.  
  2646. Syntax
  2647.  
  2648.     *DLLKillApp <Application name>
  2649.  
  2650. Parameters
  2651.  
  2652.     Application name = the name of an application (as shown by *DLLApps).
  2653.  
  2654. Use
  2655.  
  2656.     Terminates the named application’s use of the DLLManager.  It
  2657.     performs the same actions as SWI DLL_AppDying, and is mainly useful
  2658.     if an application ended abnormally (so that it failed to call
  2659.     DLL_AppDying properly).
  2660.  
  2661.     You should ensure that the application named is not running − if it
  2662.     is, it will probably crash the machine badly once it regains control.
  2663.  
  2664.     Application names are not case-sensitive.
  2665.  
  2666. Example
  2667.  
  2668.     *DLLKillApp VeryBuggy
  2669.             (kills ‘VeryBuggy’, because it wasn’t able to close
  2670.             itself down)
  2671.  
  2672.  
  2673.                                      *DLLReset
  2674.  
  2675.     Resets the DLLManager
  2676.  
  2677. Syntax
  2678.  
  2679.     *DLLReset
  2680.  
  2681. Parameters
  2682.  
  2683.     −
  2684.  
  2685. Use
  2686.  
  2687.     Resets the DLLManager module, removing all shared DLLs from memory,
  2688.     and freeing up lots of memory.
  2689.  
  2690.     This is useful in the unlikely event that the DLLManager goes out of
  2691.     control, or if you have lots of applications which haven’t closed
  2692.     them selves down properly.  Note that you can’t just RMReinit the
  2693.     DLLManager because it checks to find out if it it still in use.
  2694.  
  2695.     If there are any applications using shared DLLs, using this command
  2696.     will make them all crash very badly when they regain control.  You
  2697.     have been warned.
  2698.  
  2699. Example
  2700.  
  2701.     *DLLReset    (resets the DLLManager)
  2702.  
  2703.  
  2704.                                    *DLLEnsure
  2705.  
  2706.     Finds out if a DLL is available for use
  2707.  
  2708. Syntax
  2709.  
  2710.     *DLLEnsure <DLL name> <version>
  2711.  
  2712. Parameters
  2713.  
  2714.     DLL name = either a normal DLL name (as shown by *DLLs) or a fully
  2715.            qualified pathname version = a decimal version number
  2716.  
  2717. Use
  2718.  
  2719.     Finds out whether a DLL with the name and version specified is
  2720.     available.  The searching is the same as for the SWI DLL_Find.  In
  2721.     summary:
  2722.  
  2723.     •  If DLL name is a full pathname, a normal DLL name is set as the
  2724.        leafname
  2725.  
  2726.     •  If DLL name is a normal DLL name, a pathname is set up by
  2727.        prefixing DLL name with ‘DLL:’.
  2728.  
  2729.     •  The shared DLLs in memory are searched for the normal DLL name and
  2730.        version specified
  2731.  
  2732.     •  If it wasn’t found there, the file specified by the pathname is
  2733.        opened, and examined to see if it is of a high enough version.
  2734.  
  2735.     If the search was successful, the command stops and control returns.
  2736.     If it failed, and error is returned.
  2737.  
  2738.     This is useful for inserting in !Run files for applications.
  2739.  
  2740. Example
  2741.  
  2742.     *DLLEnsure Steel 0.02
  2743.             (make sure version 0.02 or higher of DLL Steel is
  2744.             available)
  2745.  
  2746. _____________________________________________________________________________
  2747.  
  2748.  
  2749.                               The DLLLib library
  2750.  
  2751.  
  2752. Overview
  2753.  
  2754.     The library is split internally into three sections:
  2755.  
  2756.     •  An APCS interface to the DLLManager SWIs
  2757.  
  2758.     •  Support functions provided for DLL clients
  2759.  
  2760.     •  ‘Behind the scenes’ support functions for the use of the DLL stubs
  2761.  
  2762.     All the DLLLib functions and macros are defined in the dll.h header
  2763.     file  (file DLL.h.dll in the distribution archive), which should be
  2764.     made  available to C programs via the C$Path mechanism.   The actual
  2765.     code for DLLLib is held within the file DLLLib.o.DLLLib in the
  2766.     Dynamic Linking System distribution archive.  To link the library in,
  2767.     just  add the filename of the library to the linker or compiler
  2768.     command line.  If  you use Acorn’s Make application, you simply drag
  2769.     the DLLLib file to the  Add icon in the Project dialogue box.
  2770.  
  2771. Important note
  2772.  
  2773.     In order to perform its work, the DLLLib library must export private
  2774.     support functions for the use of the replacement Shared C Library
  2775.     stubs.
  2776.  
  2777.     All DLLLib functions and macros have names beginning with the
  2778.     characters ‘_dll’, ‘_ext’ or ‘dll_’.  In order to allow for new
  2779.     features to be  added to the the library, you should consider all
  2780.     identifiers beginning  with these characters to be reserved, and not
  2781.     try to define them in your  own code.
  2782.  
  2783. Support macros
  2784.  
  2785.     So that an application can easily be written to use either dynamic
  2786.     linking  or static (standard) linking, many of the support function
  2787.     definitions are  only enabled if the macro _DLL is defined before
  2788.     including dll.h. To allow for creating libraries which may be
  2789.     compiled to be either  dynamically or statically linked, the macros
  2790.     _dllEntry and _dll_static  are provided.  _dllEntry(name) will return
  2791.     either the name of entry veneer  corresponding to entry point name or
  2792.     name itself, depending on whether  _DLL is defined.  This can be
  2793.     useful for passing addresses of functions.   e.g.
  2794.  
  2795.     void mylib_init(void)
  2796.     {
  2797.       /*
  2798.        * Some code...
  2799.        */
  2800.       atexit(_dllEntry(mylib__exit));
  2801.     }
  2802.  
  2803.     _dll_static is empty if _DLL is defined, and returns static if it
  2804.     isn’t.  It is  useful for declaring internal functions, to which you
  2805.     pass function  pointers to other functions (e.g. mylib__exit in the
  2806.     example given above).
  2807.  
  2808.     The entry veneers created for these functions need to be able to have
  2809.     the  function’s name exported, so when you are creating a DLL, they
  2810.     must be  externally visible.
  2811.  
  2812.     The macro _extEntry() performs a similar job to _dllEntry() −
  2813.     _extEntry(name) becomes _extEntry_name if _DLL is defined, and name
  2814.     if it  isn’t.
  2815.  
  2816. DLLManager SWI interface
  2817.  
  2818.     All of the interface functions return a pointer to an os_error
  2819.     structure,  which is NULL if the call was successful.  Each call
  2820.     corresponds to a  DLLManager SWI, and is documented with it above.
  2821.  
  2822. Other support functions
  2823.  
  2824.     The call interface to these functions is defined in terms of C, since
  2825.     they all  conform to APCS-R.
  2826.  
  2827.     If calling from assembler, load the arguments into registers R0
  2828.     onwards in  the same order as they are defined in the C prototype.
  2829.     On exit, R0  contains the return value or is corrupted and R1-R3 and
  2830.     R12 are cor rupted also.
  2831.  
  2832.     The following functions may be replaced by macros, although they are
  2833.     guaranteed not to multiply re-evaluate their arguments.
  2834.  
  2835.                                   _dll_setjmp
  2836.  
  2837. Prototype
  2838.  
  2839.     int _dll_setjmp(void)
  2840.  
  2841. Arguments
  2842.  
  2843.     −
  2844.  
  2845. Return value
  2846.  
  2847.     An integer value representing the current DLL stack pointer in an
  2848.     undefined manner.  This value is suitable for passing to
  2849.     _dll_longjmped.
  2850.  
  2851. Use
  2852.  
  2853.     Returns the current state of the DLL stack, so that it may be
  2854.     restored later  via _dll_longjmped.  The format of the return value
  2855.     is unspecified, and  should not be relied upon.
  2856.  
  2857. Example of use
  2858.  
  2859.     See _dll_longjmped below for an example of use.
  2860.  
  2861.  
  2862.                                    _dll_longjmped
  2863.  
  2864. Prototype
  2865.  
  2866.     void _dll_longjmped(int ptr)
  2867.  
  2868. Arguments
  2869.  
  2870.     ptr = a stack pointer returned by _dll_setjmp.
  2871.  
  2872. Return value
  2873.  
  2874.     −
  2875.  
  2876. Use
  2877.  
  2878.     Restores the DLL stack after an exceptional procedure return (e.g.
  2879.     through longjmp).
  2880.  
  2881. Example
  2882.  
  2883.     int stackptr=_dll_setjmp();    /* Read DLL stack pointer          */
  2884.     jmp_buf j;            /* Record stack frame info         */
  2885.  
  2886.     /*
  2887.      * Some setting up...
  2888.      */
  2889.  
  2890.     if (!setjmp(j))
  2891.     {
  2892.       /*
  2893.        * Some stuff involving longjmp...
  2894.        */
  2895.     }
  2896.     else
  2897.     {
  2898.       /* --- Someone longjmped here --- */
  2899.  
  2900.       _dll_longjmped(stackptr);    /* Reset DLL stack nicely          */
  2901.  
  2902.       /*
  2903.        * Do anything else to restore the state
  2904.        */
  2905.     }
  2906.  
  2907.  
  2908.                                 _dll_appspace
  2909.  
  2910. Prototype
  2911.  
  2912.     void _dll_appspace(void)
  2913.  
  2914. Arguments
  2915.  
  2916.     −
  2917.  
  2918. Return value
  2919.  
  2920.     −
  2921.  
  2922. Use
  2923.  
  2924.     Registers the location of the caller’s static variables with the
  2925.     DLLManager  so that the relocation is set up properly if the client
  2926.     is entered through an  _extEntry-type veneer.
  2927.  
  2928.     This is only of use to applications which are compiled with the -zM
  2929.     compiler option (i.e. module applications), and even then, the DLL
  2930.     stubs  perform this task on initialisation, unless the client’s DLL
  2931.     table is empty.
  2932.  
  2933.     Therefore, you will only need to make this call if:
  2934.  
  2935.     •  You are writing a module application, and
  2936.  
  2937.     •  You are not using any shared DLLs through the normal stub
  2938.        mechanism, and
  2939.  
  2940.     •  You are using DLLs (either shared or nonshared).
  2941.  
  2942.  
  2943.                                 _dll_clibdata
  2944.  
  2945. Prototype
  2946.  
  2947.     void  _dll_clibdata(void)
  2948.  
  2949. Arguments
  2950.  
  2951.     −
  2952.  
  2953. Return value
  2954.  
  2955.     −
  2956.  
  2957. Use
  2958.  
  2959.     Registers the location of the client’s copy of the Shared C Library’s
  2960.     instance data with the DLLManager so that any DLLs which require access
  2961.     to this data (e.g. if they output to stderr) can find it.
  2962.     This is normally performed automatically by the DLL stubs, unless the
  2963.     client’s DLL table is empty.  You will therefore only need to use this call if
  2964.     you are using DLLs without the standard DLL stub mechanism.
  2965.  
  2966.  
  2967.                                  _dll_setname
  2968.  
  2969. Prototype
  2970.  
  2971.     void _dll_setname(const char *name)
  2972.  
  2973. Arguments
  2974.  
  2975.     name = pointer to the application’s name (null-terminated)
  2976.  
  2977. Return value
  2978.  
  2979.     −
  2980.  
  2981. Use
  2982.  
  2983.     Registers the client’s name with the DLLManager.  This is not essential,
  2984.     although it is considered to be ‘polite’.
  2985.  
  2986.     For the rules about client application names, see the chapter Registering
  2987.     names.
  2988.  
  2989. Example of use
  2990.  
  2991.     _dll_setname("Glass");
  2992.  
  2993.  
  2994.                                   _dll_system
  2995.                                  _dll_ksystem
  2996.                                           _dll_oscli
  2997.                                    _dll_starttask
  2998.  
  2999. Prototypes
  3000.  
  3001.     int _dll_system(const char *command)
  3002.     int _dll_ksystem(const char *command,int chain)
  3003.     os_error *_dll_oscli(const char *command)
  3004.     os_error *_dll_starttask(const char *command)
  3005.  
  3006. Arguments
  3007.  
  3008.     command = pointer to a null-terminated *command.  For _dll_system,
  3009.           this  may be prefixed with the characters ‘CHAIN:’ or
  3010.           ‘CALL:’.
  3011.     chain = 0 to keep the application in memory while the command
  3012.         executes, nonzero to remove the application.
  3013.  
  3014. Return value
  3015.  
  3016.     _dll_system returns the same values as the standard C function
  3017.     system.   _dll_ksystem returns the same values as _kernel_system.
  3018.     _dll_oscli and  _dll_starttask return 0 for success, or a pointer to
  3019.     a RISC OS-style error  structure for failure.
  3020.  
  3021. Use
  3022.  
  3023.     These are all safe ways of calling *commands.  Each one is an
  3024.     interface to  a standard function which calls a *command, but they
  3025.     save the application handle around the call, so they are safe to use
  3026.     from DLL clients.   The relationship is:
  3027.  
  3028.         Table 11.1
  3029.  
  3030.     Actually, _dll_oscli and _dll_starttask call the SWIs OS_CLI and
  3031.     Wimp_StartTask directly, rather than going through the veneer
  3032.     functions.
  3033.  
  3034.     This is unlikely to make much difference in practice.
  3035.     _dll_loadExtension
  3036.  
  3037. Prototype
  3038.  
  3039.     dll _dll_loadExtension(const char *name)
  3040.  
  3041. Arguments
  3042.  
  3043.     name = pointer to the filename of a DLL file
  3044.  
  3045. Return value
  3046.  
  3047.     A DLL handle for the newly loaded DLL, or a NULL pointer if the load
  3048.     failed for any reason (e.g. ran out of memory).
  3049.  
  3050. Use
  3051.  
  3052.     This call loads and initialises a local (extension) DLL, and returns
  3053.     a  handle to it.  Space for the DLL is allocated using malloc.  The
  3054.     DLL  handle returned may be used just like any other DLL handle. When
  3055.     you are finished with an extension DLL, you can destroy it simply  by
  3056.     freeing the DLL handle.
  3057.  
  3058. Example of use
  3059.  
  3060.     The example function loads a named extension DLL and initialises it
  3061.     by  calling a named function (in this case myext_init − this would be
  3062.     standard for all the DLLs used by an application), passing it the
  3063.     address  of a table of function pointers within the main application.
  3064.  
  3065.     BOOL myapp_loadExtension(char *name,dll *d,widget *w)
  3066.     {
  3067.       widget (*p)(myapp_entryTable *tbl);
  3068.  
  3069.       *d=_dll_loadExtension(name);
  3070.       if (*d)
  3071.       {
  3072.         wimpt_noerr(dll_findEntry(d,"myext_init",(void (**)())&p));
  3073.         *w=p(&myapp__entryTable);
  3074.       }
  3075.       return (d ? TRUE : FALSE);
  3076.     }
  3077.  
  3078.  
  3079.                                   _dll_giveMemory
  3080.  
  3081. Prototype
  3082.  
  3083.     void _dll_giveMemory(void)
  3084.  
  3085. Arguments
  3086.  
  3087.     −
  3088.  
  3089. Return value
  3090.  
  3091.     −
  3092.  
  3093. Use
  3094.  
  3095.     Allocates workspace for all the shared DLLs being used by the client
  3096.     which have not yet been allocated any.  Workspace is allocated using
  3097.     malloc.  If there is not enough memory, an error is generated, and
  3098.     (in C) a  SIGOSERROR is raised.
  3099.  
  3100.  
  3101.                                 _dll_wimpPoll
  3102.                                 _dll_wimpPollIdle
  3103.  
  3104. On entry
  3105.  
  3106.     R0 = Wimp_Poll event mask and flags
  3107.     R1 = pointer to block to fill with event data
  3108.     R2 = time to return with an idle event (_dll_wimpPollIdle only)
  3109.     R3 = pointer to poll word in the RMA, if bit 22 of R0 is set
  3110.  
  3111. On exit
  3112.  
  3113.     R0 = Wimp_Poll event code, or pointer to error block
  3114.     V set if an error occurred, or clear otherwise
  3115.     Other registers preserved
  3116.  
  3117. Use
  3118.  
  3119.     Provides a ‘safe’ way to call Wimp_Poll and Wimp_PollIdle.  The entry
  3120.     and exit conditions are the same as those for Wimp_Poll and
  3121.     Wimp_PollIdle.  In particular, if bit 24 is set in R0 on entry, the
  3122.     floating  point status and registers F4-F7 are saved (even under
  3123.     RISC OS 2).  This is  of course only performed if the floating point
  3124.     emulator is loaded. These functions are not intended to be used
  3125.     directly from C, but rather  through an OS library’s Wimp interface
  3126.     (where they can be used as a  drop-in replacement for the actual SWIs
  3127.     Wimp_Poll and Wimp_PollIdle).   Indeed, they cannot be used from C,
  3128.     since the V flag requires checking.   Hence it is not declared in the
  3129.     header file.
  3130.  
  3131.  
  3132.                                      _dll_iob
  3133.                                    _dll_errno
  3134.                                    _dll_ctype
  3135.                                  _dll_hugeval
  3136.  
  3137.     These functions are for internal use only.  They locate items of data
  3138.     within  the client application’s Shared C Library data area.  Do not
  3139.     use them in  your own code, except through the macros defined in the
  3140.     replacement C  Library headers.
  3141.  
  3142.