:Program. Bin2Obj :Author. Volker Rudolph :Address. Medicusstr. 31 / 6750 Kaiserslautern :Phone. 0631/17160 :ShortCut. [vor] :Version. 1.2 :Date. 1.7.1989 :Copyright. PD :Language. Modula-II :Translator. M2Amiga 3.2d :Imports. Printf [vor] :Remark. Nur CLI ! :Usage. Bin2Obj inputfile [outputfile] Bin2Obj entfernt die Hunk-Informationen aus einem ausführbaren Programm und schreibt die Daten des ersten CODE-Hunks nach . Frage: Wozu braucht man so etwas ? Antwort: Um in Assembler geschriebene Implementation-Module verwenden zu können. Um in Assembler geschriebene Prozeduren in Modula-2 zu verwenden, gibt es zwei Möglichkeiten. Die erste ist, die einzelnen Prozeduren zu assemblieren, in INLINE-Befehle umzuwandeln, in den Module-Quelltext zu kopieren und dann das Modula-Programm zu kompilieren und zu linken. Diese Methode ist, durch die vielen Schritte bis zum fertigen Programm, sehr aufwendig und umständlich. Die andere Methode möchte ich etwas näher beschreiben, weil man etwas Know-How dazu braucht, sie aber gegenüber der anderen Methode einige Vorteile hat: Die Programmentwicklung ist bequemer und die fertigen Module sind kürzer. Man benötigt folgende Programme: DisObject (BerndPreusing, PD) Einen Assembler (ich verwende Asm68k V1.1.0 (PD)) Einen Linker für den Assembler (ich verwende Blink V6.7 (PD)) Bin2Obj Ich möchte die Entstehung eines Moduls an einem kleinen Beispielmodul zeigen, das nur eine Prozedur exportiert: Sie testet ob eine Zahl eine Primzahl ist. 1. Man schreibt die Definition- und Implementation-Module in Modula, läßt aber im Implementation-Modul die Routinen fort, die man in Assembler schreiben will. Dabei ist es sinnvoll Parameter, die an Prozeduren übergeben werden, in Registern zu übergeben, da man sich dann weder die Parameter auf dem Stack zusammensuchen, noch den Stack aufräumen muß. Libraries oder Module die man vom Assembler- Teil aufrufen möchte, sollten importiert werden, so daß man die Basisadressen der Module herankommt (z.B. IntuitionBase). DEFINITION MODULE Prim; PROCEDURE Prim(n{0}:CARDINAL):BOOLEAN END Prim. IMPLEMENTATION MODULE Prim; PROCEDURE Prim(n{0}:CARDINAL):BOOLEAN; END Prim; END Prim. 2. Man kompiliert die Definition- und Implementation-Module. >m2c Prim.def Prim 3. Mit dem Programm DisObject wandelt man das entstandene Object-File in Assembler-Quelltext um. Allerdings erzeugt die ursprüngliche DisObject-Version Quelltext, der nur vom Profimat assembliert werden kann. Da ich diesen Assembler nicht besitze (und auch nicht besitzen möchte), verwende ich eine leicht modifizierte Version von DisObject, deren Quelltext von allen, mir bekannten Assemblern, verwendet werden kann. >DisObject >Prim.asm Prim.obj Dabei ensteht die folgende Datei namens Prim.asm (ich habe sie noch mit einigen Kommentaren versehen). ; M2Amiga Object-File Disassembler V 2.1 © Bernd Preusing 1988 ; Standard-Assembler-Version 1989 by Volker Rudolph ; Disassembly of Prim.obj SECTION Module,CODE DC.L 1 ; Kennung: .obj-File DC.W 1 ; mod DC.B 'Prim' DS.B 28 DC.W $108A,$006F,$08BC ; Das ist die Modul-ID anhand der die ; Versionskontrolle sym<->obj durchge- ; führt wird. Falls das Definition- ; Modul neu kompiliert wird, muß man ; an dieser Stelle die Modul-ID des ; neuen sym-Files eintragen. ; CodeSize DC.L ENDE-Prog ; VarSize DC.L 2 ; ConstSize DC.L Jumps-Consts ; Jumps DC.L 2 ; Modules DC.L 4 Consts: ; keine Konstanten Jumps: ; Sprungtabelle: für jede exportierte ; Prozedur gibt es einen Eintrag. Der ; letzte Eintrag ist für den Initiali- ; sierungs-Block des Moduls. DC.W $4EF9 ; jmp DC.L Proc001-204 ; Proc1 = Prim DC.W $4EF9 ; jmp DC.L Proc000-204 ; Proc0 = Modul-Initialisierung ModuleIds: ; Importierte Module DC.W 1 ; mod DC.B 'Arts' DS.B 28 DC.W $0F97,$04DA,$0974 DC.W 0 ; none DS.B 32 DC.W $0000,$0000,$0000 DC.W 0 ; none DS.B 32 DC.W $0000,$0000,$0000 DC.W 0 ; none DS.B 32 DC.W $0000,$0000,$0000 Prog: dataPtr EQU Prog-20 ; Zeiger auf globale Variablen. ; Basepointer der importierten Module: ArtsBs_ EQU Prog-16 ; Arts-Basepointer Proc000: BRA L000002 ; Sprung zur Modul-Initialisierung Proc001: ; Prozedur Prim MOVE.L A4,-(A7) ; Das ist der Standard-Code, der vom MOVEA.L dataPtr(PC),A4 ; Modula-Compiler für jede Prozedur MOVE.L A5,-(A7) ; erzeugt wird. Man kann ihn i.A. MOVEA.L A7,A5 ; löschen. MOVEQ #2,D0 ; MOVEA.L ArtsBs_(PC),A6 ; JSR -24(A6) ; UNLK A5 ; MOVEA.L (A7)+,A4 ; RTS L000002: ; Modul-Initialisierung MOVE.L A4,-(A7) MOVEA.L dataPtr(PC),A4 MOVE.L A5,-(A7) MOVEA.L A7,A5 BSET #0,-2(A4) ; Ist dieses Modul schon initialisiert ; worden ? BNE L000003 ; ja: Sprung zum Ende MOVEA.L ArtsBs_(PC),A6 ; Arts initialisieren JSR -6(A6) ; Keine eigenen Initialisierungem L000003: UNLK A5 MOVEA.L (A7)+,A4 RTS ENDE: END 4. Im nächsten Schritt ersetzt man die leere Prim-Funktion, durch das entsprechende Assembler-Programm (außerdem habe ich noch ein paar Optimierungen vorgenommen). ACHTUNG: Da M2Amiga-Module NICHT reloziert werden, darf man nur positionsunabhängige Programme schreiben (pc-relative Adressierung) ! ; M2Amiga Object-File Disassembler V 2.1 © Bernd Preusing 1988 ; Standard-Assembler-Version 1989 by Volker Rudolph ; Disassembly of obj/Prim.obj SECTION Module,CODE DC.L 1 ; Kennung: .obj-File DC.W 1 ; mod DC.B 'Prim' DS.B 28 DC.W $108A,$00BE,$026B ; Das ist die Modul-ID anhand der die ; Versionskontrolle sym<->obj durchge- ; führt wird. Falls das Definition- ; Modul neu kompiliert wird, muß man ; an dieser Stelle die Modul-ID des ; neuen sym-Files eintragen. ; CodeSize DC.L ENDE-Prog ; VarSize DC.L 2 ; ConstSize DC.L Jumps-Consts ; Jumps DC.L 2 ; Modules DC.L 4 Consts: Jumps: ; Sprungtabelle: für jede exportierte ; Prozedur gibt es einen Eintrag. Der ; letzte Eintrag ist für den Initiali- ; sierungs-Block des Moduls. DC.W $4EF9 ; jmp DC.L Proc001-204 ; Proc1 = Prim DC.W $4EF9 ; jmp DC.L Proc000-204 ; Proc0 = Modul-Initialisierung ModuleIds: ; Importierte Module DC.W 1 ; mod DC.B 'Arts' DS.B 28 DC.W $0F97,$04DA,$0974 DC.W 0 ; none DS.B 32 DC.W $0000,$0000,$0000 DC.W 0 ; none DS.B 32 DC.W $0000,$0000,$0000 DC.W 0 ; none DS.B 32 DC.W $0000,$0000,$0000 Prog: dataPtr EQU Prog-20 ; Zeiger auf globale Variablen ; Basepointer der importierten Module ArtsBs_ EQU Prog-16 ; Arts-Basepointer Proc000: BRA L000002 ; Sprung zur Modul-Initialisierung Proc001: ; Prozedur Prim cmp.w #2,d0 blt.s notPrim cmp.w #4,d0 blt.s isPrim move.w d0,d1 lsr.w #1,d1 loop: moveq #0,d2 move.w d0,d2 divu d1,d2 swap d2 tst.w d2 beq.s notPrim subq.w #1,d1 cmp.w #1,d1 bgt.s loop isPrim: moveq #-1,d0 bra.s exit notPrim:moveq #0,d0 exit: rts L000002: ; Die Modul-Initialisierung kann bei ; diesem Modul entfallen. Arts wird ; bereits vom Haupt-Modul intialisiert RTS ENDE: END 5. Nun muß man das fertige Programm noch assemblieren, linken und in ein M2Amiga-Objectfile umwandeln. >asm68k Prim.asm >blink prim.o to T:prim >Bin2Obj T:prim prim.obj 6. Nun hat man das fertige Objectfile vorliegen und kann es in eigenen Programmen wie ein normales Modul verwenden. Wenn man den Assembler-Quelltext ändert, muß man nur noch Schritt 5 wiederholen. Ich hoffe, daß ich durch dieses kurze Beispiel auch andere Leute dazu anrege, kleine und praktische Module in Assembler zu schreiben. Es wäre z.B. eine gute Sache, nach und nach alle M2Amiga-Standardmodule in Assembler neu zu schreiben, denn das würde die fertigen Modula- Programme stark verkürzen. Insbesondere Arts in ein guter Kandidat dafür. Ich finde es katastrophal, daß man ein Laufzeitsystem, das zu jedem Programm dazugelinkt wird, in einer Hochsprache schreibt. Also: WER SCHREIBT ARTS NEU ???