MaxLibs

Kommentare anzeigen Worklog abonnieren

Worklogs MaxLibs

Opcode "E8"

Donnerstag, 3. Februar 2011 von Lord Stweccys
Erfreuliche Eilmeldung!

Nach frustrierten Stunden habe ich es nun geschafft ganz alleine durch BlitzMax
einen OpCode zu generieren, der den CALL NEAR PTR herstellt.
Zuerst steht natürlich das Erkennungszeichen "E8" (232) da und danach kommt eine 32 signed Int- Zahl,
die zeigt, wie relativ die Position der Funktion zur jetzigen steht.

BlitzMax: [AUSKLAPPEN]
Int(Byte Ptr(MilliSecs))-4-Int(maxlib.mem)-pos


(Das -4 ist vermutlich für die Kompensierung des stehenden Opcodes zuständig, genau
weiß ich das nicht, bin auf die Zahl durch Berechnungen gestoßen)


Zugegeben. Das war nicht sooo schwer.

Ich habe mir eine stinknormale Funktion gebaut, die Millisecs aufruft und mir an geschaut, nach
welchem Muster die sInt-Zahl hinter E8 jeweils aufgebaut ist und das kann ich jetzt auch.

D.h. man muss nicht mehr den Umweg über das EAX-Register gehen, sondern die normalen CALLs
werden von MaxLibs in Echtzeit durch die NEAR PTR CALLs ausgetauscht.



Noch sind externe Funktionen allerdings nicht abgeschlossen, ich habe bis jetzt nur MilliSecs
eingebaut, ich denke ich werde alle normalen BlitzMax-Funktionen einbauen (BRL.Blitz) und den Code
noch etwas verbessern.

Mfg,
LordSt

Extern über Umwege

Mittwoch, 2. Februar 2011 von Lord Stweccys
Tja, so ist das wohl:

Ich bin im Moment krank und mir ist langweilig...

Nach vielem Hin und Her habe ich es jetzt endlich geschafft die externe Funktion "MilliSecs()" von einer MaxLib aufrufen zu lassen und das war Schwerstarbeit Shocked !

Für diese Kleinigkeit habe ich exakt 2 Wochen gebraucht und arbeite jeden Tag an MaxLibs!


...und ein endgültiger Erfolg ist das immernoch nicht: Bisher geht das ganze noch nicht über
den direkten Weg:

BlitzMax: [AUSKLAPPEN]
MilliSecs()


Das geht noch nicht. Stattdessen...

BlitzMax: [AUSKLAPPEN]
Local a:Int()=Byte Ptr(MilliSecs)
a()


(So kann man generell jede Funktion aufrufen, es ist nur etwas dämlich Smile )


Warum muss ich das machen? Weil mir jetzt etwas, was ich mal toll fand zum Verhängnis wird:

Das CALL, das für den Aufruf einer externen Funktion verwendet wird ist das CALL NEAR PTR.
Jetzt habe ich natürlich versucht, dass mein Programm CALL findet und durch dieses spezielle CALL
ersetzt, aber nein, aber nein. Ich schreibe es ausdrücklich hin und FASM macht wieder ein CALL SHORT
draus. Nichts zu machen...
...Vorerst!

Mfg,
LordSt

section data

Mittwoch, 19. Januar 2011 von Lord Stweccys
Halli hallo.

Eigentlich wollte ich schon früher hier weiterschreiben, aber solche assemblernahen Geschichten sind immer
wieder fehleranfällig, was die Produktion zurückwirft Sad

Bis jetzt konnten ja noch keine Variablen verwendet werden (für lokale Funktionsvariablen werden von BMX
die Register verwendet), die "data" Sektion blieb also bei mir leer...
...bis letztens!

Kurze Zusammenfassung für "Kurzleser":

-Globals in Funktionen nun möglich
-TMaxLib extends TStream
-Footer
-Suche dringend Tester! (PN an mich)



Jaja, letztens wurde die Sektion "data" eingeführt, allerdings mit einer kleinen Änderung:
Jeder Vorkommen von 'align' wird entfernt. Wieso? Align sorgt dafür, dass auf die Data-Sektion schneller
zugegriffen werden kann. Wie es das macht, ist jetzt nicht wichtig, allerdings wird dadurch der Code
entscheidend verändert und meine Algos streiken Sad


Die Struktur meiner MaxLib wurde verändert und zwar steht direkt nach der MagicNumber "BLIB" die Adresse
auf einen Footer. Dieser Footer wiederum ist der Anfang einer Liste, welche alle Adressen auflistet, die
vor dem Ausführen angepasst werden müssen. Wieso das ganze? Nun ja: Z.b Globals (in Funktionen)
werden wie "echte" Variablen (okay, der Begriff 'Variable' ist in Assembler nicht grade gut, ach was solls) behandelt.
Was war denn mit If und so?, das ging doch auch! Stimmt. Für If-Abfragen werden auch Labels verwendet,
allerdings werden diese relativ gespeichert und 'MOV eax,variable' wird eben absolut gesepichert.
Mein selbst entwickelter Algo *stolz* spürte genau diese absoluten Labels auf und listet ihr vorkommen
ab dem Footer in die MaxLib. Jetzt wird einfach an jede Adresse die Startadresse der MaxLib addiert und
es kommt zu keinen Komplikationen mehr.

So sieht das Format jetzt aus: (Die [] stehen NICHT für Pointer)

Code: [AUSKLAPPEN]
db "BLIB"
dd 0 ;Platzhalter für Footer

db [AnzahlDerFunktionen-1]

db [Funktionsnamenlänge]
dd [Funktionsname]
...

[Funktionscode]

section "data"

[Datacode]

[Footer]
[Liste aller zu ändernden Adressen]


Um die Änderung der Adressen zu verwirklichen muss natürlich in den Code geschrieben werde
und was eignet sich da besser als ein TStream?
(Alle Ansätze ohne TStream haben nicht funktioniert, danke BRL für diesen Type Very Happy)

Tmaxlib wird neuerdings extendiert von TStream, dadurch ist ein besserer Zugriff möglich.
Für den Verwender dieser Bibliothek bringt das alleridings herzlich wenig. Very Happy

So das wars eigentlich auch schon.

Ach! Beinahe hätte ichs vergessen: Ich suche dringend Tester für mein Projekt, denn ich muss
ja wissen ob das alles praktisch auch auf verschiedenen System läuft. Einfach PN an mich, falls Interesse
besteht ;D

bmx2lib

Dienstag, 11. Januar 2011 von Lord Stweccys
Mit einem fröhlichen "Moin moin" begrüße ich euch heute zu meinem zweiten Eintrag.

-Warum hast du gestern nichts geschrieben?
-Tja, gestern war Ferienende in Bayern (argh!) und außerdem habe ich an einer essentiellen Sache
für mein Projekt gearbeitet, die etwas länger gedauert hat und die ich euch natürlich heute vorstelle Very Happy

Also was hat sich denn jetzt getan?

Nun, an der eigentlichen Interpretation hat sich noch nichts geändert, die externen Symbole, die man z.B.
für Arrays brauchen wird, da Arrays (man glaubt es nicht) nichts natives sind, sondern BlitzMax da seinen
eigenen Befehlssatz mitbringt (den ich natürlich noch mit Symbolen versehen werde, aber erst später Smile ),
werden erst später implementiert.

Was ich heute und gestern geschrieben habe ist der (s.Überschrift) Blitzmax -> MaxLib Konverter

Das ist kein eigenständiges Programm, sondern wird ganz einfach in den Code eingefügt:

BlitzMax: [AUSKLAPPEN]
Import "bmx2lib.bmx"   'später vermutlich sowas, wie "Import lordst.bmx2lib" XD


Man definiert seine Funktionen wie gewohnt, mit einer kleinen, aber feinen Änderung:

Das Hauptprogramm bleibt komplett leer, bis auf eine winzige, aber entscheidende Befehlszeile:

BlitzMax: [AUSKLAPPEN]
bmx2lib()



Dieser Befehl ortet die Assemblerdateien, die BlitzMax schreibt, wenn es ein Programm kompiliert
und liest diese ein (daran habe ich gestern gesessen).
Danach liest er alle wichtigen Daten aus der Datei für die spätere MaxLib.

So sah mein Code aus:
BlitzMax: [AUSKLAPPEN]
Import "bmx2lib.bmx"

bmx2lib()

Function TestFunktion()
Return 42
End Function


Nachdem ich kompiliert habe schaue ich erwartungsvoll in meinen Projektordner und stelle erfreut fest,
dass alles geklappt hat Very Happy

Jetzt muss ich die MaxLib nur noch aufrufen:
BlitzMax: [AUSKLAPPEN]
Local test:TMaxlib=LoadMaxLib("testlib.lib")
Global TestFunktion:Int()=GetSymbolAddress(test,"TestFunktion")
Print TestFunktion()


Und, hurra, Print schreibt '42' in mein IDE. Very Happy


Danke fürs Lesen,
Mfg,
LordSt

Kleine Erfolge

Sonntag, 9. Januar 2011 von Lord Stweccys
Hallo und herzlich willkommen zu meinem zweiten Worklog (der erste ist ziemlich verstaubt...)!

Manche haben es vielleicht schon hier gelesen: Ich versuche mich gerade daran dynamische Bibliotheken in BlitzMax zu verwirklichen.
(Kurzerhand habe ich das ganze MaxLibs genannt, wollte es zuerst Maxdul nennen, aber das ist irgendwie komisch auszusprechen Smile )

Das Prinzip ist einfach: Man lädt Code (vorher auf der Festplatte abgespeichert) in der/die/das RAM, zieht den Pointer auf eine Funktion und führt diese aus.

Nunja, das klingt ziemlich einfach, aber auch hier gibt es Hürden, z.B., dass FASM einfach nicht kapieren will, das mir die Pointer im Header als Byte nur Nachteile bringen. Sad


Es stehen schon ein paar kleine Befehle (2 um genau zu sein):

Arrow LoadMaxLib:TMaxLib(Dateiname)
Arrow GetSymbolAddress:Byte ptr(MaxLib,Symbolsname)


Den ersten verwendet man, ganz klar, um die MaxLib in den Speicher zu laden.
Den zweiten kann man verwenden um zuvor definierte Symbole als Pointer zu bekommen, das müssen nicht Funktionen sein, Variablen gehen theoretisch auch. (Noch nicht, aber später vielleicht)

Als Test habe ich mir eine kleine Bibliothek "Code.lib" geschrieben, allerdings noch nicht in BlitzMax, sondern erstmal in Assembler, denn die Konvertierung kommt erst später dran.

So sieht der Code der Bibliothek aus:

Code: [AUSKLAPPEN]
use32

db "BLIB"
db 0
db 8,"Funktion",_Funktion
_Funktion:
mov eax,42
ret


Hier kommt die Erklärung:

use32 sagt erstmal, dass das ganze für ein x86-System kompiliert werden soll
db "BLIB" - das ist die MagicNumber die am Anfang einer jeden MaxLib stehen muss
db 0 signalisiert, dass es genau eine Funktion gibt, mit
db 8, (also 8 Zeichen) "Funktion", welche auf den Zeiger _Funktion verweist.
Diese Funktion besteht eigentlich nur daraus, dass die Zahl 42 returned wird.

Mein BlitzMax-Code sieht so aus:

BlitzMax: [AUSKLAPPEN]
Local test:TMaxlib=LoadMaxLib("code.bin")
Local func:Int()=GetSymbolAddress(test,"Funktion")
Print func()


Da bin ich schon ein wenig stolz, denn Print gibt tatsächlich "42" aus.


Danke fürs Lesen, ich denke weitere Einträge werden noch folgen und ich hoffe MaxLibs wird ein erfolgreiches Modul Very Happy

Mfg,
LordSt