Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: bscreator am 25. July 2007, 17:12

Titel: DS,SI,ES und DI-Probleme
Beitrag von: bscreator 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 ?

Titel: Re: DS,SI,ES und DI-Probleme
Beitrag von: Korona 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.
Titel: Re: DS,SI,ES und DI-Probleme
Beitrag von: bscreator 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
Titel: Re: DS,SI,ES und DI-Probleme
Beitrag von: MNemo 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)