Autor Thema: DS,SI,ES und DI-Probleme  (Gelesen 4456 mal)

bscreator

  • Gast
Gespeichert
« am: 25. July 2007, 17:12 »
Problem 1:
Bin wieder dabei, so eine kleine Stringfunktion zu schreiben. Diese soll alle Zeichen in einem Quellstring, der in ES:SI steht, in verkehrter Reihenfolge nach DS:SI schreiben.

Copy_Begin:
mov ah,0x00             ;Stringendezeichen
mov DI,SI                  ;SI wird für später benötigt
mov [ES:DI+BX],ah   ;BX zeigt auf Stringende -> Stringendezeichen hinzufügen
mov SI,DS                 ;Offsetadresse von DS nach SI

Copy_Loop:
dec BX
mov ah,[ES:DI+BX]  ;Zeichen von ES:DI nach AH
mov [DS:SI],ah        ;Zeichen von AH nach DS:SI
inc SI                       ;nächste Speicherstelle
or BX,BX                  ;Stringende erreicht ?
jz Copy_End           
jmp Copy_Loop       ;wiederholen

Copy_End:
mov ah,0x00
mov [DS:SI]ah         ;Stringendezeichen hinzufügen
retn                         ;Beenden

Beim Ausführen des Programms passiert nichts, außer das NASM seltsamerweise beendet wird.


Nun zu meiner zweiten Frage:Thoth schrieb im vorherigen Thema:
Zitat
solltest du den Code ganz oft verwenden wollen und dich hunderprozentig darauf verlassen, dann würde ich noch nach jedem lodsb testen, ob si überläuft. Also mit jc noch ein

Code:
push ax
mov ax, ds
add ax, 0x1000
mov ds, ax
pop ax

oder so anbringen.

Was passiert eigentlich bei diesem Code ? Ich erkenne darin nur soviel, dass die Adresse des Datensegments um 1000h erhöht wird. Aber wieso ???????? Da SI doch ein 16-Bit-Indexregister ist, kann dies doch erst bei einem String überlaufen, der größer als 16Bit ist, oder ?
Außerdem wird der Inhalt von SI doch mit jedem mov si,String überschrieben und nicht hinzuaddiert, oder ?

« Letzte Änderung: 26. July 2007, 14:32 von bscreator »

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 26. July 2007, 16:20 »
SI kann auch bei Strings überlaufen die kürzer als 2^16 Bytes sind, falls der String nicht am Segmentanfang beginnt.

Ich versteh deine Funktion nicht ganz. Was soll z.B. die 5. Zeile bewirken? Du schreibst die Segmentaddresse von DS nach SI, DS:SI ist danach doch eine vollkommen unsinnige Addresse?!

Du könntest das Problem z.B. mit String-Instructions lösen:
; DS:SI = Quellstring
; ES:DI = Zielstring
; CX = Stringlänge (mit Nullbyte)

add di, cx
dec di

copy:
cld
lodsb ; byte lesen
std
stosb ; byte schreiben
loop copy ; cx mal wiederholen

ret

Oder etwa so ohne:
add di, cx

copy:
dec di
mov al, [ds:si]
mov [es:di], al
inc si
loop copy
ret

Wozu fügst du die Null-Bytes am Ende der Strings ein? Enthällt der Quellstring kein Nullbyte? Meine Funktionen oben könntest du natürlich auch so ändern, dass sie das Nullbyte am Ende einfügen (vermeidet ja einen Speicherzugriff *gg*), etwa mit
xor al, al
stosb.

bscreator

  • Gast
Gespeichert
« Antwort #2 am: 27. July 2007, 09:35 »
Danke für den Code, so kann man es natürlich einfacher machen :-D

Zitat
SI kann auch bei Strings überlaufen die kürzer als 2^16 Bytes sind, falls der String nicht am Segmentanfang beginnt.
Sorry, das versteh ich nicht ganz. Heißt das, dass ich nur eine bestimmte Anzahl von Strings ausgeben kann, bevor SI überläuft ?

Und kann mir bitte jemand den folgenden Code, mit dem man einem SI-Überlauf vorbeugen kann, kurz erklären?
push ax
mov ax, ds
add ax, 0x1000
mov ds, ax
pop ax

Thanks,
bsc

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 27. July 2007, 14:29 »
Die Adresse des Strings wird ja mit DS:SI angegeben, woraus die CPU dann die physikalisch Adresse folgendermaßen berechnet:
addr = DS * 0x10 + SI
Bsp:
DS * 0x10           0x12340
SI                   0xfedc
------------------------------
addr                0x2221c

mit loadsb wird jetzt Zeichen für Zeichen ausgelesen und si inkrementiert. Ist der String in meinem Beispiel länger als 0x124 würde si irgendwann von 0xffff auf 0x0000 springen(si läuft über) und ist somit um 0x10000 kleiner als erwartet. Um diesen Sprung auszugleichen kann man jetzt aufgrund der Adressberechnung der CPU mit Hilfe von DS ausgleichen, indem man 0x1000 addiert. (0x1000 * 0x10 = die 0x10000, die aufgrund des Überlaufes fehlen)
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

 

Einloggen