Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet 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:
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 ?
-
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.
-
Danke für den Code, so kann man es natürlich einfacher machen :-D
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
-
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)