Montage: Der Wechsel zwischen zwei Speicheradressen,
-
18-09-2019 - |
Frage
Ich versuche Montag zu lernen (so mit mir tragen), und ich bin auf dieser Linie einen Compiler-Fehler bekommen:
mov byte [t_last], [t_cur]
Der Fehler ist
error: invalid combination of opcode and operands
Ich vermute, dass die Ursache für diesen Fehler ist einfach, dass es nicht möglich, dass eine mov Anweisung zwischen zwei Speicheradressen zu bewegen, aber einem halben Stunde googeln und ich habe nicht in der Lage, dies zu bestätigen - ist dies der Fall?
Auch unter der Annahme, ich Recht habe, das bedeutet, dass ich ein Register als Zwischenpunkt zum Kopieren von Speichern verwenden muß:
mov cl, [t_cur]
mov [t_last], cl
Was ist das empfohlene Register zu verwenden (oder soll ich den Stapel statt)?
Lösung
Ihre Vermutung richtig ist, können Sie nicht aus dem Speicher in den Speicher bewegen.
Jedes Allzweckregister tun wird. Denken Sie daran, das Register zu drücken, wenn Sie nicht sicher sind, was drin ist und wiederherstellen es wieder einmal getan.
Andere Tipps
Es ist in 16-Bit wirklich einfach ist, einfach wie folgt vor:
push di
push si
push cx
mov cx,(number of bytes to move)
lea di,(destination address)
lea si,(source address)
rep movsb
pop cx
pop si
pop di
Hinweis: Die Schübe & Pops sind neceessary, wenn Sie die Inhalte der Register speichern müssen
.Es gibt auch einen MOVS von Befehlsdaten aus dem Speicher in den Speicher zu bewegen:
MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS
Es ist technisch möglich, aus dem Speicher in den Speicher zu bewegen.
Versuchen Sie es mit MOVS (move string) und Einstellung [E] SI und [E] DI , je nachdem, ob Sie wollen Byte übertragen (s), (e), etc.
mov si, t_cur ; Load SI with address of 't_cur'
mov di, t_last ; Load DI with address of 't_last'
movsb ; Move byte from [SI] to [DI]
; Some dummy data
t_cur db 0x9a ; DB tells NASM that we want to declare a byte
t_last db 0x7f ; (See above)
Dies ist weniger effizient als eine normale Last + Shop mit einem temporären Register verwenden, aber es funktioniert mit einem einzigen Befehl die aktuelle Kopie tun.
Hier ist, wie MOVS verwendet werden soll, und wie es funktioniert: https://www.felixcloutier.com/x86/movs:movsb: MOVSW: movsd: movsq
Es ist normalerweise nur mit einem rep
Präfix für Blockkopien, nicht für ein einzelnes Element verwendet. (Moderne CPUs haben ziemlich effizientes Mikro für rep movsb
, dass es in der Nähe der Geschwindigkeit einer Schleife mit AVX Vektor Lade- / Speicherbefehlen.)
Das ist richtig, Code x86 Maschine kann nicht eine Anweisung mit zwei expliziter Speicheroperanden (beliebigen Adressen angegeben in []
)
- Warum nicht movl erlaubt von Speicher zu Speicher?
- Was x86-Befehle nehmen zwei (oder mehr) Speicheroperanden?
Was ist das empfohlene Register
Alle registrieren Sie nicht speichern müssen / wiederherstellen.
In allen Mainstream-32-Bit- und 64-Bit-Aufrufkonventionen, EAX, ECX und EDX sind Call-clobbered, so AL, CL und DL sind eine gute Wahl. Für ein Byte oder ein Wort zu kopieren, mögen Sie in der Regel eine movzx
Last in ein 32-Bit-Register, dann ein 8-Bit oder 16-Bit-Speicher. Dies vermeidet eine falsche Abhängigkeit von dem alten Wert des Registers. Nur eine schmale 16 oder 8-Bit-mov
Last verwenden, wenn Sie aktiv wollen fusionieren in die Low-Bits eines anderen Wertes. x86 der movzx
ist das Analogon von Anweisungen wie ARM ldrb
.
movzx ecx, byte [rdi] ; load CL, zero-extending into RCX
mov [rdi+10], cl
In 64-Bit-Modus, SIL, DIL, R 8b, R 9b und so weiter ist auch feine Auswahl, erfordert aber einen REX-Präfix in dem Maschinencode für den Laden so gibt es einen kleinere Codegröße Grund, sie zu vermeiden.
Generell vermeiden Schreiben AH, BH, CH oder DH aus Performance-Gründen, es sei denn, Sie gelesen haben und verstanden die folgenden Links und keine falschen Abhängigkeiten oder Teilregisterstände Verschmelzung werden nicht ein Problem sein, oder überhaupt passieren in Ihrem Code.
- Warum nicht GCC Verwendung Teilregister?
- Wie genau Teilregister auf Haswell / Skylake durchführen? Schreiben AL eine falsche Abhängigkeit von RAX zu haben scheint, und AH ist inkonsistent
(oder soll ich den Stapel statt)?
Zunächst einmal können Sie nicht ein einziges Byte an alle drücken, so gibt es keine Möglichkeit, ein Byte-Lade- / Byte Speicher vom Stapel tun könnte. Für ein Wort, dword oder qword (abhängig von der CPU-Modus), könnten Sie push [src]
/ pop [dst]
, aber das ist viel langsamer als über ein Register zu kopieren. Es stellt eine zusätzliche Speicher / Reload-Store-Weiterleitung Latenz, bevor die Daten aus dem endgültigen Bestimmungsort gelesen werden können, und mehr Uops nimmt.
Es sei denn, irgendwo auf dem Stapel ist das gewünschte Ziel und Sie können nicht, dass die lokale Variable in ein Register optimieren, wobei in diesem Fall push [src]
gerade fein ist es dort zu kopieren und Stapelspeicherplatz für es zuweisen.
finden Sie unter https://agner.org/optimize/ und anderen x86-Performance-Links in die x86-Tag Wiki
Ich will nur „Memory-Barriere“ mit Ihnen besprechen. In C-Code
a = b;//Take data from b and puts it in a
würde zu montierenden
mov %eax, b # suppose %eax is used as the temp
mov a, %eax
Das System kann die Unteilbarkeit der Abtretung nicht garantieren. Deshalb haben wir eine rmb brauchen (Lesesperre)