Auswahl von vier Argumentregistern auf x64 - gemeinsam für UN * X / Win64
Eines der Dinge, die Sie bei x86 beachten sollten, ist, dass der Registername für die Codierung "reg number" nicht offensichtlich ist. In Bezug auf die Befehlskodierung (das MOD R / M- Byte, siehe http://www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm ) sind die Registernummern 0 ... 7 - in dieser Reihenfolge - ?AX
, ?CX
, ?DX
, ?BX
, ?SP
, ?BP
, ?SI
, ?DI
.
Daher ist die Wahl von A / C / D (Regs 0..2) als Rückgabewert und der ersten beiden Argumente (die "klassische" 32-Bit- __fastcall
Konvention) eine logische Wahl. In Bezug auf 64-Bit werden die "höheren" Regs bestellt, und sowohl Microsoft als auch UN * X / Linux haben sich für R8
/ R9
als erste entschieden.
Mit diesem Hintergedanken, Microsofts Wahl RAX
(Rückgabewert) und RCX
, RDX
, R8
, R9
(arg [0..3]) ist eine verständliche Auswahl , wenn Sie wählten vier Register für Argumente.
Ich weiß nicht, warum sich der AMD64 UN * X ABI RDX
zuvor entschieden hat RCX
.
Auswahl von sechs Argumentregistern für x64 - UN * X-spezifisch
UN * X hat auf RISC-Architekturen traditionell Argumente in Registern übergeben - speziell für die ersten sechs Argumente (zumindest bei PPC, SPARC, MIPS). Dies könnte einer der Hauptgründe sein, warum die AMBI-Designer von AMD64 (UN * X) auch für diese Architektur sechs Register verwendet haben.
Also , wenn Sie wollen sechs Register übergeben Argumente, und es ist logisch , zu wählen RCX
, RDX
, R8
und R9
für vier von ihnen, die beiden anderen sollten Sie wählen?
Die "höheren" Register erfordern ein zusätzliches Befehlspräfix-Byte, um sie auszuwählen, und haben daher einen größeren Platzbedarf für Befehle. Sie möchten also keines davon auswählen, wenn Sie Optionen haben. Von den klassischen Registern sind diese aufgrund der impliziten Bedeutung von RBP
und RSP
diese nicht verfügbar und werden RBX
traditionell speziell für UN * X (Global Offset Table) verwendet, mit dem die AMD64 ABI-Designer anscheinend nicht unnötig inkompatibel werden wollten.
Ergo, die einzige Wahl war RSI
/ RDI
.
Also, wenn Sie RSI
/ RDI
als Argumentregister nehmen müssen, welche Argumente sollten sie sein?
Sie zu machen arg[0]
und arg[1]
hat einige Vorteile. Siehe den Kommentar von cHao.
?SI
und ?DI
sind Zeichenfolgenbefehls-Quell- / Zieloperanden, und wie cHao erwähnt, bedeutet ihre Verwendung als Argumentregister, dass bei den AMD64 UN * X-Aufrufkonventionen die einfachste mögliche strcpy()
Funktion beispielsweise nur aus den zwei CPU-Befehlen besteht, repz movsb; ret
weil die Quelle / das Ziel Adressen wurden vom Anrufer in die richtigen Register eingetragen. Dies gilt insbesondere für Low-Level- und Compiler-generierten "Kleber" -Code (denken Sie beispielsweise an einige C ++ - Heap-Allokatoren, die Objekte bei der Erstellung nicht füllen, oder an die Kernel-Zero-Filling-Heap-Seitensbrk()
(oder Seitenfehler beim Kopieren beim Schreiben) eine enorme Menge an Blockkopien / -füllungen, daher ist es nützlich für Code, der so häufig zum Speichern der zwei oder drei CPU-Anweisungen verwendet wird, die ansonsten solche Quell- / Zieladressenargumente in die laden würden "richtige" Register.
So in einer Art und Weise, UN * X und Win64 sind nur insofern anders, als UN * X „ wird vorangestellt“ zwei weitere Argumente, in gezielt ausgewählten RSI
/ RDI
Register, auf die natürliche Wahl der vier Argumente RCX
, RDX
, R8
und R9
.
Darüber hinaus ...
Es gibt mehr Unterschiede zwischen den UN * X- und Windows x64-ABIs als nur die Zuordnung von Argumenten zu bestimmten Registern. Die Übersicht über Win64 finden Sie unter:
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64 und AMD64 UN * X unterscheiden sich auch deutlich in der Art und Weise, wie Stackspace verwendet wird. Unter Win64 muss der Aufrufer beispielsweise Stackspace für Funktionsargumente zuweisen, obwohl die Argumente 0 ... 3 in Registern übergeben werden. Auf UN * X hingegen ist eine Blattfunktion (dh eine, die keine anderen Funktionen aufruft) nicht einmal erforderlich, um Stapelspeicher zuzuweisen, wenn sie nicht mehr als 128 Byte benötigt (ja, Sie besitzen und können verwenden eine bestimmte Menge an Stack, ohne ihn zuzuweisen ... nun, es sei denn, Sie sind Kernel-Code, eine Quelle für raffinierte Fehler). All dies sind spezielle Optimierungsoptionen. Die meisten Gründe hierfür werden in den vollständigen ABI-Referenzen erläutert, auf die die Wikipedia-Referenz des Originalplakats verweist.