add support for simple shared libraries

This commit is contained in:
bebbo 2024-05-17 13:03:46 +02:00
parent b00180b09b
commit 88a4f42dca
5 changed files with 320 additions and 93 deletions

View File

@ -113,6 +113,7 @@ one: $(LIBS_TO_BUILD)
# install all kinds into the prefix
.PHONY: install_lib install_libb install_libm020 install_libm020bb install_libm020bb32 install_libm881 install_libm020bb881 install_libm020bb32881
install: install_lib install_libb install_libm020 install_libm020bb install_libm020bb32 install_libm881 install_libm020bb881 install_libm020bb32881
cp $(root)/mkstub $(PREFIX)/bin
install_lib:
$(MAKE) install_one kind=lib to=""

128
mkstub Executable file
View File

@ -0,0 +1,128 @@
#!/bin/bash
out=$1
dir=$out-support
shift
echo creating support files in $dir
rm -rf $dir
mkdir -p $dir
echo >$dir/init-stub-${out}.c "// STUB to load and init the so file
#include <proto/dos.h>
#include <proto/exec.h>
#include <stabs.h>
void * ${out}Base = 0;
void * __${out}_sp = 0;
void * __${out}_a4[3] = {0};
// linked first stub
__attribute__((section(\".dlist_so_${out}\")))
static long __so_${out}_start[1] = {0};
// init all references by name
void __so_${out}_open() {
${out}Base = OldOpenLibrary(\"$out.library\");
if (!${out}Base) {
FPuts(Output(), \"failed to load $out.library\n\");
exit(10);
}
register long * a0 asm(\"a0\") = &__so_${out}_start[1];
register void * a6 asm(\"a6\") = ${out}Base;
asm volatile(\"jsr (-30,a6)\"::\"r\"(a0), \"r\"(a6));
}
void __so_${out}_close() {
if (${out}Base)
CloseLibrary(${out}Base);
}
ADD2INIT(__so_${out}_open, -78); // one less than __initlibraries
ADD2EXIT(__so_${out}_close, -78);
"
# get last word = var name of exported functions
m68k-amigaos-objdump -t $* | grep "0000 01 " | while read line; do
n=$(echo $line | awk '{ print $NF }' | grep -v "___")
n=${n:1}
if [[ "$n" == "" ]]; then
continue;
fi
# only normal variables
echo >>$dir/export-$out.c "
extern void * $n;
__attribute__((section(\".dlist_so_export_$n\")))
char const * __name_$n = \"$n\";
__attribute__((section(\".dlist_so_export_$n\")))
void ** __ptr_to_$n = (void**)&$n;
"
echo creating $dir/stub-$n.c
text=${line##*.text}
# text segment -> function with stub
if [[ "$text" != "$line" ]]; then
echo >$dir/stub-$n.c "//=== BEGIN stubs for $n
extern void * ${out}Base;
extern void * __${out}_sp;
extern void * __${out}_a4[2];
__attribute__((section(\".data.${out}_$n\")))
long (*__ptr_$n)();
__attribute__((section(\".text.${out_}$n\")))
void $n() {
asm volatile(\"move.l (sp)+,%0\" : \"=m\"(__${out}_sp));
asm volatile(\"movem.l a4-a6,%0\" : \"=m\"(__${out}_a4));
asm volatile(\"move.l %0,a4;\nmove.l a4,a6;\nadd.l #32766,a4\" :: \"m\"(${out}Base));
asm volatile(\"move.l %0,a5;jsr (a5)\" :: \"m\"(__ptr_$n));
asm volatile(\"movem.l %0,a4-a6\" :: \"m\"(__${out}_a4));
asm volatile(\"move.l %0,-(sp)\" :: \"m\"(__${out}_sp));
}
__attribute__((section(\".dlist_so_${out}z_$n\")))
char const * __name_$n = \"$n\";
__attribute__((section(\".dlist_so_${out}z_$n\")))
void ** __to_ptr_$n = (void**)&__ptr_$n;
//=== END
"
else
echo >$dir/stub-$n.c "//=== BEGIN stubs for $n
extern void *__${out}_sp;
__attribute__((section(\".data.${out}_$n\")))
void * $n = (void *)&__${out}_sp;
__attribute__((section(\".dlist_so_${out}z_$n\")))
char const * __name_$n = \"$n\";
__attribute__((section(\".dlist_so_${out}z_$n\")))
void ** __to_ptr_$n = &$n;
//=== END
"
fi
done
pushd $dir >/dev/null
echo compiling stubs
echo m68k-amigaos-gcc -Os -fomit-frame-pointer *stub*.c -c
m68k-amigaos-gcc -Os -fomit-frame-pointer *stub*.c -c
echo create link lib $out.a
rm -f ../$out.a
echo m68k-amigaos-ar rcs ../$out.a *stub*.o
m68k-amigaos-ar rcs ../$out.a *stub*.o
echo m68k-amigaos-gcc -resident -Os -fomit-frame-pointer export*.c -c
m68k-amigaos-gcc -resident -Os -fomit-frame-pointer export*.c -c
popd >/dev/null

16
sources/headers/dlfcn.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __DLFCN_H__
#define __DLFCN_H__
/*
* To be used withlibraries created with -noixemul -shared
*/
void * __stdargs dlopen (__const char *__file, int __mode);
int __stdargs dlclose (void *__handle);
void * __stdargs dlvsym (void *__restrict __handle,
__const char *__restrict __name,
__const char *__restrict __version);
void * __stdargs dlsym (void *__restrict __handle,
__const char *__restrict __name);
#endif //__DLFCN_H__

57
sources/nix/misc/dlfcn.c Normal file
View File

@ -0,0 +1,57 @@
#include <amistdio.h>
#include <string.h>
#include <proto/dos.h>
#include <proto/exec.h>
// the linker inserts this id behind the idString
static char id[3] = {0x0b, 0xeb, 0xb0};
void *dlopen (__const char *__file, int __mode) {
struct Library * lib = OldOpenLibrary(__file);
if (lib) {
// only one exported function -> neg size == 32, magic marker "bebb0" behind id string!
if (32 != lib->lib_NegSize || !lib->lib_IdString || memcmp(id, lib->lib_IdString + strlen(lib->lib_IdString) + 1, 3)) {
#ifndef __KICK13__
Printf("%s is not suitable for dlopen", __file);
#endif
CloseLibrary(lib);
lib = 0;
}
}
return lib;
}
/* Unmap and close a shared object opened by `dlopen'.
The handle cannot be used again after calling `dlclose'. */
int dlclose (void *__handle) {
if (!__handle)
return -1;
CloseLibrary((struct Library *)__handle);
return 0;
}
/* Find the run-time address in the shared object HANDLE refers to
of the symbol called NAME with VERSION. */
void *dlvsym (void *__restrict __handle,
__const char *__restrict __name,
__const char *__restrict __version) {
if (!__handle)
return 0;
void * r = 0;
static void const * p[3];
p[0] = __name;
p[1] = &r;
register void * a0 asm("a0") = p;
register struct Library * a6 asm("a6") = (struct Library *)__handle;
asm volatile("jsr (-30,a6)" : "=m"(r) : "r"(a0), "r"(a6));
return r;
}
/* Find the run-time address in the shared object HANDLE refers to
of the symbol called NAME. */
void *dlsym (void *__restrict __handle,
__const char *__restrict __name) {
return dlvsym(__handle, __name, 0);
}

View File

@ -1,8 +1,12 @@
#include <amistdio.h>
#include <string.h>
#include <exec/execbase.h>
#include <exec/resident.h>
#include <proto/dos.h>
#include <proto/exec.h>
extern void exit(int);
#pragma GCC push_options
#pragma GCC optimize ("-Os")
#pragma GCC optimize ("-fno-toplevel-reorder")
@ -19,13 +23,12 @@ const struct Resident __RomTag;
// place into data segment -> init with zero
__attribute__((section(".data")))
struct Library __lib = {0};
struct Library __lib = { 0 };
// track all instantiated libs, the lib_Sum fields is used to track the opening Task
__attribute__((section(".data")))
struct List __libList = {0};
struct List __libList = { 0 };
const char __libName[32] = {0};
const char __libIdString[64] = {0};
const char __libName[64] = { 0 };
const APTR __FuncTable__[];
struct ExecBase *SysBase = 0;
@ -37,75 +40,85 @@ long __initFailed = 0;
unsigned short __cleanupflag = 0;
__attribute__((section(".list___INIT_LIST__")))
const int __INIT_LIST__[1] = {0};
const int __INIT_LIST__[1] = { 0 };
__attribute__((section(".list___EXIT_LIST__")))
const int __EXIT_LIST__[1] = {0};
const int __EXIT_LIST__[1] = { 0 };
__attribute__((section(".dlist___LIB_LIST__")))
int __LIB_LIST__[1] = {0};
int __LIB_LIST__[1] = { 0 };
__attribute__((section(".list___CTOR_LIST__")))
const int __CTOR_LIST__[1] = {0};
const int __CTOR_LIST__[1] = { 0 };
__attribute__((section(".list___DTOR_LIST__")))
const int __DTOR_LIST__[1] = {0};
const int __DTOR_LIST__[1] = { 0 };
// the section for the exported functions
__attribute__((section(".dlist_so_export")))
long __so_xlib_export[1] = {0};
long __so_xlib_export[1] = { 0 };
__attribute__((section(".end_of_lists")))
const int __ZZZ_LIST__[1] = {0};
const int __ZZZ_LIST__[1] = { 0 };
__attribute__((section(".end_of_dlists")))
int __ZZZ_DLIST__[1] = {0};
int __ZZZ_DLIST__[1] = { 0 };
long __LibClose(struct Library * childLib asm("a6"));
void __callfuncs(const int * p asm("a2"), unsigned short prioo asm("d2"));
long __LibClose(struct Library *childLib asm("a6"));
void __callfuncs(const int *p asm("a2"), unsigned short prioo asm("d2"));
void __restore_a4() {
asm volatile("lea 32766(a6),a4");
}
static inline VOID __NewList(struct List *_NewList_list)
{
_NewList_list->lh_TailPred = (struct Node *) _NewList_list;
_NewList_list->lh_Head = (struct Node *) &_NewList_list->lh_Tail;
static inline VOID __NewList(struct List *_NewList_list) {
_NewList_list->lh_TailPred = (struct Node*) _NewList_list;
_NewList_list->lh_Head = (struct Node*) &_NewList_list->lh_Tail;
_NewList_list->lh_Tail = 0;
}
// init the library. defer real init stuff to LibOpen!
APTR __LibInit(long __segListIn asm("a0"), struct Library *_masterlib asm("d0"), struct ExecBase *__sysBase asm("a6")) {
// get access to the data
register long * a4 asm("a4");
register long *a4 asm("a4");
asm volatile("move.l a4,-(a7)" :: "r"(a4));
asm volatile("lea ___a4_init,%0;\n" : "=r"(a4));
struct Library *masterlib = _masterlib;
#if 0
{
struct DosLibrary * DOSBase = (struct DosLibrary *)OldOpenLibrary("dos.library");
Printf("neg=%ld, pos=%ld\n", masterlib->lib_NegSize, masterlib->lib_PosSize);
Flush(Output());
CloseLibrary(&DOSBase->dl_lib);
}
#endif
/* setup private data */
SysBase = __sysBase;
__theMasterLib = masterlib;
__segList = __segListIn;
/* set up header data */
masterlib->lib_Node.ln_Type = NT_LIBRARY;
masterlib->lib_Node.ln_Name = (char*) __libName;
masterlib->lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
masterlib->lib_Version = __lib.lib_Version;
masterlib->lib_Revision = __lib.lib_Revision;
masterlib->lib_IdString = (char*) __libIdString;
// /* set up header data */
// masterlib->lib_Node.ln_Type = NT_LIBRARY;
// masterlib->lib_Node.ln_Name = (char*) __libName;
// masterlib->lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
// masterlib->lib_Version = __lib.lib_Version;
// masterlib->lib_Revision = __lib.lib_Revision;
// masterlib->lib_IdString = (char*) __libName + strlen((char*) __libName) + 1;
CopyMem(masterlib, &__lib, sizeof(__lib));
__NewList(&__libList);
/* this will be added to SysBase->LibList or NULL (init error) */
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return masterlib;
}
// bye bye library
long __LibExpunge(struct Library *_masterlib asm("a6")) {
register long * a4 asm("a4");
register long *a4 asm("a4");
asm volatile("move.l a4,-(a7)" :: "r"(a4));
asm volatile("lea ___a4_init,%0;\n" : "=r"(a4));
struct Library *masterlib = _masterlib;
@ -113,26 +126,26 @@ long __LibExpunge(struct Library *_masterlib asm("a6")) {
/* set delayed expunge flag */
masterlib->lib_Flags |= LIBF_DELEXP;
/* still in use? */
if (masterlib->lib_OpenCnt)
return 0;
/* remove lib from SysBase->LibList */
Remove(&masterlib->lib_Node);
long sl = __segList;
// free the allocated ram of the lib's struct
int neg = masterlib->lib_NegSize;
FreeMem((-neg + (char* )masterlib), neg + masterlib->lib_PosSize);
/* still in use? */
if (!masterlib->lib_OpenCnt) {
/* remove lib from SysBase->LibList */
Remove(&masterlib->lib_Node);
// free the allocated ram of the lib's struct
int neg = masterlib->lib_NegSize;
FreeMem((-neg + (char* )masterlib), neg + masterlib->lib_PosSize);
}
/* return the seglist for UnLoadSeg() */
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return sl;
}
// open the library
struct Library*
__LibOpen(struct Library *_masterlib asm("a6")) {
register long * a4 asm("a4");
register long *a4 asm("a4");
asm volatile("move.l a4,-(a7)" :: "r"(a4));
asm volatile("lea ___a4_init,%0;\n" : "=r"(a4));
struct Library *masterlib = _masterlib;
@ -143,43 +156,43 @@ __LibOpen(struct Library *_masterlib asm("a6")) {
/* clear delayed expunge flag */
masterlib->lib_Flags &= ~LIBF_DELEXP;
struct Task * task = SysBase->ThisTask;
struct Task *task = SysBase->ThisTask;
// search the List if the task already opened this library.
for (struct Node * node = __libList.lh_Head; node != (struct Node *)&__libList.lh_Tail; node = node->ln_Succ) {
struct Library * childLib = (struct Library *)node->ln_Name;
if (childLib->lib_Sum == (ULONG)task) {
for (struct Node *node = __libList.lh_Head; node != (struct Node*) &__libList.lh_Tail; node = node->ln_Succ) {
struct Library *childLib = (struct Library*) node->ln_Name;
if (childLib->lib_Sum == (ULONG) task) {
++childLib->lib_OpenCnt;
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return childLib;
}
}
// get memory per lib
unsigned sz = masterlib->lib_PosSize + masterlib->lib_NegSize;
char * to = (char *)AllocVec(sz, MEMF_PUBLIC);
char *to = (char*) AllocVec(sz, MEMF_PUBLIC);
// copy jump table
CopyMemQuick(((char *)masterlib) - masterlib->lib_NegSize, to, masterlib->lib_NegSize);
CopyMemQuick(((char* )masterlib) - masterlib->lib_NegSize, to, masterlib->lib_NegSize);
to += masterlib->lib_NegSize;
// copy data segment
CopyMemQuick (&__lib, to, masterlib->lib_PosSize);
CopyMemQuick(&__lib, to, masterlib->lib_PosSize);
struct Library * childLib = (struct Library*)to;
childLib->lib_Sum = (ULONG)task;
struct Library *childLib = (struct Library*) to;
childLib->lib_Sum = (ULONG) task;
childLib->lib_OpenCnt = 1;
AddHead(&__libList, (struct Node *)&childLib[1]); // the child's libList as node...
AddHead(&__libList, (struct Node* )&childLib[1]); // the child's libList as node...
// apply datadata relocs
long * p;
long *p;
asm volatile("lea ___datadata_relocs,%0" : "=r"(p));
asm volatile("lea __etext,%0" : "=r"(a4));
if (p < a4) {
long count = *p++;
long diff = (char *)&__lib - to;
long diff = (char*) &__lib - to;
while (count > 0) {
long * t = (long *)*p++;
long *t = (long*) *p++;
*t -= diff;
--count;
}
@ -196,78 +209,87 @@ __LibOpen(struct Library *_masterlib asm("a6")) {
if (__initFailed) {
__LibClose(childLib);
return 0;
childLib = 0;
}
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return childLib;
}
// close the library
long __LibClose(struct Library * childLib asm("a6")) {
register long * a4 asm("a4");
long __LibClose(struct Library *childLib asm("a6")) {
register long *a4 asm("a4");
asm volatile("move.l a4,-(a7)" :: "r"(a4));
asm volatile("lea 32766(a6),%0;\n" : "=r"(a4));
Forbid();
--__theMasterLib->lib_OpenCnt;
// still in user
if (--childLib->lib_OpenCnt) {
long r = 0;
if (!--childLib->lib_OpenCnt) {
// disable forbid during cleanup
Permit();
return 0;
// run exit
__cleanupflag ^= -1;
__callfuncs(&__EXIT_LIST__[1], -1);
// forbid again
Forbid();
// free the instance
Remove((struct Node* )&childLib[1]);
FreeVec(((char* )childLib) - childLib->lib_NegSize);
/* one less user */
if (!__theMasterLib->lib_OpenCnt && (__theMasterLib->lib_Flags & LIBF_DELEXP))
r = __LibExpunge(__theMasterLib);
}
Permit();
// run exit
__cleanupflag ^= -1;
__callfuncs(&__EXIT_LIST__[1], -1);
Forbid();
// free the instance
Remove((struct Node *)&childLib[1]);
FreeVec(((char *)childLib) - childLib->lib_NegSize);
/* one less user */
long r = 0;
if (!__theMasterLib->lib_OpenCnt && (__theMasterLib->lib_Flags & LIBF_DELEXP))
r = __LibExpunge(__theMasterLib);
Permit();
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return r;
}
__regargs
void __so_xlib_init(char const * name, void **to) {
long * p = &__so_xlib_export[1];
void __so_xlib_init(char const *name, void **to) {
long *p = &__so_xlib_export[1];
while (*p) {
char const * oname = (char const *)*p++;
void * v = (void *)*p++;
char const *oname = (char const*) *p++;
// {
// struct DosLibrary * DOSBase = (struct DosLibrary *)OldOpenLibrary("dos.library");
// Printf("%s==%s\n", name, oname);
// Flush(Output());
// CloseLibrary(&DOSBase->dl_lib);
// }
void *v = (void*) *p++;
if (0 == strcmp(name, oname)) {
*to = v;
break;
}
}
if (!*to)
exit(10);
}
void __ResolveSymbols(long * p asm("a0"), struct Library * childLib asm("a6")) {
register long * a4 asm("a4");
void __ResolveSymbols(long *p asm("a0"), struct Library *childLib asm("a6")) {
register long *a4 asm("a4");
asm volatile("move.l a4,-(a7)" :: "r"(a4));
asm volatile("lea 32766(a6),%0;\n" : "=r"(a4));
while (*p) {
char const * name = (char const *)*p++;
void ** to = (void **)*p++;
char const *name = (char const*) *p++;
void **to = (void**) *p++;
__so_xlib_init(name, to);
}
asm volatile("move.l (a7)+,a4" : "=r"(a4));
}
extern void __initlibraries();
extern void __initcpp();
// the function table
const APTR __FuncTable__[] = { __LibOpen, __LibClose, __LibExpunge, NULL,
__ResolveSymbols,
(APTR) -1,
const APTR __FuncTable__[] = { __LibOpen, __LibClose, __LibExpunge, NULL, __ResolveSymbols, (APTR) -1,
// link __initlibraries and __initcpp behind end marker^
__initlibraries,
__initcpp
};
__initlibraries, __initcpp };
// the libraries init table
extern long __data_size;
@ -276,16 +298,18 @@ const APTR __InitTab[4] = { (APTR) &__data_size, (APTR) &__FuncTable__[0], (APTR
// that's what the library loader is looking for: the rom tag with references to the remaining data.
const struct Resident __RomTag = { RTC_MATCHWORD, (struct Resident*) &__RomTag, (struct Resident*) &__RomTag + 1,
RTF_AUTOINIT, 1,
NT_LIBRARY, 0, (char*) __libName, (char*) __libIdString, (APTR) &__InitTab };
NT_LIBRARY, 0, (char*) __libName,
(char*) __libName, // the linker will fix this!
(APTR) &__InitTab };
void __callfuncs(const int * q asm("a2"), unsigned short order asm("d2")) {
void __callfuncs(const int *q asm("a2"), unsigned short order asm("d2")) {
for (;;) {
const int * p = q;
const int *p = q;
unsigned short curprio = __cleanupflag;
unsigned short nextprio = -1;
while (*p) {
unsigned short prio = *((unsigned short *) p + 3) ^ order;
unsigned short prio = *((unsigned short*) p + 3) ^ order;
// invoke
if (prio == curprio)
@ -304,6 +328,7 @@ void __callfuncs(const int * q asm("a2"), unsigned short order asm("d2")) {
}
}
// just in case callfunc calls something which calls exit
void exit(int x) {
__initFailed = -1;
__initFailed = x;
}