[comp.sys.amiga.tech] Making Shared Libraries

peter@cbmvax.commodore.com (Peter Cherna) (12/16/89)

In article <1989Dec15.042112.9582@aucs.uucp> 840445m@aucs.UUCP (Alan McKay) writes:
>In article <596@cameron.cs.duke.edu> amr@dukee.egr.duke.edu (Anthony M. Richardson) writes:
>>I've always thought the Amiga shared libraries were a nifty idea and
>>so I've decided to try and create my own library. Blink (with thei
>>
>>Tony Richardson        amr@dukee.egr.duke.edu
>
>Try 'oml' which comes with Lattice 5.0x.  It is used specifically for 
>making shared libraries.
>-- 
>+ Alan W. McKay       +  VOICE: (902) 542-1565                        +
>+ Acadia University   +  "Courage my friend, it is not yet too late   +
>+ WOLFVILLE, N.S.     +   to make the world a better place."          +
>+ 840445m@AcadiaU.CA  +                    - Tommy Douglas            +


Actually, oml is for making linked libraries, which may indeed by
shared _at_compile_time_.  Things like lc.lib, amiga.lib, and others
are like this.

However, I believe Anthony is talking about making Amiga shared libraries
that live in libs:.  There are new support features as of the 5.04 release
of Lattice that help make this easy.

Your C source modules must be compiled with the -ml switch.

If you have a function foo that takes an int and a long *, and returns
a char *, you would declare it like

char * __saveds __asm LIB_foo(register __d0 int i, register __a0 long *lptr)

The __saveds instructs Lattice to set up your data area (off A4) when
anybody calls your function.  The __asm keyword states that you intend
to specify which registers receive which parameters, as shown above.

The 'LIB_' is any prefix you care to associate with the actual names
of the functions.  You must also provide this prefix to blink.

If you wish from within your library to call one of your public functions
through the function table, you just do so, as in:

	cptr = foo(i, lptr)

In highly exceptional circumstances, you may wish to call yourself directly
(not through the table).  Then use

	cptr = LIB_foo(i, lptr)

Note that if someone SetFunctions() your library, only the former type
of call are affected.

You will also have to create an "fd" file, which typically looks like

##base MyLibBase
##bias 30
foo(i,lptr)(D0/A0)
...

##end

The ##base directive names the library base that clients of your
library will need.
The ##bias directive gives the offset to the first of your functions
(for a library, it is 30).
Your functions follow, with the parameters named in brackets, and the
registers after.  Registers are separated by "/" or by ",".  Use
"/" when in correct order for multiple moves (An/Am or Dn/Dm are ok
if n < m, An/Dm is always ok, Dm with An must use a comma, i.e. Dm,An).

Lattice's fd2pragma utility will build a pragma file you can include
so that clients may call your routines.  They'll have to declare
struct Library *MyLibBase and call OpenLibrary() to get it.
The declaration must precede the #include of your pragma file.

In order to call yourself through the library jump table, you must
also include this file.  Your own library base will be in A6, so
you should

	#define MyLibBase (struct Library *)getreg(REG_A6)

When you link, you must link with Lattice's libent.o first,
libinit.c second, and your .o files after.  As well, you provide
LIBPREFIX _LIB_ (or whatever you chose, but you'll need a leading
underscore here), and LIBFD mylib.fd (your fd file).

Also, you may use what look like global variables, and Lattice
arranges to stuff them off your library base.  In the source to
libinit.c, they imply you can initialize stuff at the appropriate
moment.  Well, a warning: DO NOT INITIALIZE ANY OF YOUR GLOBALS
IN LIBINIT.C.  If you need to do stuff upon open, add a call to
some MyOpenFunc() inside LibOpen(), and put that function in a module
other than libinit.c.

If you need stuff in your library base to be public, you'll have
to extend the MyLibrary structure in libinit.c, and figure out
how to access it.  Any globals that Lattice cares for you automatically
are placed whereever Lattice feels, and could change as you change
your source.

You should end up with a shared library.

Hope this helps.

--
     Peter Cherna, Software Engineer, Commodore-Amiga, Inc.
     {uunet|rutgers}!cbmvax!peter    peter@cbmvax.cbm.commodore.com
My opinions do not necessarily represent the opinions of my employer.

"A friend of mine is into Voodoo Acupuncture.  You don't have to go.  You'll
just be walking down the street and ..... oooohhh, that's much better..."
     - Steven Wright

ggk@tirith.UUCP (Gregory Kritsch) (09/16/90)

In a message posted on 16 Sep 90 15:55:29 GMT,
butch@fergvax.unl.edu (FERGVAX Daily Operator) wrote:

FDO>	Anyway, if anyone who has made a library for the Amiga and would
FDO>not mind sharing the how-to's of it all, I would very much appreciate
FDO>it, since I've tried and failed on several occasions to make one.

Okay, I've created several libraries successfully, and so I may as well
try to document what I've done.

I use Lattice C 5.05, and Lattice Asm for my work.  I do NOT use the
blink library making utility, since it does not work as far as I can
tell.  There are some things which must be done awkwardly, I'd be
interested in hearing of anyone's solutions.

The first part of creating a library is the first segment of the load
file, which pretty much has to be done with an assembler (to get data in
the code section).  I'm going to insert an example file, and add
documentation to each step along the way.

All files , comments, and notes in this example are copyright (c) 1990
by Gregory Kritsch, All rights reserved, except where borrowed from
the v1.1 RKM Appendix library example, which is copyright (c) 1985
Commodore-Amiga Inc.  By now, the amount of actual Commodore code is so
minimal, I don't think this really matters.  Use as an example basis for
freeware products is permitted.  EMail me (ggk@tirith.UUCP) for details
on using it in a commercial or shareware product. 

 *
 * $Header: tirith:usr/dev/work/juliet/jms/rcs/lib.a,v 2.0 90/04/01 15:35:30 kritschg Exp $
 *
 

	include "base.i"

That file describes a few constants, and includes all the other files. 
See below.

	csect	romtag,0,2,0,4
; code segment
; long word aligned
; use 4 byte absolute addresses

The RomTag must occur in the first HUNK_CODE segment in the load module.
Assigning it a unique section name and not using Small Code is probably
a good idea (don't let the linker merge it, just in case it moves it). 
The closer you can get the RomTag to the beginning of the segment, the
(almost trivially) faster it will be found.

;--- external references
;--- standard library vectors
	xref	_LibInit
	xref	_LibOpen
	xref	_LibClose
	xref	_LibExpunge
	xref	_LibNull

These functions are written in C.  If you're doing assembly, they should
probably go in this segment as well.  These are the "standard" library
functions... the next set are "custom".  Yes, the table was derived from
the _lib.fd file - remember, third column is comments.

I've added two '_', rather than one for a reason.  It allows me to call
my own library internally through #pragmas and the library base rather
than directly.  This means that SetFunction() will be fully, not
partially, effective.

;--- custom function vectors
	xref	__ARexxQuery	() ()
	xref	___mblog	(fmt,a,b,c,d,e) (A0,D0/D1/D2/D3/D4)
	xref	__AddFlo	(name,mode) (A0,D0)
	xref	__AddReq	(file,pass) (A0,A1)
	xref	__FindScreen	()()
	xref	__FreeScreen	()()
	xref	__SetScreen	(scr)(a0)
	xref	__AddArea	(area) (A0)
	xref	__OpenArea	(name,mode) (A0,D0)
	xref	__OpenFirstArea	(mode) (D0)
	xref	__OpenNextArea	(area,mode) (A0,D0)
	xref	__CloseArea	(area) (A0)
	xref	__RemoveArea	(area) (A0)
	xref	__ReadMsg	(area,num,msg,text) (A0,D0,A1,A2)
	xref	__ReadMsgText	(area,num,msg,text) (A0,D0,A1,A2)
	xref	__UpdateMsg	(area,num,msg) (A0,D0,A1)
	xref	__PostMsg	(area,msg,text) (A0,A1,A2)
	xref	__DeleteMsg	(area,num) (A0,D0)
	xref	__GetField	(body,field,buf,len) (A0,A1,A2,D0)
	xref	__FindField	(body,name)(A0,A1)

;--- debugging
	IFD	DEBUG
	xref	_dprintf
	ENDC

The debugging at this level essentially causes register dumps on every
function call entry and exit.  There's not much else.  Oh, btw, I'm
using lattice's __asm keyword, so my arguments are passed to the C
functions in registers, not on the stack.  If you want (need) them on
the stack, you must put assembler stubs inside the library, or you could
specify that your functions take parameters on the stack (unlike nearly
every other library out there).

;--- beginning of the code
; if called from AmigaDOS, return error code 30
entry:
        moveq.l	#30,d0
        rts

Really simple.  Set d0 to some value and RTS, in case the user types
your library name in as a command.  The RKM reccomends 0, I use 30 here
to cause a failure.  Once I wrote a short routine to print out the
library idString (see below) and return.


This is the romtag.  Notice that it is, uh, 4 bytes (I think) from the
beginning of the segment.  Look in the file exec/resident.{h|i} for the
details on this structure.  Be very careful not to mess it up.

;--- romtag and other resident stuff
romtag:
	dc.w	RTC_MATCHWORD
	dc.l	romtag

The first six bytes identify the RomTag.  The first two bytes MUST be
RTC_MATCHWORD (which is "the official illegal instruction"), and the
following long word MUST be a pointer to the first byte.

	dc.l	endskip

This pointer MUST be within the same segment, according to the RKM.  I'm
not entirely sure why, but I suspect it has to do with searching and not
finding an appropriate library (like if someone renames the .library file).

	dc.b	RTF_AUTOINIT

There are two bits defined for that field, RTF_COLDSTART and
RTF_AUTOINIT.  RTF_COLDSTART is for libraries in the ROM or on the
KickTagPtr list, and indicates they should be inited during boot time. 
Otherwise, I think they would be inited on the first OpenLibrary() call
for them, but I'm not sure.

The second is RTF_AUTOINIT.  Since a RomTag can indicate just about
anything, not just a library or device, you don't always want Exec to
create a Library base structure for you.  By setting RTF_AUTOINIT, the
RT_INIT field points to a four long word structure used to create the
library base.  Otherwise, it points to a function to execute to
initialize the whatever.  Some older libraries and devices don't use
RTF_AUTOINIT, and create the library base internally.

	dc.b	VERSION
	dc.b	NT_LIBRARY

Oh, by the way, with the assistance of the RKM, you can also use this
template to create an NT_DEVICE entry (just add two more standard
functions, BeginIO and AbortIO).  Or, if you want to put some code or
something on the KickTagPtr list, you can set this to something else.

	dc.b	0

That was the priority.  Only really used if you're on the KickTagPtr
list (or in the ROMs).

	dc.l	libname
	dc.l	libid

libname is a nul terminated string, including the ".library".  It must
exactly match the disk file name, except in case sensitivity.  Note that
OpenLibrary() IS case sensitive.

libid is the "idString" of your library.  It has a very rigid format in
the RKM:
   'name version.revision (dd MMM yyyy)',13,10,0
I don't know of anything that depends on this, but you should follow it
anyhow.

	dc.l	init

This is the RT_INIT pointer discussed in RTF_AUTOINIT.  Immediately
following is the init table.

init:
	dc.l	BaseSize

The POSITIVE size of your library base, AT LEAST sizeof(struct Library).
If you have extended your library structure to include private data, you
should MAKE SURE you use the correct size.  I have an external program
that basically does a printf("%d\n",sizeof(struct JulietBase)).  THIS IS
WHERE A MESSUP WILL HURT!

	dc.l	LibFuncTab

A pointer to an array of function entry points, terminated by a -1 (see
below).

	dc.l	LibDataTab

A pointer to an InitStruct data array.  See the autodocs on
exec/InitStruct() if you're curious, exec/initializers.i is enough info
to build the table I think.

	dc.l	LibInit

A pointer to an init function to call.

;--- function table
LibFuncTab:
;--- standard functions
;--- debug trap versions
	IFD	DEBUG
	dc.l	LibOpen
	dc.l	LibClose
	dc.l	LibExpunge
	dc.l	LibNull
	ENDC
;--- non-debug trap versions
	IFND	DEBUG
	dc.l	_LibOpen
	dc.l	_LibClose
	dc.l	LibExpunge
	dc.l	_LibNull
	ENDC

;--- custom functions
	dc.l	__ARexxQuery	() ()
	dc.l	___mblog	(fmt,a,b,c,d,e) (A0,D0/D1/D2/D3/D4)
	dc.l	__AddFlo	(name,mode) (A0,D0)
	dc.l	__AddReq	(file,pass) (A0,A1)
	dc.l	__FindScreen	()()
	dc.l	__FreeScreen	()()
	dc.l	__SetScreen	(scr)(a0)
	dc.l	__AddArea	(area) (A0)
	dc.l	__OpenArea	(name,mode) (A0,D0)
	dc.l	__OpenFirstArea	(mode) (D0)
	dc.l	__OpenNextArea	(area,mode) (A0,D0)
	dc.l	__CloseArea	(area) (A0)
	dc.l	__RemoveArea	(area) (A0)
	dc.l	ReadMsg		(area,num,msg,text) (A0,D0,A1,A2)
	dc.l	ReadMsgText	(area,num,msg,text) (A0,D0,A1,A2)
	dc.l	__UpdateMsg	(area,msg) (A0,A1)
	dc.l	PostMsg		(area,msg,text) (A0,A1,A2)
	dc.l	__DeleteMsg	(area,num) (A0,D0)
	dc.l	GetField	(body,field,buf,len) (A0,A1,A2,D0)
	dc.l	__FindField	(body,field) (A0,A1)

	dc.l	-1

;--- data to initialize the library base with
LibDataTab:
	INITBYTE	LH_TYPE,NT_LIBRARY
	INITLONG	LN_NAME,libname
	INITBYTE	LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
	INITWORD	LIB_VERSION,VERSION
	INITWORD	LIB_REVISION,REVISION
	INITLONG	LIB_IDSTRING,libid
	dc.l	0	

Most of LibDataTab is probably directly from the RKM, since I don't
claim to fully understand InitStruct() [yet].  Probably doing a straight
copy is your safest bet.

;--- the name and id strings
libname:
	dc.b	'jms.library',0

libid:
	dc.b	'JMS II (12 May 1990)',13,10,0

Note the nul terminated strings.  You should change them to suit your
own needs.

;--- word align for code
	ds.l	0

The following "functions" are mainly to correct problems I had.  Some of
them may not have been neccesary, I'm not sure.  It works, I'm happy.

LibInit:
	movem.l	d1-d7/a0-a6,-(sp)
	jsr	_LibInit
	movem.l	(sp)+,d1-d7/a0-a6
	rts

the LibInit function has a return value in d0.  Everything else must be
preserved I think, including A0,A1,D1 (which normally aren't).

As noted below, there is (was?) a bug in Lattice 5.04, where using the
__asm key with too many registers caused it to clobber some before
taking working copies.  I wish Lattice was a bit more intelligent with
the __asm keyword.

;--- kludge aroung LC 5.04 compiler errors with __asm keyword
;    passing A0,A1,A2 and A6 results in A2 being clobbered
ReadMsg:
	move.l	a2,d1
	jmp	__ReadMsg

ReadMsgText:
	move.l	a2,d1
	jmp	__ReadMsgText

PostMsg:
	move.l	a2,d1
	jmp	__PostMsg

GetField:
	move.l	a2,d1
	jmp	__GetField

;--- kludge to preserve registers properly for expunge routine
	IFND	DEBUG
LibExpunge:
	movem.l	a0-a6/d1-d7,-(sp)
	jsr	_LibExpunge
	movem.l	(sp)+,a0-a6/d1-d7
	rts
	ENDC

The debugging traps exist for the register dump.  It does, however, look
like I've removed that code partially from this lib.a version.

;--- debugging traps
	IFD	DEBUG
LibOpen:
	jsr	_LibOpen
	rts

LibClose:
	jmp	_LibClose

LibExpunge:
	bsr	regdump
	movem.l	a0-a6/d1-d7,-(sp)
	jsr	_LibExpunge
	movem.l	(sp)+,a0-a6/d1-d7
	bsr	regdump
	rts

LibNull:
	jmp	_LibNull

regdump:
	bchg	#1,$bfe001

	movem.l	d0-d7/a0-a7,-(sp)
	pea	fmtstr
	jsr	_dprintf

For the curious, dprintf() is a Lattice function that goes directly to
the printer, through the cia port and the debug.lib RawDoFmt() type
functions. 

	move.l	#14965,d0
1$	dbra	d0,1$

	addq.l	#4,sp
	movem.l	(sp)+,d0-d7/a0-a7
	
	bchg	#1,$bfe001
	
	rts
	
fmtstr:
	dc.b	'd0:$%08lx d1:$%08lx d2:$%08lx d3:$%08lx',13,10
	dc.b	'd4:$%08lx d5:$%08lx d6:$%08lx d7:$%08lx',13,10
	dc.b	'a0:$%08lx a1:$%08lx a2:$%08lx a3:$%08lx',13,10
	dc.b	'a4:$%08lx a5:$%08lx a6:$%08lx a7:$%08lx',13,10
	dc.b	13,10,0

	ENDC

;--- align the endskip
	ds.l	0

;--- end of this segment
endskip:

endskip MUST MUST MUST be in the same segment as the RomTag.

	end

-- end of lib.a --

Now, base.i, for the curious.  Fairly boring.  BaseSize is determined by
an external program, of course.

;------------------------------------
; $Header: tirith:usr/dev/work/juliet/jms/rcs/base.i,v 2.0 90/04/01 15:44:50 kritschg Exp $
; $Author: kritschg $
; $Revision: 2.0 $
; $Date: 90/04/01 15:44:50 $
;------------------------------------

	include "exec/types.i"
	include "exec/libraries.i"
	include "exec/lists.i"
	include "exec/resident.i"
	include "exec/initializers.i"

BaseSize	equ	$000008D4
VERSION		equ	2
REVISION	equ	0
SUBREV		equ	0

-- end of base.i --

Now, library.c.  This is the C functions for LibOpen, LibClose, LibInit,
LibExpunge, and LibNull.  There are some strange things in here, that
aren't explained very well in the RKM docs.  I'm cutting parts of this
file out, that are directly related to the discussion of creating a
library.

/*
 * $Header: tirith:usr/dev/work/juliet/jms/rcs/library.c,v 2.0 90/04/01 15:35:51 kritschg Exp $
 */

#include "jms/jms.h"

Note that struct JulietBase is defined in jms/jms.h.  It's not really
important, other than it begins as:
   struct JulietBase {
      struct Library Library;
      ULONG SegList;
The struct Library MUST be the first field in the structure, this is the
only restriction.

For no apparent reason, you are passed your library base pointer in d0
and the result of LoadSeg() in a0.  Every other library function has the
library base in A6.  Remember, this is assuming RTF_AUTOINIT.  If you
don't use RTF_AUTOINIT, I'm not sure what you get (if anything at all). 

Note: Exec has, I think, done a Forbid() for you here, and will call
Permit() later for you.  The RKM reccomends keeping this routine very
short.  I tend to agree. 

Return Value:  You should return the pointer to your library base (or
NULL if the init failed), in D0 (which is the normal register for
Lattice C to put return values in).

struct JulietBase * __asm
LibInit(register __d0 unsigned long lb, register __a0 unsigned long Seglist)
{
	register struct JulietBase *JulietBase;

	JulietBase = (struct JulietBase *)lb;
	JulietBase->Seglist = Seglist;

	return(JulietBase);
}


This function is called when Exec has determined that it needs some
memory, typically from within AllocMem() when there is very little
memory available.  As such, MAKE NO ASSUMPTIONS about the context you
will be called in.  You may be a Task or a Process, so dos calls are
probably out.  Calling AllocMem() is probably taboo as well.

Note: Once again, Exec has called Forbid() for you, and will call
Permit() for you as well.  Keep it short and sweet.

Note: The RKM infers that Expunge will be called by AllocMem() whenever
it needs memory.  My experience is that it will only be called by
AllocMem() IF THE OPENCNT IS 0.  I hope CBM fixes this (sometimes,
Expunge could free data structures not in use, even though the library
is open).

Return Value: Return a NULL if your library is still in memory, or the
segment list (stored somewhere from the LibInit call) if you wish to be
unloaded.

long __asm
LibExpunge(register __a6 struct JulietBase *JulietBase)
{
	long seg;
	register struct Area *area, *next;

/* now expunge the library if possible */
	if (JulietBase->Library.lib_OpenCnt == 0) {
		Remove(JulietBase);

As soon as you call Remove, you're off the library list, and that pretty much
gaurantees that you'll want to return your seglist and be removed from
memory.  Any conditions should be checked BEFORE THIS POINT.

		seg = JulietBase->Seglist;
		FreeMem((void *)(((long)JulietBase) - JulietBase->Library.lib_NegSize),JulietBase->Library.lib_NegSize + JulietBase->Library.lib_PosSize);

NOTE: YOU MUST CACHE THE SEGMENT LIST BEFORE CALLING FREEMEM().  As soon
as you call FreeMem(), the library base is considered entirely invalid.

		return(seg);
	} else {
		JulietBase->Library.lib_Flags |= LIBF_DELEXP;

I'm not 100% sure, but the RKM has this clause, so I have it too.  I
don't think I've ever seen it called (I don't think it can be). 
However, if you have your own conditionals about expunges, you should
set LIBF_DELEXP if Expunge is called and you don't remove yourself.

		return(NULL);
	}
}

This is called by the OpenLibrary() function every time someone opens
the library.  I think Exec does a Forbid(), but its definitely not as
critical.  I do dos calls here.

Note: Increment the open count, and clear the LIBF_DELEXP bit in this
function. 

Return Value: return the library base pointer.

struct JulietBase * __asm
LibOpen(register __a6 struct JulietBase *JulietBase)
{

	JulietBase->Library.lib_OpenCnt++;
	JulietBase->Library.lib_Flags &= ~LIBF_DELEXP;

	return(JulietBase);
}

This is related to a call to CloseLibrary().  There are two possible
results from this function: a NULL, which means to just keep on going,
or the segment list, which means that you've called expunge and it
returned the seglist, indicating the library should be removed.  The
CloseLibrary() call to LibExpunge() is done IF LIBF_DELEXP is set.

Note: Decrement the open count.

long __asm
LibClose(
	register __a6 struct JulietBase *JulietBase,
	register __a1 struct IOStdReq *ior)
{
	JulietBase->Library.lib_OpenCnt--;

/* determine if we should try to expunge */
	if ((JulietBase->Library.lib_OpenCnt == 0) && (JulietBase->Library.lib_Flags & LIBF_DELEXP)) {
		return(LibExpunge(JulietBase));
	} else {
		return(NULL);
	}
}

This is sort of a "reserved for future expansion" function.  It should
return NULL, I think (either that or just be an rts), so this code below
may be wrong.  I don't think it will be called under 1.3, although maybe
under 2.0... 

void __asm
LibNull()
{
}

-- end of library.c --

Additional notes:

When compiling, I use lc1 -b0 to force absolute addressing.  Needless to
say, A4 will not be properly set for relative addressing.  There is no
c.o, so getting A4 might also be some fun.  I think the lc2 -y may work,
but I'm note sure.

Specify the lib.a object module FIRST on the FROM line to BLink.

Be careful using SMALLCODE and/or SMALLDATA.

Don't link with any of the c*.o family.  Also remember that since there
is NO c.o, so some things just plain won't work properly.  You should
stay away from any complicated runtime library functions (like C files),
and should use pragmas for external libraries.  Avoid amiga.lib like the
plague, I only include it for the dprintf() function.  

Note that the best thing for other libraries (like dos, graphics,
intuition, &c) is to add struct MumbleBase *MumbleBase to your library
base structure, and create your own #pragma files using
YourBase->MumbleBase as the library base (instead of the Lattice
provided #pragmas, which use the global MumbleBase).

Globals aren't actually evil, just strongly disreccommended.  Remember,
if you use globals, especially if they're volatile (ie they change) you
should put semaphores around access to them.  Even stuff in your library
base may need to be semaphored.  Remember that you CAN have the very
same function doing the very same thing at almost the very same time
within library code.

Declare your library base for all functions.  An example declaration:

/*
 * $Header: Bottom:usr/dev/work/juliet/msg/rcs/field.c,v 2.0 90/04/01 18:05:49 kritschg Exp $
 */

#include "jms/jms.h"

char * __asm
_FindField(register __a6 struct JulietBase *JulietBase,
	register __a0 char *body,
	register __a1 char *name)
{

Note that this function could call itself recursively as FindField(),
not _FindField(), if you include the normal pragmas to your own library.
This has the advantage that SetFunction() works for calls made inside
your library (which is a good idea).

Oh, a word about .fd files.  They're really simple:

##base <base name>
* this is a comment: <base name> must start with an '_' for fd2pragma,
* this _ is removed (normal C vs. Asm thing).
* eg. ##base _JulietBase
##bias 30
* the offset of the first function, expressed as a positive rather than
* a negative.  Just leave it at 30.
function(arg1,arg2,...)(r1,r2,...)
* argN are not actually looked at, but make them meaniful for humans
* reading the file.
* rN are one of the registers D0-D7/A0-A5 (A6 and A7 are already in use).
##end
* you MUST mark the end this way

If you have any questions, mail me.

FDO>Butch Rosecrans
FDO>butch@fergvax.unl.edu

---
  Gregory Kritsch
    Fido:  1:221/208.11110  [1:163/109.30]
    UUCP:  xenitec!tirith!ggk

lphillips@lpami.wimsey.bc.ca (Larry Phillips) (09/16/90)

In <2751.653532429@tirith.UUCP>, ggk@tirith.UUCP (Gregory Kritsch) writes:
>
>Okay, I've created several libraries successfully, and so I may as well
>try to document what I've done.
>

Very nice tutorial Gregory! Thanks for the posting.

-larry

--
It is not possible to both understand and appreciate Intel CPUs.
    -D.Wolfskill
+-----------------------------------------------------------------------+ 
|   //   Larry Phillips                                                 |
| \X/    lphillips@lpami.wimsey.bc.ca -or- uunet!van-bc!lpami!lphillips |
|        COMPUSERVE: 76703,4322  -or-  76703.4322@compuserve.com        |
+-----------------------------------------------------------------------+

butch@fergvax.unl.edu (FERGVAX Daily Operator) (09/16/90)

	I posted a message about a month or so ago asking for any help
making a shared library for the Amiga.  I got a few responses from
people pointing to other sources, but none of those ever helped (I never
got a response about the Amiga Developer's Newsletter which supposedly
had an article on the subject).

	Anyway, if anyone who has made a library for the Amiga and would
not mind sharing the how-to's of it all, I would very much appreciate
it, since I've tried and failed on several occasions to make one.

	Also, if anyone has a copy of the Developer's Newsletter which
has the article on making libraries, I would be interested in getting a
copy (if it doesn't violate any copyright laws).  I'm not a develop so
I don't suppose I can subscribe to the newsletter (if non-developers can
subscribe, please let me know how).

Thanks in advance for any info,

Butch Rosecrans
butch@fergvax.unl.edu

lhotka@incstar.uucp (Glamdring) (09/17/90)

In article <butch.653500529@fergvax>, butch@fergvax.unl.edu (FERGVAX Daily Operator) writes:
> 	Anyway, if anyone who has made a library for the Amiga and would
> not mind sharing the how-to's of it all, I would very much appreciate
> it, since I've tried and failed on several occasions to make one.

I would second this motion - if anyone would like to post an example or
some pointers on this topic it would be very nice.  I have read through
several books and such, but it is still somewhat confusing and no one ever
seems to publish an example...

> Butch Rosecrans
> butch@fergvax.unl.edu
 ______________________________________________________________________
/ Rockford Lhotka				INCSTAR Corp	       \
| Systems Administrator				PO Box 285	       |
| incstar!lhotka@rosevax.rosemount.com		1990 Industrial Blvd   |
\ 612/779-1701					Stillwater, MN 55082   /
 ----------------------------------------------------------------------

dlarson@blake.u.washington.edu (Dale Larson) (09/18/90)

>In article <butch.653500529@fergvax>, butch@fergvax.unl.edu (FERGVAX Daily Operator) writes:
>> 	Anyway, if anyone who has made a library for the Amiga and would
>> not mind sharing the how-to's of it all, I would very much appreciate
>> it, since I've tried and failed on several occasions to make one.

Manx comes with example code and detailed instructions for the creation
and use of shared libraries.  Under 5.0 it is really easy.



--
-Dale Larson  (dlarson@blake.u.washington.edu)

valentin@cbmvax.commodore.com (Valentin Pepelea) (09/21/90)

In article <259@incstar.uucp> lhotka@incstar.uucp (Glamdring) writes:
>
>> 	Anyway, if anyone who has made a library for the Amiga and would
>> not mind sharing the how-to's of it all, I would very much appreciate
>> it, since I've tried and failed on several occasions to make one.
>
> I would second this motion - if anyone would like to post an example or
> some pointers on this topic it would be very nice.  I have read through
> several books and such, but it is still somewhat confusing and no one ever
> seems to publish an example...

You both have pointed out a weakness in the available documentation. While the
useage of shared libraries and devices is well explained, the process of
creating such beasts is covered with clarity and simplicity exemplified by
the KGB documentation bureau.

All I can do to help you out for now, it to tell you that there is nothing to
it. Shared libraries consist simply of a skeleton, along with a set of
functions that accompany them. For an assembler example, look in the ROM Kernel
Manual, Includes & Autodocs. For a C example, look in AmigaMail, page III-11.
AmigaMail is a tachnical newsletter sent by CATS (Commodore-Amiga Technical
Support) to registered devellopers.

No, I don't work for CATS.

Valentin
-- 
The Goddess of democracy? "The tyrants     Name:    Valentin Pepelea
may distroy a statue,  but they cannot     Phone:   (215) 431-9327
kill a god."                               UseNet:  cbmvax!valentin@uunet.uu.net
             - Ancient Chinese Proverb     Claimer: I not Commodore spokesman be

bcphyagi@Twg-S5.uucp (Stephen Walton) (09/22/90)

In article <14576@cbmvax.commodore.com> valentin@cbmvax.commodore.com
(Valentin Pepelea) writes:
>
>For a C example [of a shared library], look in AmigaMail, page III-11.
>AmigaMail is a tachnical newsletter sent by CATS (Commodore-Amiga Technical
>Support) to registered devellopers.

The AmigaMail article is Lattice-specific.  For a C example for Manx
5.0, look in the directory reslib on the fourth (or maybe third)
distribution floppy.  Write your subroutines, put their names in a
table in the supplied main, run Make with the example makefile, and
you're done.  The next rev of XPR Kermit (currently under development)
uses it with great success.
--
Stephen R. Walton, Dept. of Physics and Astronomy, Cal State Northridge
I am srw@csun.edu no matter WHAT the stupid From: line says!