Reihenfolge von Programmteilen beachten

Eine sehr wichtige Rolle spielt gerade bei 8086-Assemblerprogrammen die Reihenfolge, in der einzelne Programmteile angeordnet sind.

Jeder, der schon irgendwann einmal beim Übersetzen eines Assemblerprogrammes die Fehlermeldung »relative jump out of range« (zu große Distanz eines relativen Sprungs) erhalten hat, kennt das Dilemma. Denn der 8086 verfügt zwar über unzählige bedingte Sprungbefehle; kein einziger davon schafft es aber, eine größere Distanz als +/- 128 Bytes zu überwinden, weil bei der Codierung dieser Befehle nur ein Byte für die Angabe des Sprungzieles vorgesehen ist. Eines der größten Versäumnisse der Entwickler der so verbreiteten INTEL-80×86-Familie, mit dem sich jeder Assemblerprogrammierer herumzuschlagen hat. Abhilfe schafft in solchen Fällen das Erzeugen eines größeren Sprungbefehls durch Umkehrung der Bedingung. Aus der Anweisung »JNE $+100h« wird so die Speicherplatz- und Quelltext-freßende Befehlsfolge:

JE L1      ;Umgekehrte Bedingung: Weiten Sprung übergehen
JMP $+100h ;Jetzt kommt der Sprung
L1:        ;hier geht's weiter

In vielen Fällen läßt sich dies jedoch umgehen, indem man die einzelnen Bestandteile des Programmes dermaßen umsortiert, daß sich der Abstand des Zieles auf weniger als 128 Bytes verringert. Die richtige Reihenfolge zu finden kann oft auch sehr zeitaufwendig oder gar unmöglich sein, weil sich durch jede Änderung an anderer Stelle erneut solche übergroßen Sprungdistanzen ergeben können.

Die richtige Reihenfolge der einzelnen Module spielt jedoch nicht nur aus diesem Grunde eine Rolle. Durch einige Tricks läßt sich zudem so manches an Quelltext einsparen. So läßt sich eine Folge von Anweisungen wie

CALL 12D
RET

durch die eine Zeile »JMP 12D« ersetzen, sofern der »RET« nicht gerade ein Sprungziel ist. Das bewirkt, daß die Return-Anweisung des aufgerufenen Unterprogramms ab Adresse 12D die Return-Anweisung des obigen Programmausschnittes ersetzt — eine Ersparnis von einer Zeile und 2 Byte. Ist es außerdem noch möglich, die Module in eine solche Reihenfolge zu bringen, daß das Unterprogramm unmittelbar im Anschluß an den Abschnitt folgt, dann kann sogar noch die Sprunganweisung entfallen — ein »JMP $+0« bewirkt schließlich nichts, außer einer Zeitverzögerung. Durch die Einbeziehung der RET-Anweisung zur Programmbeendigung in diese Überlegungen ergeben sich oft verblüffende Algorithmen zur Lösung eines Problems. Die Befehlsfolge ab Offset 125h in unserem oben abgedruckten Demonstrationsprogramm, die den Speicher des bereits geladenen Programmes wieder freigibt, läßt sich zum Beispiel auch so formulieren:

CALL 12D        ;125  das residente Programm freigeben
ES:MOV ES,[2C]  ;128  das Environment freigeben
MOV AH,49       ;12D  Unterprogramm zum Freigeben von Speicher
INT 21          ;12F
RET             ;131  Ende

Quelle: 200 Utilities für PC-/MS-DOS von Gerhard Schild und Thomas Jannot

💡 Sie haben einen Linkedin-Account? Dann können Sie meinen Newsletter „Der 18-Jährige, der einen Zettel schrieb und verschwand“ abonnieren ✔︎ 

Matomo