Entwickler-Dokumentation |
|
Assembler-Projekt 1.31 - Gruppe 4 |
strcmpnew |
|
esi und edi gesichert,
da der Visual C++ Compiler erwartet, daß diese Register nicht verändert werden.
Außerdem wird das Flag-Register gesichert, da auch das Direction-Flag erhalten bleiben
muß.
esi, edi und es auf die Verwendung der
Blockbefehle lods und scas vorbereitet. Die Adressen der Strings str1 und str2 werden in die
Register esi und edi geladen, und das Direction-Flag gelöscht, damit die
Blockbefehle mit aufsteigenden Adressen arbeiten.
al geladen, und dann mit dem entsprechenden Byte von str2 verglichen.
al=0. Wenn ja, wird mit 6. fortgefahren, ansonsten wird bei 3. das
nächste Byte verglichen.
eax wird mit dem Funktionsergebnis
0 geladen und zum Ende der Funktion, Schritt 8 gesprungen.
eax mit dem Funktionsergebnis -1 geladen, andernfalls mit +1 und
zum Ende der Funktion, Schritt 8 gesprungen.
edi und esi werden
wiederhergestellt und schließlich wird zum aufrufenden Programm zurückgekehrt.
Um eine Object-Datei aus dem Quellcode zu erzeugen, ist unter DOS folgender Aufruf des Borland Turbo Assemblers nötig:
tasm /ml /zi strcmpn.asm
tasm /ml strcmpn.asm
Man hätte die Assembleranweisungen von strcmpnew auch innerhalb eines __asm-Blocks
direkt in einer C-Bibliothek schreiben können (sog. inline-Assembler). Wir haben uns
jedoch für die Erzeugung von .obj-Dateien entschieden, weil diese auch in anderen
Programmiersprachen als C eingesetzt werden können und dem Programmierer außerdem größere
Freiheiten bei der Codegestaltung läßt.
Eine Alternative zum gewählten Lösungsweg wäre es, wenn man die beiden Strings mit der Blockanweisung
repe cmpsb
auf einmal vergleichen würde, man bräuchte auf diese Weise keine Wiederholungsschleife.
Vorher müsste man jedoch die Länge eines der beiden Strings bestimmen (z.B. str1),
indem man seine Ende-Markierung (ein '0'-Byte) sucht:
mov ecx,0ffffffffh ;maximale Segmentgröße
mov al,0 ;'0'-Byte wird gesucht
repne scasb ;Vergleich von al mit es:[edi], bis '0' gefunden
Dies hat jedoch Nachteile in der Ausführungszeit, denn es wird immer ein ganzer
String abgesucht, um dessen Ende zu finden. In ungünstigen Fällen wird dabei ein String
ganz abgearbeitet, obwohl sich beide Strings schon in den ersten Zeichen unterscheiden,
oder der andere String viel kürzer wäre. Die Ausführungsgeschwindigkeit hinge zu sehr
von der Reihenfolge der Parameter ab.
Wenn die Parameterliste der Funktion erweitert werden soll, muß beim Zugriff beachtet
werden, daß der Compiler die Parameter von rechts nach links auf dem Stack ablegt. Am
einfachsten ist deswegeb die Erweiterung, wenn neu hinzugefügte Parameter hinten an die
bereits bestehenden angefügt werden. An der Adressierung der ursprünglichen Parameter
muß dann nämlich nichts verändert werden, da sie weiterhin als letzes auf den Stack
gelegt werden.
Wenn es neue Optionen notwendig machen, daß innerhalb des Unterprogramms mittels
push/pop auf den Stack zugegriffen wird, ist es empfehlenswert,
die Parameter nicht über esp, wie es in der jetzigen Version geschieht, zu
adressieren, sondern einen Stackrahmen einzurichten und ebp zu verwenden. Anfang
und Ende der Funktion sähen dann etwa so aus:
push ebp ;ebp sichern
mov ebp,esp ;jetzige Stackhöhe in ebp
... ;Anweisungen ...
pop ebp ;ebp wiederherstellen
ret ;Rücksprung
Eine sinnvolle Ergänzung der Funktion strcmpnew ist z.B. die Erweiterung um einen
Parameter n, der die maximale Anzahl Zeichen zweier Strings angibt, die verglichen werden
sollen (so geschehen in der unten beschriebenen Funktion strncmpnew).
Der Parameter liegt dann 4 Bytes über dem Zeiger auf str2 auf dem Stack. Innerhalb der
Vergleichsschleife muß dann noch geprüft werden, ob bereits n Zeichen verglichen
wurden.
Sinnvoll wäre auch die Möglichkeit, neben dem normalen Funktionsergebnis einen Wert zurückzugeben, der den Index des ersten verschiedenen Zeichens enthält. Die Parameterliste müsste dann um einen Zeiger auf eine 32-Bit Integer-Variable ergänzt werden. Innerhalb der Vergleichsschleife würde ein Zählregister mit jedem Vergleichsschritt inkrementiert werden, und sein Wert am Ende der Variablen zugewiesen werden.
strncmpnew |
|
esi und edi gesichert,
da der Visual C++ Compiler erwartet, daß diese Register nicht verändert werden.
Außerdem wird das Flag-Register gesichert, da auch das Direction-Flag erhalten bleiben
muß.
ecx mit dem Zähler n geladen und über jecxz
geprüft, ob es den Wert 0 enthält. In diesem Fall wird sofort mit Schritt 8. weitergemacht (bei
Vergleich von 0 Zeichen wird als Resultat Gleichheit zurückgegeben)
esi, edi und es auf die Verwendung
der Blockbefehle lods und scas vorbereitet. Die Adressen der Strings str1 und str2 werden
in die Register esi und edi geladen, und das Direction-Flag gelöscht, damit
die Blockbefehle mit aufsteigenden Adressen arbeiten.
al geladen, und dann mit dem entsprechenden Byte von str2 verglichen.
al=0. Wenn ja, wird mit 6. fortgefahren.
ecx um 1 dekrementiert
und geprüft, ob er dadurch 0 geworden ist. Wenn ja, ist der Vergleich beendet und es wird
mit 6. fortgefahren, ansonsten wird bei 3. das nächste Byte verglichen.
eax wird mit dem Funktionsergebnis
0 geladen und zum Ende der Funktion, Schritt 8 gesprungen.
eax mit dem Funktionsergebnis -1 geladen, andernfalls mit +1 und
zum Ende der Funktion, Schritt 8 gesprungen.
edi und esi werden
wiederhergestellt und schließlich wird zum aufrufenden Programm zurückgekehrt.
Eine Alternative zum gewählten Lösungsweg wäre es, wenn man die beiden Strings mit der Blockanweisung
repe cmpsb
auf einmal vergleichen würde, man bräuchte auf diese Weise keine Wiederholungsschleife.
Vorher müsste man jedoch prüfen, ob die Länge eines der beiden Strings kleiner als die durch
den Parameter n angegebene maximale Vergleichslänge ist, indem man seine Ende-Markierung (ein
'0'-Byte) sucht:
mov ecx,n ;maximale Vergleichslänge
mov al,0 ;'0'-Byte wird gesucht
repne scasb ;Vergleich von al mit es:[edi], bis '0' gefunden
Dies hat wieder den unter strcmpnew erwähnten Nachteil, daß unter ungünstigen
Umständen mehr Vergleiche als notwendig ausgeführt werden.
Für das Erweitern der Funktion strncmpnew gilt dasselbe wie oben bereits bei
strcmpnew beschrieben.
Assemblierung |
Um eine Object-Datei aus den Quellcode zu erzeugen, ist unter DOS folgender Aufruf des
Borland Turbo Assemblers nötig:
für strcmpnew
tasm /ml /zi strcmpn.asm
tasm /ml strcmpn.asm
strncmpnew
tasm /ml /zi strncmpn.asm
tasm /ml strncmpn.asm
Man hätte die Assembleranweisungen von strcmpnew und strncmpnew auch innerhalb eines
__asm-Blocks direkt in einer C-Bibliothek schreiben können (sog. inline-Assembler).
Wir haben uns jedoch für die Erzeugung von .obj-Dateien entschieden, weil diese auch in
anderen Programmiersprachen als C eingesetzt werden können und dem Programmierer außerdem
größere Freiheiten bei der Codegestaltung läßt.
12.07.98