2009-12-14 5 views
18

Wie der Titel sagt, warum würde man "movl $ 1,% eax" im Gegensatz zu sagen, " movb $ 1,% eax ", mir wurde gesagt, dass movl die Bits hoher Ordnung von% eax auf Null setzen würde, aber ist nicht% eax ein Register, das der Größe der Wortgröße des Systems entspricht? was bedeutet, dass movl in Wirklichkeit eine ganzzahlige Operation ist (und nicht lang?)

Ich bin eindeutig ein bisschen verwirrt über alles; Vielen Dank.

Antwort

3

long war ursprünglich 32 Bits, während int und short 16. Und die Namen der Opcodes nicht jedes Mal ändern, wenn jemand mit einem neuen Betriebssystem herauskommt.

+1

Was hat eine Version eines Betriebssystems mit den Namenskonventionen von Typen zu tun? –

+0

Es war eine Redewendung. Die Absicht war anzugeben, dass, wenn sie einmal veröffentlicht wurde, die Befehlssatzspezifikation nicht destruktiv geändert wurde. –

+0

Deshalb bevorzuge ich die Syntax von Intel zur GAS-Syntax. Intel: mov dword eax, ecx GAS: movl eax, ecx Die "l" Größe Operand verwirrt Menschen. Mehr Leute bekommen dieses "dword" bedeutet 32-Bit. – Jason

5

%eax ist ein 32-Bit-Register. Um eine kleinere Breite zu verwenden, benötigen Sie %ax für 16-Bit. %ax kann weiter unterteilt werden in %ah für das High-Byte %ax und %al für das untere Byte. Das gleiche gilt für die anderen x86 GPRs.

Betrachtet man die Intel Befehlssatz Referenz für die mov Anweisung, sehe ich keine Variante, die ein einzelnes Byte in ein 32-Bit-Register verschieben kann - es wird wahrscheinlich als ein Umzug in %al interpretiert.

Da movl ist ein 32-Bit-Befehl, die Werte für die obere Bytes Null in dem Fall eines unmittelbaren Wertes entsprechen. Wenn Sie sich aus dem Speicher bewegen, würden Sie ein ganzes 32-Bit-Wort verschieben.

%eax wird nicht genullt, es sei denn Sie movl $0, %eax, oder wenn Sie xorl %eax, %eax. Sonst behält es den Wert, der zuvor dort war. Wenn Sie movl $1, %eax eingeben, werden Sie mit 0x00000001 im Register enden, da der 32-Bitbefehl einen 32-Bit-Sofortwert in das Register verschiebt.

+0

Das Movl ist ein 32-Bit-Befehl ist zum Teil die Antwort, die ich gesucht habe, aber eine andere Antwort, die ich frage, ist, ob% eax standardmäßig _not_ nicht genullt wird, oder ist unzufrieden? –

+1

% eax wird niemals nullgestellt, es sei denn, Sie tun dies ausdrücklich. Wenn Sie movb verwenden, um nur in eines der Bytes zu schreiben, bleiben die anderen Bytes unverändert. –

7

Auf einer 32-Bit-Maschine ist% eax ein 4-Byte-Register (32 Bit). movl schreibt in alle 4 Bytes. In Ihrem Beispiel werden die oberen 3 Bytes auf Null gesetzt und 1 in das unterste Byte gesetzt. Das Movb wird nur das niederwertige Byte ändern.

+0

Also Movl ist eine 4-Byte-Operation? –

+0

Nicht sicher, welcher Assembler das ist, aber ist nicht der einzige Unterschied die Größe der Konstante? – peterchen

+2

Ja. In der IA32-Architektur (gewöhnlich als x86 bezeichnet) bedeutet "lang" 4 Bytes und movl steht für "move long". –

1

%eax ist 32 Bits auf 32-Bit-Maschinen. %ax ist 16 Bit, und %ah und %al sind seine 8-Bit hohen und niedrigen Bestandteile.

Daher ist movl hier vollkommen gültig. In Bezug auf die Effizienz wird movl so schnell wie movb sein, und das Nullsetzen der hohen 3 Bytes von %eax ist oft eine wünschenswerte Eigenschaft. Möglicherweise möchten Sie es später als 32-Bit-Wert verwenden, daher ist movb keine gute Möglichkeit, ein Byte dorthin zu verschieben.

36

Gegensatz zu, sagen wir, "MOVB 1 $,% eax"

Diese Anweisung ist ungültig. Sie können eax nicht mit der Anweisung movb verwenden. Sie würden stattdessen ein 8-Bit-Register verwenden. Zum Beispiel:

MOVB $ 1, $ al

aber nicht% eax ein Register, das ist entspricht der Größe des Wortgröße des Systems?

Nein. EAX wird immer ein 32-Bit-Wert sein, unabhängig von der Registergröße des Systems.

Sie verwechseln C-Variablengrößen mit Registergrößen. C-Variablengrößen können sich je nach System und Compiler ändern.

Die Montage ist einfacher als C. Bei der GAS-Montage werden die Anweisungen mit den Buchstaben "b", "s", "w", "l", "q" oder "t" versehen, um die Größe des Operanden zu bestimmen manipuliert.

* b = byte (8 bit) 
* s = short (16 bit integer) or single (32-bit floating point) 
* w = word (16 bit) 
* l = long (32 bit integer or 64-bit floating point) 
* q = quad (64 bit) 
* t = ten bytes (80-bit floating point) 

Diese Größen sind konstant. Sie werden nie geändert werden. al ist immer 8-Bit und eax ist immer 32-Bit.

+0

Schöne Antwort, danke! –

2

Ihre zweite Wahl wird nur einen Fehler erzeugen, x86 hat diesen Befehl nicht. X86 ist ein bisschen einzigartig in Bezug auf das Laden von Bytes in bestimmte Register. Ja, bei den meisten Befehlssatzarchitekturen ist der Operand null oder vorzeichenerweitert, aber x86 erlaubt es Ihnen, nur das untere Byte oder die unteren 16 Bits einiger von ihnen zu schreiben.

Es gibt sicherlich andere Möglichkeiten, wie das Register Clearing- und es dann erhöht wird, aber hier sind drei zunächst vernünftig aussehende Entscheidungen, die Sie haben:

0: b8 01 00 00 00   movl $0x1,%eax 

    5: 31 c0     xorl %eax,%eax 
    7: b0 01     movb $0x1,%al 

    9: b0 01     movb $0x1,%al 
    b: 0f b6 c0    movzbl %al,%eax 

Die erste ist 5 Bytes, die zweite 4, die dritte 5. Also ist die Sekunde die beste Wahl, wenn man für den Raum optimiert, sonst nehme ich an, dass die erste, die am schnellsten läuft, die erste ist. X86 ist in diesen Tagen zutiefst in Pipelines verwickelt, so dass die beiden Anweisungen ineinandergreifen und die Maschine abhängig von den Details der Pipeline-Hardware einige Wartezustände benötigt.

Natürlich sind diese x86-ops werden in CPU micro-ops, in CPU-spezifischen Weise übersetzt und so wer weiß, was passieren wird.

+0

Sehr gute Antwort, sehr erklärend. Vielen Dank –

Verwandte Themen