Welcome, Guest. Please login or register.

Author Topic: Writing a shared library - ASM Help  (Read 4724 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline Thomas

Re: Writing a shared library - ASM Help
« on: February 16, 2017, 08:25:23 AM »
You cannot have varargs functions in a shared library.

What you do is to define a function which takes a pointer to a tag list and provide a varargs stub in a static link library which calls the shared library function.

in your shared library:

Code: [Select]
ULONG myFunctionTagList (__A0 APTR some_argument, __A1 struct TagItem *arg_taglist)

{
struct TagItem *temp_taglist = arg_taglist;
struct TagItem *ti;

while (ti = NextTagItem (&temp_taglist))
   {
   ...
   }

return (result);
}



in your static link library (or in the user's program):

Code: [Select]
void myFunctionTags (APTR some_argument, Tag tag1, ...)
{
return (myFunctionTagList (some_argument, (struct TagItem *)&tag1));
}



If you carefully check the include files for OS libraries, you'll see that they work the same: the library itself only contains TagList functions while all the varargs functions are in amiga.lib.

Offline Thomas

Re: Writing a shared library - ASM Help
« Reply #1 on: February 16, 2017, 02:20:25 PM »
Regarding registers:

A7 is the stack pointer (also referred to as SP), it cannot be used for anything else.
A6 is your library base pointer. You may use/change it in your routine if you don't need the library base, but it cannot be used for arguments.
A5 is used by the compiler as base for the local variables. You might get the compiler into deep trouble if you use it for function arguments. At least it adds some overhead.
A4 is used by the compiler as base for the global variables when the small data model is used. Same trouble as above. No issue with large data model.

D0, D1, A0 and A1 are scratch-registers. You may use/change them in your routine and don't need to preserve their values. With the exception of D0 which is used as return value. If your routine shall return something, move it into D0.

All other registers  must be preserved. This does not mean you may not use them, you only have to restore their values before you leave your routine.

Finally a word about the "register" attribute. The way you use it creates unnecessary overhead.

The register attribute tells the compiler to reserve a register for that variable. In case of a function argument which already comes in a register, this means the compiler reserves an additional register for the variable and moves the argument register into the reserved register.

For example if you declare a function argument as register __D0, the compiler will reserve a free register, for example D2 and move D0 into it.

To avoid this overhead (and excessive register usage) I suggest to omit the word register and only use __Dx or __Ax.