Runtime Link Library System

RLM PROGRAMMERS GUIDE

Contents


Overview

It is not envisaged that the average C programmer will ever need to be directly concerned with the details of how a system interfaces to the Runtime Link Manager. This capability is intended primarily for use by a systems level programmer who is trying to interface a new programming language to the RLM.

The calls that the RLM supports allow all phases of its operation to be directly controlled. This should make it easy to interface a new system to the RLM.

If you are a C programmer using the C68 system, then you do not have to worry about this aspect of the RLM at all. The necessary calls to link C68 programs to the RLM are issued automatically from the C startup module if you specified that you wanted to use RLL libraries when you built your program.

The RLM is implemented using the THING system. The calls to the RLM therefore use the standard mechanisms for interfacing to the THING system. Some systems such as SMSQ, SMSQ/E, SMS2 or Atari QL Emulators with Level E drivers have built in support for the THING system. On other systems it needs to be loaded explicitly. It is worth noting that if your system has support for the Hotkey system, then you do already have THING support loaded (this means that users of QPAC2 will always have such support loaded). If the system does not satisfy any of the above criteria then the THING support code needs to be loaded explicitly. C68 users will have the THING_REXT file on the RUNTIME 2 disk to provide such support.


Standard Definitions

If you are going to write code that interfaces to the RLL or RLM at this level, then you should use the standard include files provided.

For C programmers, this is done using a statement of the form:

#include <rll.h>

while for assembler programmers the equivalent is

include rll_in

These include files are themselves used internally within th e components used to implement the RLL system, so using them in your own code will ensure consistency.


Finding the RLM

The first thing that one has to do is to check that the RLM is actually loaded into memory, and if so at what address. This is done by using assembler of the form:

rlmname dc.b 0,3,"RLM",0 
rlmaddr dc.l 0 
rlmver  dc.l 0
 
moveq  #sms.uthg,d0    ; Use THING call 
moveq  #-1,d1          ; this job 
moveq  #-1,d3          ; infinite timeout 
lea    rlmname$pc),a0  ; name of THING 
bsr    _ThingTrap      ; ... do it 
tst.l  d0              ; did it work? 
bne    suicide         ; ... NO, abandon 
move.l a0,rlmaddr      ; save address 
move.l d3,rlmver       ; save version 

In the above example, the _ThingTrap routine is used to invoke the sms.uthg system call. This is because on systems that have direct operating support for THINGS, the relevant operating system calls are available as TRAP #1 calls, while on other systems these calls have to be performed via a vector. The routine _ThingTrap is a way of automatically using the TRAP #1 call if it is available, or using the vector method otherwise - but in both cases passing exactly the same parameters. The source of the _ThingTrap routine is provided as part of the source of the C68 LIBC_A libraries.


Calling the RLM

The calls to the RLM are made with a value in d0 indicating the operation required, with any additional parameters passed on the stack in C style. The parameters passed for each operation type will be as defined for that particular operation.

In assembler, a typical call sequence will be something of the form:

.... set up any parameters required 
moveq   #OperationCode,d0 
move.l  rlmaddr$pc),a0 
jsr 12  $a0) 
lea     ??$sp),sp   ; remove stack parameters 
tst.l   d0          ; did it work? 
bne     ???         ; ... NO, do something 

Note that it is the responsibility of the calling code to tidy the stack and remove the parameters that were passed on the stack when the call has completed.


Freeing the RLM

When you have finished using the RLM, then you should immediately free it.

In Assembler this would look like:

moveq #sms.fthg,d0 
moveq #-1,d1 
lea   rlmname,a1 
jsr   _ThingTrap 


Simplified Interface to the RLM

The C68 standard C library contains routines which simplifies the handling of the RLM. The above complexities of finding, calling and releasing the RLM are hidden behind a single function call. This simplified interface does the following every time:

The simplified assembler interface is provided by the CallRLM() function. This used by as follows:

.... set up parameters for the RLM call 
moveq #OperationCode,d0 ; Set the operation type 
jsr   CallRLM           ; go and do it 
lea   ??$sp),sp         ; remove stack params  
tst.l d0                ; did call work? 
bne   ???               ; ... NO, do something 

The interface for the C programmer consists of a named call corresponding to each of the possible RLM functions (which are then mapped internally in the library onto the CallRLM() function mentioned above). If you are going to use these versions of the calls, then the C program should include a statement of the form:

#include <rll.h>

to get the appropriate prototype definitions included. You can then simply use statements such as:

RLM_SetDebugDir("ram1_");

from within the C program. This C interface is also, of course, available to the assembler programmer. The full definition of all these calls in C terms follows later in this document.

Note, however, that a program cannot issue a call to the RLM to do relocation on itself using this simplified interface. This is because the C compiler does not produce position independent code, so until the relocation has happened no C library routines can be called.


RLM Operation

In operation the Runtime Library Manager will be installed as a shareable utility thing with a single entry point at offset %10 relative to its Thing Header. The first parameter must always be a word containing an operation code to indicate the call function required. A QDOS/SMS error code is returned in d0.l. Parameters are passed on the calling jobs stack. Calling jobs should have at least 1000 bytes of stack space available + any stack space used by RLL init routines $thus maximum total usage 2000 bytes).

The RLM is initialised by the conventional LRESPR call. The SuperBasic command INIT_RLM is also linked in to permit the user to re-link the RLM in the event of accidental Thing removal. The RLM is not currently ROMable as it includes C code that needs runtime relocation. It could be rewritten in assembler to remove this restriction.

SuperBasic extensions are provided to permit the user to change defaults etc. This interface was described in Section 2 of this document. The low-level assembler calls to change the global environment of the RLM are intended for front-end programs and not client jobs requiring linking.

Libraries can be loaded explicitly by the user or as required by the RLM $and automatically removed when not in use). A default library directory is defined internally to the RLM as the primary search path for RLLs. In addition the LIB_ subdirectory of the PROG_USE directory, and the DATA_USE directories would also be searched.


Supported RLM Calls

The following gives the details of the calls that are supported by the RLM.

The operation codes available are:

Operation Code C function name Description
0 RLM_LinkCode Link Code to RLL system
1 RLM_CheckRLL Check if a RLL is loaded
2 RLM_LinkRLL Link code to a single RLL
3 RLM_UnlinkRLL Unlink code from a single RLL
4 RLM_LoadLib Load a RLL
5 RLM_SetTimeout Set Default timeout delay
6 RLM_SetLoadMode Set Interactive Reporting mode
7 RLM_SetLoadDir Set Default Library Directory
8 RLM_SetDebugDir Set Debug Directory
9 RLM_SetDebugMode Set Debug Mode
10 RLM_ReadSettings Read RLM global settings
11 RLM_RelocLD Relocate code using C68 compatible relocation
12 RLM_RelocGST Relocate code using GST compatible relocation
13 RLM_LibrarySymbol Get the address of a symbol within the given RLL
14 RLM_ProgramSymbol Get the address of a symbol used by the current program
Note that it is possible to pass a console channel on some calls. This feature is primarily intended for the internal use by the RLM. It is not expected (but not forbidden) that client jobs will pass a channel.

The above calls are each described in detail in the remainder of this section.


RLM_LinkCode

Link Code to RLL

(d0 = 0)

Carry out the actual process of linking a program (or a RLL) to all the RLLs that it needs.

C prototype

int RLM_LinkCode(char *, BSS_HEADER *, jobid_t, chanid_t);

Parameters

long Address of start of code to be linked in
long Address of RLL BSS area. In practise only the BSS_HEADER, RLIB and XREF areas need to be present at this stage
long Job Id of the owner
long Channel ID for debug reports. A value of -1 causes a new console channel ID to be opened

Return Values

0 Success
Other QDOS/SMS error code.

Description

This expected to be the interface to the RLM used by most programs. It carries out the whole process of identifying what RLLs are needed by the caller, loading them if they are not already loaded, and then linking the calling code to the RLLs that it is going to use.

The list of RLLs required is taken from the RLIB section of RLL BSS area of the calling code. If any RLLs are specified by the calling program that have not already been loaded, then an attempt will be made to load them.

The list of addresses in the calling program that need linking are taken from the XREF part of the BSS area.

It is possible for one job to link the code of another by passing the job ID of the code owner. If this is done steps must be taken to guard against the unexpected removal of the code owner, for example the calling job being owned by the code owner.

Note that this call does not do program relocation of the calling program. The RLM can, however, be called to do this if needed.


RLM_CheckRLL

Check if a RLL is loaded

(d0 = 1)

Check if a specified RLL is already loaded into memory.

C prototype

RLL_HEADER * RLM_CheckRLL (char *);

Parameters

long Address of the name of the RLL that we want to check to see if it is already loaded into memory. This is passed as a C style string.

Return Values

+ve Success. The value returned is a pointer to the RLL Header.
0 RLL is not loaded.
-ve QDOS/SMS error code.

Description

The list of RLLs that are loaded into memory will be searched. If the RLL is found then a pointer to the RLL header will be passed back, and 0 (NULL) if it cannot. If any other error occurs it will be passed back as a negative error code.

The RLL Header can be used to check things such as the version number, or locate any of the other control areas.


RLM_LinkRLL

Link to a specified RLL

(d0 = 2)

Carry out the process of linking a program (or a RLL) to a specified RLL.

C prototype

int RLM_LinkRLL (char *, char *, BSS_XREF *, chanid_t);

Parameters

long Address of the name of the RLL to be linked in.
long Address of start of code to be unlinked in.
long Address of BSS_XREF area.
long Channel ID for debug reports. A value of -1 causes a new console channel ID to be opened.

Return Values

0 Success
Other QDOS/SMS error code.

Description

This call is not expected to be used very often as in most cases the RLM_LinkCode() call would be used instead to link all RLL(s associated with a particular program. It is intended for use by programs that want to be able to dynamically load and unload RLL(s at runtime. It carries out the actual process of linking external references that are in the caller with the relevant locations in the RLL.

If the RLL to be used has any dependencies on other RLLs, then these will also be automatically loaded. However no references from these extra RLLs will be used to satisfy the ones listed in the BSS_XREF area passed to this call.

It is possible for one job to link the code of another by passing the job ID of the code owner. If this is done steps must be taken to guard against the unexpected removal of the code owner, for example the calling job being owned by the code owner.

Note that this call does not do program relocation of the calling program.


RLM_UnlinkRLL

UnLink Code from a specified RLL

(d0 = 3)

Carry out the process of unlinking a program $or a RLL) from a specified RLL.

C prototype

int RLM_UnlinkRLL (char *, char *, BSS_XREF *, chanid_t);

Parameters

long Address of the name of the RLL to be unlinked from
long Address of start of code to be unlinked from the RLL
long Address of BSS_XREF area
long Channel ID for debug reports. A value of -1 causes a new console channel ID to be opened.

Return Values

0 Success
Other QDOS/SMS error code

Description

This call is a companion to the RLM_LinkRLL() call. It will unlink a specified program from the given RLL. If the unload timeout for this RLL is reached, then it will be automatically unloaded. Similarly if there are any dependent RLLs that reach their unload timeout, then they would also be unloaded.

This call is not expected to be used very often as in most cases the RLM_LinkCode() call would be used instead to link all RLL(s) associated with a particular program, and they would never be explicitly unlinked. Instead the program would terminate itself, and the RLM would automatically tidy up the state of the loaded RLLs as a result.

The main purpose of this call is to provide a method of dynamically linking in different RLLs at runtime according to some external criteria. This system needs to be used with great care as any attempt to execute code that has not yet been linked to its target RLL is certain to cause a program to crash, and is quite likely to crash the whole system.

It is possible for one job to unlink the code of another by passing the job ID of the code owner. If this is done steps must be taken to guard against the unexpected removal of the code owner, for example the calling job being owned by the code owner.

Note that the default action of the LD linker is to set up the program so that the BSS_XREF area is to be re-used as UDATA (Unitialised Data) purposes once a program has finished its initialisation phase. If you want to make the UDATA area start after the XDEF area then you need to make sure you use the -keepxref parameter to LD.


RLM_LoadLib

Load a RLL

(d0 = 4)

Load a specified RLL into memory.

C prototype

int RLM_LoadLib (char *, timeout_t, chanid_t);

Parameters

long Address of a zero terminated string that is the name of the RLL to be loaded
word The timeout value to be used. A negative value means make permanently resident and only removable by manual action
long The channel ID to be used for reporting status

Return Values

0 Success
Other QDOS/SMS error code

Description

The system first attempts to load a RLL with the same name as that specified in the parameters. If this is not found (or if it is found, but the major version numbers do not match) then the major version number is added to the name and further attempts are made to load the RLL using this revised name.

Notes

  1. If any of the RLLs loaded have a dependency on other RLLs, then these will also be loaded. It is good practise (although not essential) to load RLLs in "reverse" order so that at any point in time any dependency on other RLLs are already satisfied.
  2. RLLs with a finite timeout or a dependency on another RLL are loaded into transient program space. Is is so that they can be allocated a job ID to permit the THING system to mark them as users of other THINGs. The job names given to RLLs loaded into transient program space will always be "RLL " followed by the RLL name. RLLs that have no dependencies and infinite timeout are loaded into the Common Heap.
  3. RLLs that are cascade loaded will be given the same timeout value as applied to the orginally loaded RLL.


RLM_SetTimeout

Set Default Timeout Value

(d0 = 5)

Set the default value of the timeout delay

C prototype

int RLM_SetTimeout (timeout_t);

Parameters

word New timeout value

Return Values

0 Success
Other QDOS/SMS error code

Description

The timeout delay is used for deciding when to unload libraries that are loaded dynamically. A negative value is treated as infinite delay. This timeout delay does not apply to libraries that are loaded statically as in this case the delay is explicitly stated in the load call.

It is also normally inadvisable to specify too small a value for this timeout. If you do, you may find that the library is continually being unloaded just before you are about to use it again.


RLM_SetLoadMode

Set Interactive Reporting status

(d0 = 6)

Specify whether interactive reporting is to used when loading RLLs.

C prototype:

int RLM_SetLoadMode (short);

Parameters

word Set Reporting status. 0 = off, 1 = on

Return Values

0 Success
Other QDOS/SMS error code

Description

Normally one would expect the RLL system to be run with the Interactive Reporting status set to off. However, if a particular program is refusing to load because it cannot find all the RLLs that it requires, then the interactive mode can be useful in determining which RLL is missing.


RLM_SetLoadDir

Set Default Library Load Directory

(d0 = 7)

Set the default directory that is to be used for loading RLLs.

C prototype:

int RLM_SetLoadDir (char *);

Parameters

long Address of a zero terminated string (C style) that is the new name to be used

Return Values

0 Success
Other QDOS/SMS error code

Description

The default directory is always searched first when trying to find a RLL. If it is not found there, then the PROG_USE and DATA_USE directories are searched.

Notes.

  1. The default directory can also be set using the QJUMP CONFIG program. This is the value that is then used unless superseded by a call to the RLM_SetLoadDir() function.


RLM_SetDebugDir

Set Debug Directory

(d0 = 8)

Set the directory that is to be used for writing debug information files.

C prototype:

int RLM_SetDebugDir (char *);

Parameters

long Address of a zero terminated string that is the new name to be used.

Return Values

0 Success
Other QDOS/SMS error code

Description

If debug mode is active, then any debug files are put into this directory. The debug filename is made up of the job name with _DBG appended at the end.


RLM_ SetDebugMode

Set Debug Mode

(d0 = 9)

Switch debug mode on or off.

C prototype:

int RLM_SetDebugMode (short);

Parameters

word Debug mode. 0 = off, 1 = on

Return Values

0 Success
Other QDOS/SMS error code

Description

The debug mode is intended primarily for use in debugging RLL libraries. It give copious information about exactly what libraries are used, and what symbols are linked in from each RLL.


RLM_ReadSettings

Read RLM Settings

(d0 = 10)

Read all the RLM internal settings and pass the results back to the calling code.

C prototype:

void RLM_ReadSettings (RLM_READVALUES *);

Parameters

long Address of a structure that will be used to return the values of the RLM internal variables.

Return values

none

Description

The results are passed back in a structure of the form:
34 bytes Name of the default debug directory
34 bytes Name of the default directory for loading RLLs
Word Default timeout for unloading RLLs that are dynamically loaded.
word Debug Mode status
word Report Mode status


RLM_RelocLD

Relocate using C68 relocation

(d0 = 11)

Do the relocation of the specified bit of code. The relocation table supplied will be in the format of that used by the LD linker.

C prototype:

void RLM_RelocLD (char *, BSS_HEADER *);

Parameters

Long Base address of the code to be relocated.
long Address of the BSS area for the code to be relocated

Return Values

none

Description

This routine examines the System Variable that holds the Processor type information (at offset $a0), and if it is not set it performs checks to determine the processor type. The system variable is then updated with the results of these checks.

If the processor is a 68020 or better, then the System Variable that controls hardware FPU support (at offset $d0) is examined. If this not set, then a check will be made to see if hardware FPU is present. The System Variable will then be set to disable checks if not found, and to use hardware FPU if it is found.

If the processor is a type that supports caches (i.e. a 68020 or better), then the current cache state will be read; the caches disabled while the relocation takes place; and then the original cache state restored.

Notes

  1. It is assumed that all locations that need relocation are of type long. No provision is made for any shorter data types.
  2. To aid with transition, if the "<<RELOC>>" string is missing from the start of the area passed, it will be assumed that this is an LD v1.xx format area that is missing this identifying string.


RLM_RelocGST

Relocate using GST relocation

(d0 = 12)

Do the relocation of the specified bit of code. The relocation table supplied will be in the format of that used by the GST linker.

C prototype:

int RLM_RelocGST (char *, long *);

Parameters

long Base address of the code to be relocated.
long Address of the BSS area for the code to be relocated

Return Values

none

Description

As with the RLM_RelocLD() routine, processor type will be detected, hardware FPU will be detected and caches handled if appropriate.

Note that it is assumed that all locations that need relocation are of type long. No provision is made for any shorter data types.


RLM_LibrarySymbol

Get library symbol address

(d0 = 13)

Get the address of the given symbol from the given RLL library. The library must already be loaded.

C prototype:

char * RLM_LibrarySymbol(char * symname, char * libname

Parameters

long Name of the symbol to find as a C string
long Name of the library to search

Return Values

0 (NULL) Symbol (or library) not found
Other Address of the symbol.

Description


RLM_ProgramSymbol

Get Program symbol address

(d0 = 14)

Get the address of the given symbol from any RLL used by the current program. The library must already be loaded.

C prototype:

char * RLM_ProgramSymbol(char *name);

Parameters

char * name Name of the symbol to find as a C string

Return Values

0 (NULL) Symbol not found.
Other Address of the symbol

Description