Admin Panel
#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")
#pragma GCC optimize ("-fomit-frame-pointer")
// make cli happy
long __safefail(void) {
return -1;
}
// library header stuff - kind of forward decls - results in a rom tag directly behind the cli-do-nothing-function.
// the real values are defined at the end.
const struct Resident __RomTag;
// place into data segment -> init with zero
__attribute__((section(".data")))
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 };
const char __libName[64] = { 0 };
const APTR __FuncTable__[];
struct ExecBase *SysBase = 0;
struct Library *__theMasterLib = 0;
long __segList = 0;
long __initFailed = 0;
// needed per instance
unsigned short __cleanupflag = 0;
long __save_a4;
long __save_sp;
struct A4List {
struct A4List * next;
void * code;
ULONG a4;
} __a4List;
__attribute__((section(".list___INIT_LIST__")))
const int __INIT_LIST__[1] = { 0 };
__attribute__((section(".list___EXIT_LIST__")))
const int __EXIT_LIST__[1] = { 0 };
__attribute__((section(".dlist___LIB_LIST__")))
int __LIB_LIST__[1] = { 0 };
__attribute__((section(".list___CTOR_LIST__")))
const int __CTOR_LIST__[1] = { 0 };
__attribute__((section(".list___DTOR_LIST__")))
const int __DTOR_LIST__[1] = { 0 };
// the section for the exported functions
__attribute__((section(".dlist_so_export")))
long __so_xlib_export[1] = { 0 };
__attribute__((section(".end_of_lists")))
const int __ZZZ_LIST__[1] = { 0 };
__attribute__((section(".end_of_dlists")))
int __ZZZ_DLIST__[1] = { 0 };
long __LibClose(struct Library *childLib asm("a6"));
void __callfuncs(const int *p asm("a2"), unsigned short prioo asm("d2"));
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");
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*) __libName + strlen((char*) __libName) + 1;
CopyMem(masterlib, &__lib, sizeof(__lib));
__NewList(&__libList);
asm volatile("move.l (a7)+,a4" : "=r"(a4));
/* this will be added to SysBase->LibList */
return masterlib;
}
// bye bye library
long __LibExpunge(struct Library *_masterlib asm("a6")) {
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;
/* set delayed expunge flag */
masterlib->lib_Flags |= LIBF_DELEXP;
long sl = __segList;
/* 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");
asm volatile("move.l a4,-(a7)" :: "r"(a4));
asm volatile("lea ___a4_init,%0;\n" : "=r"(a4));
struct Library *masterlib = _masterlib;
// Forbid is on - increase the counter
++masterlib->lib_OpenCnt;
/* clear delayed expunge flag */
masterlib->lib_Flags &= ~LIBF_DELEXP;
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) {
++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);
// copy jump table
CopyMemQuick(((char* )masterlib) - masterlib->lib_NegSize, to, masterlib->lib_NegSize);
to += masterlib->lib_NegSize;
// copy data segment
CopyMemQuick(&__lib, to, masterlib->lib_PosSize);
struct Library *childLib = (struct Library*) to;
childLib->lib_Sum = (ULONG) task;
childLib->lib_OpenCnt = 1;
struct Node* node = (struct Node* )&childLib[1];
node->ln_Name = (char *)childLib;
AddHead(&__libList, node); // the child's libList as node...
// apply datadata relocs
long *p;
asm volatile("lea ___datadata_relocs,%0" : "=r"(p));
long count = *p++;
long diff = (char*) &__lib - to;
while (count > 0) {
long t = (long) *p++;
*(long*)(t + to) -= diff;
--count;
}
CacheClearU();
// reload a4 for the child library
asm volatile(
"move.l %1,%0;\n"
"add.l #32766,%0;\n"
: "=r"(a4) : "r"(childLib));
// run init
__callfuncs(&__INIT_LIST__[1], 0);
if (__initFailed) {
__LibClose(childLib);
childLib = 0;
}
// queue the library into pr_Task->tc_TrapData
__a4List.next = (struct A4List *)task->tc_TrapData;
__a4List.code = __LibOpen;
__a4List.a4 = (ULONG)a4;
task->tc_TrapData = &__a4List;
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return childLib;
}
/**
* A safe way to restore a4: search the A4List
*/
void __restore_a4() {
asm volatile("movem.l d0/a0/a1,-(a7)");
struct ExecBase * SysBase = *(struct ExecBase **)4;
struct Task * task = SysBase->ThisTask;
struct A4List * a4i = (struct A4List *)task->tc_TrapData;
while (a4i) {
if (a4i->code == __LibOpen) {
asm volatile("move.l %0,a4" :: "a"(a4i->a4));
break;
}
a4i = a4i->next;
}
asm volatile("movem.l (a7)+,d0/a0/a1");
}
// close the library
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
long r = 0;
if (!--childLib->lib_OpenCnt) {
// disable forbid during cleanup
Permit();
// 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);
// load a4 with initial data segment
asm volatile("lea ___a4_init,%0;\n" : "=r"(a4));
/* one less user */
if (!__theMasterLib->lib_OpenCnt && (__theMasterLib->lib_Flags & LIBF_DELEXP))
r = __LibExpunge(__theMasterLib);
}
Permit();
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return r;
}
extern char __export_stubs_start;
extern char __export_stubs_end;
__regargs
char const * __so_xlib_init(char const *name, void **to) {
long *p = &__so_xlib_export[1];
while (*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;
if ((char *)v > &__export_stubs_start && (char *)v < &__export_stubs_end) {
register long * l asm("a2") = (long *)v - 1;
asm volatile("move.l a4,(%0)" :: "r"(l));
}
return 0;
}
}
return name;
}
char const * __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));
char const * r = 0;
while (!r && *p) {
char const *name = (char const*) *p++;
void **to = (void**) *p++;
r = __so_xlib_init(name, to);
}
CacheClearU();
asm volatile("move.l (a7)+,a4" : "=r"(a4));
return r;
}
extern void __initlibraries();
extern void __initcpp();
// the function table
const APTR __FuncTable__[] = { __LibOpen, __LibClose, __LibExpunge, NULL, __ResolveSymbols, (APTR) -1,
// link __initlibraries and __initcpp behind end marker^
__initlibraries, __initcpp };
// the libraries init table
extern long __data_size;
const APTR __InitTab[4] = { (APTR) &__data_size, (APTR) &__FuncTable__[0], (APTR) NULL, (APTR) &__LibInit };
// 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*) __libName, // the linker will fix this!
(APTR) &__InitTab };
void __callfuncs(const int *q asm("a2"), unsigned short order asm("d2")) {
for (;;) {
const int *p = q;
unsigned short curprio = __cleanupflag;
unsigned short nextprio = -1;
while (*p) {
unsigned short prio = *((unsigned short*) p + 3) ^ order;
// invoke
if (prio == curprio)
((void (*)(void)) *p)();
// update next prio
if (prio < nextprio && prio > curprio)
nextprio = prio;
p += 2;
}
if (nextprio == curprio)
break;
__cleanupflag = nextprio;
}
}
// just in case callfunc calls something which calls exit
void exit(int x) {
__initFailed = x;
}