2017-08-21 1 views
0

(Laufe Montag x86 durch DOSBOX) bewegenMontag x86 - wie Strings zwischen Variablen

I Verfahren bin mit einem Bild (BMP-Datei) und den ersten laden wird die Datei (öffnen) zu laden:

proc OpenFile 
    mov ah, 3Dh 
    xor al, al 
    mov dx, offset filename 
    int 21h 
    jc openerror1 
    mov [filehandle], ax 
    ret 
    openerror1: 
    mov dx, offset ErrorMsg 
    mov ah, 9h 
    int 21h 
    ret 
endp 

ich möchte Dateiname für den Namen einer Datei als globale Variable verwendet werden - String seines Weges so das einzige, was ich tun muss, bevor alle procs ausgeführt ist, den richtigen Pfad zu dem Dateinamen bewegen Variable.

filename db ? 
img1 db 'img1.bmp',0 
img2 db 'img2.bmp',0 

Ich dachte, es ist eine Art von String ist die Übertragung und ich fand heraus, dass der MOVS Befehl hilfreich sein könnte, aber ich schaffte nicht die Art und Weise funktioniert es zu verstehen.

+2

Sie können nur einen Zeiger darin speichern. Kennst du C? Du könntest es natürlich auch kopieren, aber dann brauchst du genug Platz (übrigens ist ein Zeiger auch mehr als ein Byte). – Jester

+0

Sie können auch entscheiden, dass 'OpenFile' erfordert, dass der Aufrufer den' ds: dx' bereits so voreinstellt, dass er auf den Dateinamen zeigt, also wird es Prozedurargument sein. Dann können Sie tun 'mov dx, offset img1'' Aufruf OpenFile' .. und es ist auch üblich, Wert in 'ax' aus der Prozedur zurückgeben, so wieder der Aufrufer wird verantwortlich sein, den Griff irgendwo zu speichern. Auf diese Weise können Sie die 'OpenFile' für verschiedene Dateien gleichzeitig wiederverwenden. Vielleicht etwas über die Vorteile der funktionalen Programmierung lesen (nur nicht überanstrengt werden, manche Leute springen zu schnell auf diesen Weg, ohne zu verstehen, wie praktisch SW anti-Fn ist). – Ped7g

Antwort

5

Nur ein kurzes Beispiel, wie MOVS funktioniert (und andere aus der "String" -Befehlsfamilie sind ähnlich).

Zuerst brauchen Sie Speicherplatz im Speicher, in Ihrem Fall muss also filename erweitert werden.

MAX_FILE_NAME_LENGTH EQU 128 
filename db MAX_FILE_NAME_LENGTH dup (?) ; reserving enough space for "string" 
img1  db 'img1.bmp',0 
img1length equ $-img1 
img2  db 'img2.bmp',0 
img2length equ $-img2 

Nun img2 "string" in filename ... img2 ist die Adresse in den Speicher, in dem die folgenden img2length Bytes definiert werden durch die db oben (einschließlich des Null-Separator) zu kopieren. Und Zieladresse ist das filename Symbol. Die MOVS kopiert Daten von ds:si (si als "Quelle") zu es:di (di als "Ziel").

... 
; make sure the DS and ES are set up correctly, if you use data segment, then 
; (this can be done just once, if you don't change ds/es in your code any more) 
mov ax, @data 
mov ds, ax 
mov es, ax 
cld    ; DF=0, if you don't plan to use DF=1 elsewhere 
    ; DF=0 means, that the "string" instructions increment SI/DI 
    ; DF=1 would make them run backwards, decrementing addresses 
    ; (that's handy when implementing "memmove" with overlapping areas) 
... 

... 
; now prepare registers (except ds+es) for `rep movsb` variant 
mov cx, img2length ; how many bytes to copy (numeric value) 
lea si, [img2]  ; offset img2 into SI 
lea di, [filename] ; offset filename into DI 
rep movsb   ; copy "img2length" bytes from ds:si to es:di 

; check memory in debugger, the reserved area at "filename" should 
; now contain the copied string, including the zero terminator 

; WARNING, if you forget about reserved space limitations, and define 
; img2 string longer than MAX_FILE_NAME_LENGTH, the code above will 
; merrily overwrite more memory than expected, destroying values in memory 
; beyond the filename buffer 

... 

Eine weitere Variante mit Zeigern Beispiel:

Gängige Praxis ist Wert zu übergeben als Argument zu funktionieren, in diesem Fall, dass Sie den Anrufer fragen ds:dx vor OpenFile Aufruf voreinzustellen, dann weglassen Sie einfach den dx Setup-Code in der Prozedur, und Sie sind fertig, Beispiel:

; arguments: ds:dx = pointer to ASCIIZ file name 
; returns (and modifies): ax = file handle 
; in case of file error "..." happens 
proc OpenFile 
    mov ax, 3D00h ; ah = 3D "open file", al = 0 "read-only" 
    int 21h 
    jc openerror1 
    ret 
    openerror1: 
    ... ; probably terminate app any way in case of error 

dann vor jedem c alle richten Sie ds: dx, und nach dem Laden der Datei-Handle, wie Sie wollen:

img1 db 'img1.bmp',0 
img1FileHandle dw 2 ; DW, because handle is 16 bit "wide" (AX = 16 bits) 
    ; 2 == STDERR, until the code will run OpenFile and store real handle 

Es ist auch möglich, diese Dinge in Globals in Erinnerung zu bringen:

... 
    ; let's pretend the DS was already set before 
    mov dx, offset img1 
    call OpenFile 
    mov [img1FileHandle],ax 
    ... 

Daten wie diese aufgebaut wird , und dann lesen Sie sie aus dem Speicher innerhalb OpenFile, aber wenn Sie versuchen, das zu schreiben, werden Sie sehen, es ist ziemlich umständlich, Argumente in Registern zu übergeben ist einfacher ... bis zu einem Punkt, bis Ihr Code komplex genug wird, um zu vergessen, welche Prozedur braucht was in welchem ​​Register, und plötzlich wird es ein bisschen durcheinander.

Von dort ist es besser, einige offizielle Aufrufkonvention, wie Cdecl und ähnliche, aber die meisten der Aufrufkonventionen für 16b/32b-Modi verwendet Stapel für die Weitergabe von Argumenten, die wiederum ein bisschen mühsam ist, von Hand zu schreiben, und auch führt schlechter als Werte durch Register. Für kleine pure asm-Anwendungen können Sie die Argumente/Ergebnisse jeder Prozedur so optimieren, wie sie passen, und einfach jede Prozedur mit einer klaren Beschreibung der verwendeten Register kommentieren.

+0

upvoted für die Verwendung von 'rep movsb ', aber Sie sollten zumindest erwähnen, dass der Kommentar von Jester korrekt ist: Durch die Übergabe eines Zeigers anstelle der Festcodierung eines Verweises auf' [Dateiname] 'würde die Notwendigkeit einer Kopie vermieden. –

+0

@PeterCordes versuchte die Antwort etwas zu erweitern. Ich spielte auch mit einem Beispiel herum, das den Speicher des Zeigers in globale Variable zeigt, aber der resultierende Code war so fugig, dass ich ihn lieber komplett entfernte, damit jemand nicht versehentlich daraus lernt und denkt, dass es ein gutes Beispiel dafür ist, wie man schreibt es. – Ped7g

+1

Ja, es ist eine Menge Arbeit, eine vollständige Antwort auf diese Fragen zu geben, die ein Problem auf eine wirklich seltsame (und ineffiziente Weise) angehen. –

Verwandte Themen