amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Library erzeugen [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- [ - Beitrag schreiben - ]

08.04.2004, 13:27 Uhr

Mazze
Posts: 263
Nutzer
Hi,

ich trage mich mit dem Gedanken, aus GGTL
eine Shared-Library für den Amiga zu erzeugen.

Ich habe so etwas noch nie gemacht, und habe deshalb ein paar Fragen:

Brauche ich eine Multbase-Library, um Funktionen aus der dos.library verwenden zu können? (Lesen und Schreiben in Dateien)

Vermutlich muss ich die 'assert'-Funktionen durch etwas anderes ersetzen. Kann man gezielt Task-Held-Fehler auslösen? (Ein Guru ist mir zu brutal :D )

Im Aminet gibt es 2 Sachen, die man als Basis für shared libraries verwenden kann (Clib und SDI). Welches ist denn einfacher in der Handhabung? Ich brauche Hook-Funktionen.


[ - Antworten - Zitieren - Direktlink - ]

17.04.2004, 10:58 Uhr

Mazze
Posts: 263
Nutzer
Ich möchte folgende Funktion in eine Shared-Library einbauen:

code:
void sl_free(void *root, void (*func)(void*))
{
	struct sl_node *p;

	if (func == NULL)
		func = free;

	while ((p = sl_pop(&root)))
		func(p);
}


Ich bin davon ausgegangen, dass ich Callbacks mit "struct Hook" realisieren muss. Ich habe mir mal den Source der expat.library angeschaut. Dort wird nicht mit "struct Hook" gearbeitet. Wann braucht man "struct Hook"?

Kann ich in einer Library die C-Funktion "free" aufrufen?

[ - Antworten - Zitieren - Direktlink - ]

17.04.2004, 12:01 Uhr

cygnusEd
Posts: 104
Nutzer

@Mazze

> Ich bin davon ausgegangen, dass ich Callbacks mit "struct Hook" realisieren muss. Ich habe mir
> mal den Source der expat.library angeschaut. Dort wird nicht mit "struct Hook" gearbeitet.
> Wann braucht man "struct Hook"?

Das kannst Du machen, wie es Dir am liebsten ist. Die Hook-Struktur ist nur der "Amiga-Weg", eine Funktion
zu übergeben. Der Weg, wie er in Deinem Code-Schnipsel zu sehen ist, geht natürlich auch.
Das Problem ist, daß die Hooks nur unter 68k vernünftig funtionieren. Die Argumente werden nämlich über
die Register übergeben, was in einem PPC-System nicht ohne weiteres funktioniert. Um kompatibel zu bleiben,
ist der andere Weg wohl besser.

>Kann ich in einer Library die C-Funktion "free" aufrufen?

Wenn Du den Speicher vorher mit malloc() (oder realloc()... ) angefordert hast - ja.

Gruß
CygnusEd

[ - Antworten - Zitieren - Direktlink - ]

17.04.2004, 16:27 Uhr

Mazze
Posts: 263
Nutzer
Zitat:
Original von cygnusEd:

>Kann ich in einer Library die C-Funktion "free" aufrufen?

Wenn Du den Speicher vorher mit malloc() (oder realloc()... ) angefordert hast - ja.


Ok. Ich bin nur deshalb etwas vorsichtig, weil es heißt, dass eine Library-Funktion kein "forbid" unterbrechen darf.

[ - Antworten - Zitieren - Direktlink - ]

17.04.2004, 21:42 Uhr

obw
Posts: 94
Nutzer
Zitat:
Original von Mazze:
Zitat:
Original von cygnusEd:

>Kann ich in einer Library die C-Funktion "free" aufrufen?

Wenn Du den Speicher vorher mit malloc() (oder realloc()... ) angefordert hast - ja.


Ok. Ich bin nur deshalb etwas vorsichtig, weil es heißt, dass eine Library-Funktion kein "forbid" unterbrechen darf.


Dann mußt Du wohl die Doku deiner C-Bibliothek befragen. :D

OBW

[ - Antworten - Zitieren - Direktlink - ]

18.04.2004, 19:46 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von cygnusEd:
Das kannst Du machen, wie es Dir am liebsten ist. Die Hook-Struktur ist nur der "Amiga-Weg", eine Funktion zu übergeben. Der Weg, wie er in Deinem Code-Schnipsel zu sehen ist, geht natürlich auch.
Das Problem ist, daß die Hooks nur unter 68k vernünftig funtionieren. Die Argumente werden nämlich über die Register übergeben, was in einem PPC-System nicht ohne weiteres funktioniert. Um kompatibel zu bleiben, ist der andere Weg wohl besser.

Das ist komplett falsch. Wenn innerhalb einer 68k-Emulation Parameter in 68k-Registern übergeben werden, können selbstverständlich 68k-Anwendungen den 68k-Libraries problemlos Werte in Registern übergeben.
Das ist der Normalfall für jede konventionelle Amiga-Libraryfunktion.
Will man 68k-Anwendung und ppc-Library zusammen verwenden, muß man sich ohnehin mit der Implementation der Emulation des jeweiligen OS auseinandersetzen, egal, ob hook oder direkter Funktionspointer.

Ein wesentlicher Punkt, den Du hier außer acht läßt, daß hooks im Gegensatz zu einfachen Funktionspointern die Aufrufkonvention genau definieren.
Einfache Funktionspointer müssen nicht zwischen verschiedenen Compilern kompatibel sein und sind es insbesondere auf dem Amiga nicht, haben somit als Parameter in einer shared Amiga-Library nichts zu suchen.
Nicht umsonst haben hook-Strukturen einen Platz für Compiler-spezifische stub-Funktionen.
Auf einem PPC-OS mit definiertem vom compiler direkt unterstütztem ABI sieht das zwar anders aus, aber hier geht es um die "classic" 68k-Libraries.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ Dieser Beitrag wurde von Holger am 18.04.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

18.04.2004, 19:58 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Mazze:
Zitat:
Original von cygnusEd:

>Kann ich in einer Library die C-Funktion "free" aufrufen?

Wenn Du den Speicher vorher mit malloc() (oder realloc()... ) angefordert hast - ja.


Ok. Ich bin nur deshalb etwas vorsichtig, weil es heißt, dass eine Library-Funktion kein "forbid" unterbrechen darf.

Library-Funktionen können normalerweise von verschiedenen Tasks gleichzeitig aufgerufen werden, weshalb die Finger von sämtlichen Compiler-Funktionen lassen sollte, die möglicherweise nicht dafür ausgelegt sind, im Zweifelsfall alle.
Die Speicherverwaltung gehört definitiv zu den problematischen Fällen. Wenn es um die Portierung von Software geht, die diese Funktionen nutzt, ist der beste Weg, einen header zu entwickeln, der die entsprechenden Funktionen auf sichere Amiga-spezifische umbiegt.
Man kann nicht vermeiden, daß Library-Funktionen andere Funktionen aufrufen, die u.U. ein forbid() unterbrechen. Am einfachsten ist es, die Dokumentation dahingehend zu erweitern, daß ein Programmierer diese Funktion bei laufendem forbid() nicht aufrufen darf.
Das entspricht sowieso der uralten Amiga-Konvention, daß ein forbid() nie länger als nötig dauern sollte.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

18.04.2004, 23:17 Uhr

Mazze
Posts: 263
Nutzer
Als Basis für die Library verwende ich CLIB-SDI. Der Linker meldet folgendes:

code:
5.Work:CProj/ggtl-amiga/src/sl> ed makefile.gcc
5.Work:CProj/ggtl-amiga/src/sl> make -f makefile.gcc
gcc -O2 -c -I ../include/C/ -D __NOLIBBASE__ -o libinitgcc.o libinit.c
gcc -O2 -c -I ../include/C/ -D __NOLIBBASE__ -o slgcc.o sl.c
gcc -noixemul -nostartfiles -s -o ../libs/sl.library libinitgcc.o slgcc.o
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(free.o)(.tex t+0x2a): undefined reference to 'SysBase'
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(free.o)(.tex t+0x46): undefined reference to 'SysBase'
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(free.o)(.tex t+0x52): undefined reference to 'SysBase'
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(malloc.o)(.t ext+0x18): undefined reference to 'SysBase'
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(malloc.o)(.t ext+0x4e): undefined reference to 'SysBase'
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(malloc.o)(.t ext+0x8a): more undefined references to 'SysBase' follow
collect2: ld returned 1 exit status


So sieht das Makefile aus:

code:
CFLAGS = -O2 -c -I ../include/C/ -D __NOLIBBASE__
LFLAGS = -noixemul -nostartfiles -s

DDIR = ../libs/# the directory, where destination library is stored

$(DDIR)sl.library: libinitgcc.o slgcc.o
	gcc $(LFLAGS) -o $@ libinitgcc.o slgcc.o

libinitgcc.o: libinfo.h libinit.c
	gcc $(CFLAGS) -o $@ libinit.c

slgcc.o: libinfo.h sl.c
	gcc $(CFLAGS) -o $@ sl.c


Ich verstehe das nicht. SysBase wird in libinit.c definiert. Da ich aufgrund Holgers's posting free und malloc durch AmigaOs-Funktionen ersetzen werde, löst sich das Problem wahrscheinlich so nebenbei. Trotzdem interessiert mich mal, was hier los ist.

[ Dieser Beitrag wurde von Mazze am 18.04.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

19.04.2004, 09:57 Uhr

Mazze
Posts: 263
Nutzer
Nach dem ich free durch FreeVec ersetzt hatte, bekam ich bei dieser Funktion den Fehler mit der fehlenden SysBase.
Der Fehler tritt nur auf, wenn ich die Funktionsadresse zuweise.
( z. B. func = FreeVec)
Beim normalen Aufruf klappt das. Ich habe deshalb die Library-Funktion so umgebaut, dass keine Zuweisung der Funktionsadresse stattfindet.

[ - Antworten - Zitieren - Direktlink - ]

19.04.2004, 11:05 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Mazze:
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(free.o)(.tex t+0x2a): undefined reference to 'SysBase'
/gg/lib/gcc-lib/m68k-amigaos/3.3/../../../libnix/libnix.a(malloc.o)(.t ext+0x18): undefined reference to 'SysBase'
[/code]
Da wird doch eindeutig noch free/malloc von libnix verwendet.
[code]
Ich verstehe das nicht. SysBase wird in libinit.c definiert.

Vieleicht als static. Der Linker kann aber kein globales SysBase finden.

[ - Antworten - Zitieren - Direktlink - ]

19.04.2004, 11:09 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Original von Mazze:
Nach dem ich free durch FreeVec ersetzt hatte, bekam ich bei dieser Funktion den Fehler mit der fehlenden SysBase. Der Fehler tritt nur auf, wenn ich die Funktionsadresse zuweise (z.B. func = FreeVec). Beim normalen Aufruf klappt das. Ich habe deshalb die Library-Funktion so umgebaut, dass keine Zuweisung der Funktionsadresse stattfindet.

Wenn Du die Funktionsadresse benutzt, dann verwendest Du den Stub aus libamiga.a. Alle dortigen Wrapper verwenden globale Librarybases (wie solls auch anders gehen?). Das Exec Symbol ist SysBase.

[ - Antworten - Zitieren - Direktlink - ]

22.04.2004, 19:31 Uhr

Mazze
Posts: 263
Nutzer
Hi,

im Moment sieht es so aus, dass alles bis auf eine Sortierfunktion funktioniert.
Um der Fehlerursache näher zu kommen: Was passiert, wenn sich eine Libraryfunktion rekursiv aufruft? Werden dann die Register gesichert oder muss ich mich selbst darum kümmern?

[ - Antworten - Zitieren - Direktlink - ]

23.04.2004, 16:41 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Mazze:
im Moment sieht es so aus, dass alles bis auf eine Sortierfunktion funktioniert.
Um der Fehlerursache näher zu kommen: Was passiert, wenn sich eine Libraryfunktion rekursiv aufruft?

Das klingt nacht Stack-overflow.
Zitat:
Werden dann die Register gesichert oder muss ich mich selbst darum kümmern?
Non-Scratch Register werden bei Funktionseintritt gesichert. Noch ein Hinweis: Library-funktionen (auch eigene!) sollten immer relativ zur Librarybasis aufgerufen werden.

[ - Antworten - Zitieren - Direktlink - ]

23.04.2004, 21:53 Uhr

cygnusEd
Posts: 104
Nutzer
@Holger

> Das ist komplett falsch. Wenn innerhalb einer 68k-Emulation Parameter in 68k-Registern übergeben werden, können
> selbstverständlich 68k-Anwendungen den 68k-Libraries problemlos Werte in Registern übergeben.
> Das ist der Normalfall für jede konventionelle Amiga-Libraryfunktion.
> Will man 68k-Anwendung und ppc-Library zusammen verwenden, muß man sich ohnehin mit der Implementation der Emulation
> des jeweiligen OS auseinandersetzen, egal, ob hook oder direkter Funktionspointer.

Da habe ich mich wohl etwas undeutlich ausgedrückt. In einer simulierten Umgebung funtioniert das natürlich auch auch
mit jedem anderen Prozessor. Aber das meinte ich nicht - direkt läuft's eben nicht.

> Ein wesentlicher Punkt, den Du hier außer acht läßt, daß hooks im Gegensatz zu einfachen Funktionspointern die
> Aufrufkonvention genau definieren.
> Einfache Funktionspointer müssen nicht zwischen verschiedenen Compilern kompatibel sein und sind es insbesondere auf dem
> Amiga nicht, haben somit als Parameter in einer shared Amiga-Library nichts zu suchen.
> Nicht umsonst haben hook-Strukturen einen Platz für Compiler-spezifische stub-Funktionen.
> Auf einem PPC-OS mit definiertem vom compiler direkt unterstütztem ABI sieht das zwar anders aus, aber hier geht es
> um die "classic" 68k-Libraries

Da hast Du allerdings recht. Das habe ich nicht zu Ende gedacht. Eine Funktion kann so nicht von Programmen aufgerufen
werden, die mit unterschiedlichen Compilern erzeugten wurden. Ist also eher was für Link-Libraries ;-)
Den PPC hatte ich auch nur erwähnt, um zu unterstreichen, daß Hooks nur für 68k-Amigas interessant sind.

> Library-Funktionen können normalerweise von verschiedenen Tasks gleichzeitig aufgerufen werden, weshalb die Finger von
> sämtlichen Compiler-Funktionen lassen sollte, die möglicherweise nicht dafür ausgelegt sind, im Zweifelsfall alle.
> Die Speicherverwaltung gehört definitiv zu den problematischen Fällen. Wenn es um die Portierung von Software geht, die
> diese Funktionen nutzt, ist der beste Weg, einen header zu entwickeln, der die entsprechenden Funktionen auf sichere
> Amiga-spezifische umbiegt.
> Man kann nicht vermeiden, daß Library-Funktionen andere Funktionen aufrufen, die u.U. ein forbid() unterbrechen. Am
> einfachsten ist es, die Dokumentation dahingehend zu erweitern, daß ein Programmierer diese Funktion bei laufendem
> forbid() nicht aufrufen darf.
> Das entspricht sowieso der uralten Amiga-Konvention, daß ein forbid() nie länger als nötig dauern sollte

Um 100%ig sicher zu sein, ist das wohl richtig.
Zwischen Forbid() und Permit() sollte man aber sowieso nur die einfachsten Funktionen ausführen. Außerdem muß man gelegendlich
auch beim Aufruf von Amiga-Shared-Lib-Funktionen vorsichtig sein, wie z.B. bei Wait(), WaitPort() etc. Die Problematik mit Forbid()
stand aber auch zuerst nicht zur Debatte.

MfG

[ - Antworten - Zitieren - Direktlink - ]

23.04.2004, 22:50 Uhr

Mazze
Posts: 263
Nutzer
Zitat:
Original von gni:
Zitat:
Mazze:
im Moment sieht es so aus, dass alles bis auf eine Sortierfunktion funktioniert.
Um der Fehlerursache näher zu kommen: Was passiert, wenn sich eine Libraryfunktion rekursiv aufruft?

Das klingt nach Stack-overflow.

Ich habe mich ungenau ausgedrückt. Die Funktion wird absichtlich rekursiv aufgerufen. Ich muss vermutlich non-scratch-Register verwenden.

Zitat:
Werden dann die Register gesichert oder muss ich mich selbst darum kümmern?
Non-Scratch Register werden bei Funktionseintritt gesichert. Noch ein Hinweis: Library-funktionen (auch eigene!) sollten immer relativ zur Librarybasis aufgerufen werden.
[/quote]

Bei den eigenen Funktionen kenne ich den Prototyp. Aber in den Protos der Systemlibraries taucht doch der Basepointer gar nicht auf?


Zum Thema Stack: Übernimmt eine Library den Stack des aufrufenden Programmes? Habe ich überhaupt eine Chance zu verhindern, dass eine Libraryfunktion die Stackgrenze überschreitet?

MFG
Matthias

[ - Antworten - Zitieren - Direktlink - ]

24.04.2004, 14:45 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Mazze:
Bei den eigenen Funktionen kenne ich den Prototyp. Aber in den Protos der Systemlibraries taucht doch der Basepointer gar nicht auf?

Bei den Systemlibraries mußt Du Dich auch nicht selbst darum kümmern. Das machen die stubs/inlines automatisch für Dich. Es ging wohl mehr um die Aufrufkonventionen für Deine eigene Library, wobei ich das nicht so pauschalisieren würde. Eine rekursive Funktion würde ich z.B. nicht jedesmal über den Library-Einsprung realisieren.
Zitat:
Zum Thema Stack: Übernimmt eine Library den Stack des aufrufenden Programmes? Habe ich überhaupt eine Chance zu verhindern, dass eine Libraryfunktion die Stackgrenze überschreitet?
Ja, Deine Funktion läuft mit dem Stack des aufrufenden Programms. Es gibt eine dokumentierte Mindestgröße (4096 für normale Programme, 1024 für bestimmte entsprechend dokumentierte Funktionen), die der Stack einer Anwendung haben muß, um die standard-Bibliotheken nutzen zu dürfen.
Wenn Deine Bibliothek davon abweicht, mußt Du das zumind. dokumentieren. Natürlich könnte Deine Bibliothek die Stackgröße des Aufrufers überprüfen, aber von einem solchen Overhead rate ich ab. Alternativ kann man natürlich für die Dauer eine Funktion einen neuen Stack erzeugen, das gehört aber schon in den Bereich sehr trickreicher Programmierung, die u.U. auf neuen Systemen Probleme macht.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

24.04.2004, 14:53 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von cygnusEd:
Den PPC hatte ich auch nur erwähnt, um zu unterstreichen, daß Hooks nur für 68k-Amigas interessant sind.

Uninteressant ist es für ppc auch nicht. Man muß nur wissen, daß, wenn man hooks in Library-APIs verwendet, die Software nicht mehr mit einem einfachen re-compile auf den ppc portiert werden kann.
Man muß sich dann direkt mit der Abwärtskompatibilität und 68k-Emulation auseinandersetzen und u.U. eine abweichende API in der PPC-Version anbieten.
Aber das sollte nicht dazu führen, daß man jetzt komplett auf callbacks verzichtet.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

27.04.2004, 08:46 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Mazze:
Zitat:
von gni:
Zitat:
Mazze:
Um der Fehlerursache näher zu kommen: Was passiert, wenn sich eine Libraryfunktion rekursiv aufruft?

Das klingt nach Stack-overflow.
Ich habe mich ungenau ausgedrückt. Die Funktion wird absichtlich rekursiv aufgerufen.
Das habe ich auch so verstanden. Und genau das verursacht auch den Stackoverflow. Library-Funktionen laufen immer im Context des Programmes, das die Library benutzt. Wenn das Programm "wenig" Stack hat, Du aber viel benötigst, gibts einen Crash. Entweder Du verlangst genügend Stack oder Du wechselst den Stack, wenn zuwenig da ist.
Zitat:
Zitat:
Library-funktionen (auch eigene!) sollten immer relativ zur Librarybasis aufgerufen werden.
Bei den eigenen Funktionen kenne ich den Prototyp. Aber in den Protos der Systemlibraries taucht doch der Basepointer gar nicht auf?
Library-Funktionen werden _immer_ relativ zur Librarybasis aufgerufen. Direkte Aufrufe sind nicht möglich. Der Prototyp in clib/ ist nicht der Name der "echten" Funktion im Quell-code sondern der des Einsprungs relativ zur Basis.

[ - Antworten - Zitieren - Direktlink - ]

27.04.2004, 11:25 Uhr

thomas
Posts: 7716
Nutzer
Zitat:
Library-Funktionen werden _immer_ relativ zur Librarybasis aufgerufen. Direkte Aufrufe sind nicht möglich. Der Prototyp in clib/ ist nicht der Name der "echten" Funktion im Quell-code sondern der des Einsprungs relativ zur Basis.

Das stimmt so nicht. Wenn du nur die clib/xyz_protos.h einbindest und die amiga.lib dazulinkst, hat jede OS-Funktion einen C-Stub, der ganz normal mit Stack-Parametern aufgerufen wird und auch eine absolute Adresse hat.

Nur wenn du die pragmas (bzw. inlines) mit einbindest, wird der Compiler die OS-Funktion direkt relativ zur Library-Base und mit Parametern in Registern aufrufen. Und dann hat die Funktion natürlich keine absolute Adresse mehr.

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

27.04.2004, 16:06 Uhr

obw
Posts: 94
Nutzer
Zitat:
Original von gni:
Das habe ich auch so verstanden. Und genau das verursacht auch den Stackoverflow. Library-Funktionen laufen immer im Context des Programmes, das die Library benutzt. Wenn das Programm "wenig" Stack hat, Du aber viel benötigst, gibts einen Crash. Entweder Du verlangst genügend Stack oder Du wechselst den Stack, wenn zuwenig da ist.


Interessante Frage: Wie stelle ich fest, ob zu wenig da ist? Spontan
würde ich sagen: StackSwap() auf Verdacht und dann stk_Pointer und stk_Lower vergleichen. Dann wieder zurückswappen. Kann man als Stack für die StackSwapStruct einfach beliebig allozierten Speicher verwenden (Alignment?)?

Zitat:
Library-Funktionen werden _immer_ relativ zur Librarybasis aufgerufen. Direkte Aufrufe sind nicht möglich. Der Prototyp in clib/ ist nicht der Name der "echten" Funktion im Quell-code sondern der des Einsprungs relativ zur Basis.

Wenn ich also eine Funktion habe, die sich z.B. rekursiv durch einen Baum arbeitet, mache ich das am besten wie? so?

code:
ULONG lib_func(ULONG foo)
{
  return do_func(ULONG foo);
}

static ULONG do_func(ULONG foo)
{
  [...]
  bar = do_func(bar);
  [...]
}


korrekt? Für lib_func() gibt es ein öffentliches Interface in den Includes. do_func() ist rein intern. Im anderen Fall müßte ich noch mit Registern jonglieren und das ganze ist nicht mehr trivial compiler-portabel.

OBW

[ - Antworten - Zitieren - Direktlink - ]

27.04.2004, 19:48 Uhr

Mazze
Posts: 263
Nutzer
Zitat:
Non-Scratch Register werden bei Funktionseintritt gesichert.

Angenommen, ich habe in einer Funktion eine Variable auf ein Scratch-Register gelegt. Wenn ich jetzt eine Betriebssystem-Funkion aufrufe, die ihre Parameter ebenfalls auf Scratch-Register leitet, dann wird doch aus einem Call-by-Value ein Call-by-Reference-Aufruf. Sehe ich das richtig? Die Betriebssystem-Funktion kann doch "hintenrum" den Registerwert veränderen. Wie kommt den der Kompiler bzw. Optimizer damit zurecht?

[ - Antworten - Zitieren - Direktlink - ]

27.04.2004, 20:43 Uhr

thomas
Posts: 7716
Nutzer

Das Scratch-Register muß nach dem Funktionsaufruf als verändert angesehen werden, da kann man keine Variable rein legen. Deshalb heißt es ja Scratch.

Assembler kennt kein "by-value" oder "by-reference". In Assembler gibt es nur globale Variablen, die von den Unterprogrammen verändert werden können. Daß bestimmte Register als Nicht-Scratch angesehen werden, ist eine Konvention, kein Gesetz.

Gruß Thomas
--
Email: thomas-rapp@web.de
Home: home.t-online.de/home/thomas-rapp/

[ - Antworten - Zitieren - Direktlink - ]

28.04.2004, 08:54 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Mazze:
Zitat:
Non-Scratch Register werden bei Funktionseintritt gesichert.
Angenommen, ich habe in einer Funktion eine Variable auf ein Scratch-Register gelegt.
Machst Du Assembler oder C? In C mußt Du Dich um so was nicht kümmern. Das erledigt der Compiler für Dich, weil er sich an ein ABI hält. Soll heißen, Parameter kannst Du in SCratch-registern übergeben, da der Compiler die Argumente bei Bedarf an einen "sicheren" Ort bringt.

[ Dieser Beitrag wurde von gni am 29.04.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

28.04.2004, 09:02 Uhr

gni
Posts: 1106
Nutzer
Zitat:
obw:
Zitat:
gni:
Das habe ich auch so verstanden. Und genau das verursacht auch den Stackoverflow. Library-Funktionen laufen immer im Context des Programmes, das die Library benutzt. Wenn das Programm "wenig" Stack hat, Du aber viel benötigst, gibts einen Crash. Entweder Du verlangst genügend Stack oder Du wechselst den Stack, wenn zuwenig da ist.

Interessante Frage: Wie stelle ich fest, ob zu wenig da ist? Spontan
würde ich sagen: StackSwap() auf Verdacht und dann stk_Pointer und stk_Lower vergleichen. Dann wieder zurückswappen. Kann man als Stack für die StackSwapStruct einfach beliebig allozierten Speicher verwenden (Alignment?)?

Normalerweise über die SP-Einträge in der Task-Struktur bzw. Einträge in der Process-Struktur wenn das Programm aus der Shell gestartet wird. Wurde der Stack bereits ausgetauscht ohne StackSwap(), dann bekommet man ein "falsches" Ergebnis". Bei getauschtem Stack eines Shell-programms würde man auch "falsche" Werte bekommen egal wie der Stack getauscht wurde. Solange das Ergebnis lautet "zu klein" geht alles glatt ;-) War der Stack groß genug, wird ja wohl niemand auf die Idee gekommen sein ihn zu tauschen. Was man eigentlich wissen will ist, ob noch genügend Platz ist.
Zitat:
Zitat:
Library-Funktionen werden _immer_ relativ zur Librarybasis aufgerufen. Direkte Aufrufe sind nicht möglich. Der Prototyp in clib/ ist nicht der Name der "echten" Funktion im Quell-code sondern der des Einsprungs relativ zur Basis.
Wenn ich also eine Funktion habe, die sich z.B. rekursiv durch einen Baum arbeitet, mache ich das am besten wie? so?
code:
ULONG lib_func(ULONG foo)
{
  return do_func(ULONG foo);
}

static ULONG do_func(ULONG foo)
{
  [...]
  bar = do_func(bar);
  [...]
}

korrekt?
Ja.
Zitat:
Für lib_func() gibt es ein öffentliches Interface in den Includes. do_func() ist rein intern.
Ich bezog mich auf die öffentliche Funktion, die muß immer relativ zur Basis aufgerufen werden. Was dann weiter intern passiert, ist Sache der Bibliothek.

[ - Antworten - Zitieren - Direktlink - ]

28.04.2004, 09:04 Uhr

gni
Posts: 1106
Nutzer
Zitat:
thomas:
Zitat:
Library-Funktionen werden _immer_ relativ zur Librarybasis aufgerufen. Direkte Aufrufe sind nicht möglich. Der Prototyp in clib/ ist nicht der Name der "echten" Funktion im Quell-code sondern der des Einsprungs relativ zur Basis.
Das stimmt so nicht. Wenn du nur die clib/xyz_protos.h einbindest und die amiga.lib dazulinkst, hat jede OS-Funktion einen C-Stub, der ganz normal mit Stack-Parametern aufgerufen wird und auch eine absolute Adresse hat.
Dennoch wird auch hier die Libraryfunktion relativ zur Basis aufgerufen und genau darauf kommt es an. Es ist völlig unerheblich, an welcher Stelle der relative Aufruf erfolgt. Hauptsache es wird so gemacht :-)

[ - Antworten - Zitieren - Direktlink - ]

28.04.2004, 19:51 Uhr

Mazze
Posts: 263
Nutzer
Zitat:
Machst Du Assembler oder C? In C mußt Du Dich um so was nicht kümmern. Das erledigt der Compiler für Dich, weil er sich an ein ABI hält. Soll heißen, Parameter kannst Du in SCratch-registern übergeben, da der Compiler die Argumente bei Bedarf an einen "sicheren" Ort bringt.

Ich programmiere in C und zwar gcc3.3 unter Amithlon/AOS3.9BB2.
Wenn ich in einem normalen C-Programm Registervariablen verwende, dann trifft es auf jeden Fall zu, dass die Registerinhalte an einen sicheren Ort gebracht werden. Aber was passiert, wenn ich eine Library-Funktion aufrufe? Weis der C-Kompiler, dass bestimmte Register (Scratch) "hinterrücks" von den Library-Funktionen verändert werden können?

Ich habe jetzt mal in der Library die Registerparameter a0 und a1 durch a3 und a5 ersetzt. Jetzt bekomme ich im Test-Programm einen Parse-Error. Als Ursache vermute ich folgendes Makro im Inline-Header:

code:
#define sl_map(root, func, data) \
	LP3A5(0x3c, APTR, sl_map, APTR, root, a2, struct Hook *, func, a3, APTR, data, d7, \
	, SL_BASE_NAME)


Hier fällt zunächst mal auf, dass der 3. Parameter statt auf a5 auf d7 liegt.

In meinem inline/macros.h ist kein LP3A5 definiert. Hier klappt offenbar das Zusammenspiel zwischen fd2pragma und gcc nicht.

Frage: gibt es einen Unterschied zwischen Adress- und Wert-Register? Kann ich eine Adresse an ein Wert-Register übergeben? Oder muss ich mich übergeben? :lach:

[ Dieser Beitrag wurde von Mazze am 28.04.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

29.04.2004, 13:09 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Mazze:
Zitat:
Machst Du Assembler oder C?
Ich programmiere in C und zwar gcc3.3 unter Amithlon/AOS3.9BB2.
Also C. In diesem Fall mußt Du Dir um Scratch-Register _keinen_ Kopf machen. Der Compiler kümmert sich um die Details. BTW, Du weisst, das GCC 3.3 unter Umständen bei Verwendung von LP-Inlines nicht-funktionierenden Code erzeugt? Das kann mit einem Update von inline/macros.h behoben werden, das aber noch nicht verfügbar ist :-(
Zitat:
Wenn ich in einem normalen C-Programm Registervariablen verwende, dann trifft es auf jeden Fall zu, dass die Registerinhalte an einen sicheren Ort gebracht werden.
Was ist für Dich eine Register-Variable? Eine lokale Variable mit "register" Zusatz? Oder redest Du von Parameterübergabe in Registern?
Zitat:
Aber was passiert, wenn ich eine Library-Funktion aufrufe? Weis der C-Kompiler, dass bestimmte Register (Scratch) "hinterrücks" von den Library-Funktionen verändert werden können?
Alle Libraries müssen AmigaOS-ABI konform sein, soll heissen alle non-scratch Register _müssen_ nach dem Funktionsaufruf den selben Wert wie _vor_ dem Funktionsaufruf haben. Scratch-Register _können_andere Werte haben, aber sie _müssen_ nicht. Wenn eine Funktion vom allgemeinen Schema abweicht, ist das meist dokumentiert (zb. Forbid/Permit, etc.) aber das ist nur für Assembler wirklich interessant. Für den Compiler ist der OS-Funktionsaufruf wie jeder andere, dh. er erwartet das "Standardverhalten".
Zitat:
Ich habe jetzt mal in der Library die Registerparameter a0 und a1 durch a3 und a5 ersetzt.
a4/a5[/a6/a7 ;-)] vermeiden. a4 und a5 werden vom Compiler verwendet. a0 und a1 sind vollkommen korrekt.
Zitat:
Jetzt bekomme ich im Test-Programm einen Parse-Error. Als Ursache vermute ich folgendes Makro im Inline-Header:
code:
#define sl_map(root, func, data) \
	LP3A5(0x3c, APTR, sl_map, APTR, root, a2, struct Hook *, func, a3, APTR, data, d7, \
	, SL_BASE_NAME)

Hier fällt zunächst mal auf, dass der 3. Parameter statt auf a5 auf d7 liegt.
und das Maktro heisst LP3_A5_. A5 kann nicht ohne weiteres als Argumentregister verwendet werden. Deshalb wird das Argument erst nach d7 (hoffentlich ist das frei ;-) gepackt und danach nach A5. Das wird vom speziellen LP Makro erledigt.
Zitat:
In meinem inline/macros.h ist kein LP3A5 definiert. Hier klappt offenbar das Zusammenspiel zwischen fd2pragma und gcc nicht.
inline/macros.h enthält nur die Makros., die von OS-Funktionen verwendet werden. Wenn eine 3rd-Party Library eine Kombination verwendet, die eine System-Libraries nicht hat, dann fehlt das Makro.
Du solltest Dir für Deine Library ein Inline erzeugen, die die LP Makros "direkt" verwendet (ohne Einbindung von inlines/macros.h).
Zitat:
Frage: gibt es einen Unterschied zwischen Adress- und Wert-Register? Kann ich eine Adresse an ein Wert-Register übergeben? Oder muss ich mich übergeben? :lach:
Die Frage verstehe ich nicht.

[ Dieser Beitrag wurde von gni am 29.04.2004 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

29.04.2004, 23:54 Uhr

Mazze
Posts: 263
Nutzer
Zitat:
Also C. In diesem Fall mußt Du Dir um Scratch-Register _keinen_ Kopf machen. Der Compiler kümmert sich um die Details.

Gut

Zitat:
BTW, Du weisst, das GCC 3.3 unter Umständen bei Verwendung von LP-Inlines nicht-funktionierenden Code erzeugt?

Habe ich nicht gewusst. Allerdings muss ich ein #define setzen, wenn ich ReAction-GUIs erstelle. Dies hat möglicherweise etwas mit den LP-Makros zu tun.

Zitat:
Alle Libraries müssen AmigaOS-ABI konform sein, soll heissen alle non-scratch Register _müssen_ nach dem Funktionsaufruf den selben Wert wie _vor_ dem Funktionsaufruf haben. Scratch-Register _können_andere Werte haben, aber sie _müssen_ nicht. Wenn eine Funktion vom allgemeinen Schema abweicht, ist das meist dokumentiert (zb. Forbid/Permit, etc.) aber das ist nur für Assembler wirklich interessant. Für den Compiler ist der OS-Funktionsaufruf wie jeder andere, dh. er erwartet das "Standardverhalten".

a4/a5[/a6/a7 ;-)] vermeiden. a4 und a5 werden vom Compiler verwendet. a0 und a1 sind vollkommen korrekt.


OK

Zitat:
inline/macros.h enthält nur die Makros., die von OS-Funktionen verwendet werden. Wenn eine 3rd-Party Library eine Kombination verwendet, die eine System-Libraries nicht hat, dann fehlt das Makro.
Du solltest Dir für Deine Library ein Inline erzeugen, die die LP Makros "direkt" verwendet (ohne Einbindung von inlines/macros.h).


OK

Zitat:
Zitat:
Frage: gibt es einen Unterschied zwischen Adress- und Wert-Register? Kann ich eine Adresse an ein Wert-Register übergeben?
Die Frage verstehe ich nicht.
Eine C-Funktion mit einem Pointer als Argument:
Bsp: void test(void *p)
würde ich in einer Library mit den Makros aus Clib-SDI folgendermaßen deklarieren
ASM(VOID) LIBtest (REG(a0, APTR p))
Kann ich a0 durch d0-7 ersetzen?

Leute, ich stelle das Thema "Library erzeugen" erstmal zurück und binde stattdessen den C-Code direkt ein. Wahrscheinlich habe ich einen Fehler gemacht, den ich erst finde, wenn ich mit etwas zeitlichem Abstand noch mal von vorne anfange.

[ - Antworten - Zitieren - Direktlink - ]

30.04.2004, 12:54 Uhr

gni
Posts: 1106
Nutzer
Zitat:
Mazze:
Zitat:
BTW, Du weisst, das GCC 3.3 unter Umständen bei Verwendung von LP-Inlines nicht-funktionierenden Code erzeugt?
Habe ich nicht gewusst. Allerdings muss ich ein #define setzen, wenn ich ReAction-GUIs erstelle. Dies hat möglicherweise etwas mit den LP-Makros zu tun.
Das ReAction-Define hat wohl nichts mit der GCC3+LP Makro Problematik zu tun.
Zitat:
Eine C-Funktion mit einem Pointer als Argument:
Bsp: void test(void *p)
würde ich in einer Library mit den Makros aus Clib-SDI folgendermaßen deklarieren
ASM(VOID) LIBtest (REG(a0, APTR p))
Kann ich a0 durch d0-7 ersetzen?

Ja. Manchmal ist es natürlich von Vorteil, wenn man Zeiger in Adressregistern übergibt. Da spart man sich u.U. ein "move". BTW, Ergebnisse werden unter AmigaOS/68k immer über _D0_ geliefert. Auch Zeiger ;-)
Zitat:
Leute, ich stelle das Thema "Library erzeugen" erstmal zurück und binde stattdessen den C-Code direkt ein. Wahrscheinlich habe ich einen Fehler gemacht, den ich erst finde, wenn ich mit etwas zeitlichem Abstand noch mal von vorne anfange.
Ich weiss nicht wie Du es gemacht hast, aber ich würde wohl Wrapper für die Original-Funktionen schreiben, da man dann die Originalquellen nicht ändern muß. Das macht die Bibliothek leider etwas langsamer, ist aber viel besser wartbar.

[ - Antworten - Zitieren - Direktlink - ]

08.05.2004, 15:48 Uhr

Mazze
Posts: 263
Nutzer
Ich habe die GGTL* auf den Amiga portiert. Mittlerweile sehe ich keinen großen Sinn mehr darin, eine Runtime-Library zu erzeugen. Ich binde einfach den C-Source eine und erspare mir dadurch den Stress mit Registern, Hooks und Wrappern für Standard-C-Funktionen.

Falls sich mal jemand meinen Versuch, eine Runtime-Library zu erzeugen, anschauen will:
Download
Es ist das Programm test-mergesort, das Fehler meldet.

* Generic Game Tree Library. (Library zum Erzeugen von "intelligenten" Spielen wie Othello, Dame, Schach etc.)
GGTL Amiga Port
Original Linux-Version
Es wird wohl noch ein paar Tage dauern, bis es im Aminet erscheint.

[ - Antworten - Zitieren - Direktlink - ]


-1- [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Library erzeugen [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.