Warum verwendet Windows64 eine andere Aufrufkonvention als alle anderen Betriebssysteme unter x86-64?

110

AMD verfügt über eine ABI-Spezifikation, die die auf x86-64 zu verwendende Aufrufkonvention beschreibt. Alle Betriebssysteme folgen ihm, mit Ausnahme von Windows, das über eine eigene x86-64-Aufrufkonvention verfügt. Warum?

Kennt jemand die technischen, historischen oder politischen Gründe für diesen Unterschied oder handelt es sich lediglich um ein NIH-Syndrom?

Ich verstehe, dass verschiedene Betriebssysteme unterschiedliche Anforderungen an übergeordnete Dinge haben können, aber das erklärt nicht, warum zum Beispiel die Reihenfolge der Registerparameterübergabe unter Windows so ist, wie sie rcx - rdx - r8 - r9 - rest on stackalle anderen verwenden rdi - rsi - rdx - rcx - r8 - r9 - rest on stack.

PS Ich bin mir bewusst, wie sich diese Aufrufkonventionen im Allgemeinen unterscheiden, und ich weiß, wo ich Details finden kann, wenn ich muss. Was ich wissen möchte ist warum .

Bearbeiten: Für das Wie siehe zB den Wikipedia-Eintrag und die Links von dort.

JanKanis
quelle
2
Nun, nur für das erste Register: rcx: ecx war der "this" -Parameter für die msvc __thiscall x86-Konvention. Wahrscheinlich, um die Portierung ihres Compilers auf x64 zu vereinfachen, haben sie als erstes mit rcx begonnen. Dass dann auch alles andere anders wäre, war nur eine Folge dieser anfänglichen Entscheidung.
Chris Becke
@ Chris: Ich habe unten einen Verweis auf das AMD64 ABI-Ergänzungsdokument (und einige Erklärungen, was es tatsächlich ist) hinzugefügt.
FrankH.
1
Ich habe keine Begründung von MS gefunden, aber ich habe hier eine Diskussion gefunden
phuclv

Antworten:

81

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- __fastcallKonvention) 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/ R9als 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 RDXzuvor 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, R8und R9fü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 RBPund RSPdiese nicht verfügbar und werden RBXtraditionell 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/ RDIals 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.
?SIund ?DIsind 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; retweil 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/ RDIRegister, auf die natürliche Wahl der vier Argumente RCX, RDX, R8und 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.

FrankH.
quelle
1
Informationen zu Registernamen: Dieses Präfixbyte kann ein Faktor sein. Dann wäre es für MS logischer, rcx - rdx - rdi - rsi als Argumentregister zu wählen. Der numerische Wert der ersten acht kann Ihnen jedoch helfen, wenn Sie einen ABI von Grund auf neu entwerfen. Es gibt jedoch keinen Grund, ihn zu ändern, wenn bereits ein perfekter ABI vorhanden ist, was nur zu mehr Verwirrung führt.
JanKanis
2
Bei RSI / RDI: Diese Anweisungen werden normalerweise eingefügt. In diesem Fall spielt das Aufrufen der Konvention keine Rolle. Ansonsten gibt es nur eine Kopie (oder vielleicht ein paar) diese Funktion systemweit , so dass es nur eine Handvoll von Bytes speichert insgesamt . Ist es nicht wert. Zu anderen Unterschieden / Aufrufstapel: Die Nützlichkeit bestimmter Auswahlmöglichkeiten wird in den ABI-Referenzen erläutert, sie führen jedoch keinen Vergleich durch. Sie sagen nicht, warum andere Optimierungen nicht ausgewählt wurden - z. B. warum Windows nicht über die rote Zone mit 128 Byte verfügt und warum der AMD ABI nicht über die zusätzlichen Stapelsteckplätze für Argumente verfügt.
JanKanis
1
@cHao: nein. Aber sie haben es trotzdem geändert. Der Win64 ABI unterscheidet sich vom Win32 ABI (und ist nicht kompatibel) und unterscheidet sich auch vom AMD ABI.
JanKanis
7
@Somejan: Win64 und Win32 __fastcallsind zu 100% identisch, wenn nicht mehr als zwei Argumente nicht größer als 32 Bit sind und ein Wert zurückgegeben wird, der nicht größer als 32 Bit ist. Das ist keine kleine Klasse von Funktionen. Eine solche Abwärtskompatibilität zwischen den UN * X-ABIs für i386 / amd64 ist überhaupt nicht möglich.
FrankH.
2
@szx: Ich habe gerade den entsprechenden Mailinglisten-Thread vom November 2000 gefunden und eine Antwort gepostet, in der die Gründe zusammengefasst sind. Beachten Sie, memcpydass dies auf diese Weise implementiert werden könnte, nicht strcpy.
Peter Cordes
42

IDK, warum Windows das getan hat, was sie getan haben. Eine Vermutung finden Sie am Ende dieser Antwort. Ich war neugierig, wie die SysV-Anrufkonvention beschlossen wurde, also habe ich mich im Mailinglistenarchiv umgesehen und ein paar nette Sachen gefunden.

Es ist interessant, einige dieser alten Threads auf der AMD64-Mailingliste zu lesen, da AMD-Architekten darauf aktiv waren. zB war die Auswahl von Registernamen einer der schwierigen AspekteUAX : AMD erwog, die ursprünglichen 8 Register r0-r7 umzubenennen oder die neuen Register aufzurufen .

Das Feedback von Kernel-Entwicklern identifizierte auch Dinge, die das ursprüngliche Design von syscallund swapgsunbrauchbar machten . Auf diese Weise hat AMD die Anweisung aktualisiert , um dies zu klären, bevor tatsächliche Chips freigegeben werden. Interessant ist auch, dass Ende 2000 davon ausgegangen wurde, dass Intel AMD64 wahrscheinlich nicht einführen würde.


Die SysV (Linux) -Aufrufkonvention und die Entscheidung, wie viele Register im Vergleich zur Anrufer-Speicherung aufbewahrt werden sollen, wurde ursprünglich im November 2000 von Jan Hubicka (einem gcc-Entwickler) getroffen. Er kompilierte SPEC2000 und untersuchte die Codegröße und die Anzahl der Anweisungen. Dieser Diskussionsthread dreht sich um einige der gleichen Ideen wie Antworten und Kommentare zu dieser SO-Frage. In einem zweiten Thread schlug er die aktuelle Sequenz als optimal und hoffentlich endgültig vor und erzeugte kleineren Code als einige Alternativen .

Er verwendet den Begriff "global", um aufruferhaltene Register zu bezeichnen, die bei Verwendung gepusht / gepoppt werden müssen.

Die Wahl rdi, rsi, rdxals die ersten drei args war motiviert durch:

  • geringfügige Einsparung von Codegröße in Funktionen, die memsetoder andere C-String-Funktionen in ihren Argumenten aufrufen (wo gcc eine Wiederholungs-String-Operation einfügt?)
  • rbxist anruferhalten, da es ein Gewinn ist, wenn zwei anruferhaltene Regs ohne REX-Präfixe (rbx und rbp) zugänglich sind. Vermutlich gewählt, weil es die einzige andere Registrierung ist, die von keiner Anweisung implizit verwendet wird. (Wiederholungszeichenfolge, Verschiebungsanzahl und Mul / Div-Ausgänge / Eingänge berühren alles andere).
  • Keines der Register mit speziellen Zwecken ist aufruferhalten (siehe vorherigen Punkt), daher muss eine Funktion, die Wiederholungszeichenfolgenanweisungen oder eine Verschiebung der Variablenanzahl verwenden möchte, möglicherweise Funktionsargumente an einen anderen Ort verschieben, muss jedoch nicht / speichern Stellen Sie den Wert des Anrufers wieder her.
  • Wir versuchen, RCX zu Beginn der Sequenz zu vermeiden, da es sich um ein Register handelt, das üblicherweise für spezielle Zwecke wie EAX verwendet wird, sodass es denselben Zweck hat, in der Sequenz zu fehlen. Es kann auch nicht für Syscalls verwendet werden, und wir möchten, dass die Syscall-Sequenz so weit wie möglich mit der Funktionsaufrufsequenz übereinstimmt.

    (Hintergrund: syscall/ sysretZerstöre unvermeidlich rcx(mit rip) und r11(mit RFLAGS), sodass der Kernel nicht sehen kann, was ursprünglich rcxbeim syscallAusführen enthalten war.)

Der Kernel-Systemaufruf ABI wurde ausgewählt, um mit dem Funktionsaufruf ABI übereinzustimmen, außer r10anstelle von rcx, sodass ein libc-Wrapper wie mmap(2)can nur mov %rcx, %r10/ mov $0x9, %eax/ funktioniert syscall.


Beachten Sie, dass die von i386 Linux verwendete SysV-Aufrufkonvention im Vergleich zu Windows 32-Bit __vectorcall nicht funktioniert. Es übergibt alles auf dem Stapel und gibt nur edx:eaxfür int64 zurück, nicht für kleine Strukturen . Es ist keine Überraschung, dass wenig Anstrengungen unternommen wurden, um die Kompatibilität damit aufrechtzuerhalten. Wenn es keinen Grund gibt, dies nicht zu tun, haben sie Dinge wie die Beibehaltung des rbxAnrufs getan , da sie entschieden haben, dass es gut ist, einen anderen in der ursprünglichen 8 zu haben (der kein REX-Präfix benötigt).

Die Optimierung des ABI ist langfristig viel wichtiger als jede andere Überlegung. Ich denke, sie haben einen ziemlich guten Job gemacht. Ich bin mir nicht ganz sicher, ob ich in Register gepackte Strukturen anstelle verschiedener Felder in verschiedenen Regs zurückgeben soll. Ich denke, Code, der sie nach Wert weitergibt, ohne tatsächlich auf den Feldern zu arbeiten, gewinnt auf diese Weise, aber die zusätzliche Arbeit des Auspackens scheint albern. Sie hätten mehr als nur ganzzahlige Rückgaberegister haben können rdx:rax, so dass die Rückgabe einer Struktur mit 4 Mitgliedern sie in rdi, rsi, rdx, rax oder so zurückgeben könnte.

Sie erwogen, Ganzzahlen in Vektorregs zu übergeben, da SSE2 mit Ganzzahlen arbeiten kann. Zum Glück haben sie das nicht getan. Ganzzahlen werden sehr oft als Zeiger-Offsets verwendet, und ein Roundtrip zum Stapelspeicher ist ziemlich billig . Außerdem benötigen SSE2-Anweisungen mehr Codebytes als Ganzzahlanweisungen.


Ich vermute, Windows ABI-Designer haben möglicherweise versucht, Unterschiede zwischen 32 und 64 Bit zu minimieren, um Menschen zu helfen, die asm von einem zum anderen portieren müssen oder #ifdefin einigen ASMs ein paar s verwenden können, damit dieselbe Quelle einfacher erstellt werden kann eine 32- oder 64-Bit-Version einer Funktion.

Das Minimieren von Änderungen in der Toolchain scheint unwahrscheinlich. Ein x86-64-Compiler benötigt eine separate Tabelle, deren Register für was verwendet wird und wie die aufrufende Konvention lautet. Eine kleine Überlappung mit 32 Bit führt wahrscheinlich nicht zu erheblichen Einsparungen bei der Größe / Komplexität des Toolchain-Codes.

Peter Cordes
quelle
1
Ich glaube, ich habe irgendwo in Raymond Chens Blog über die Gründe für die Auswahl dieser Register nach dem Benchmarking von MS-Seite gelesen, aber ich kann sie nicht mehr finden. Einige Gründe bezüglich der Homezone wurden jedoch hier erläutert. Blogs.msdn.microsoft.com/oldnewthing/20160623-00/?p=93735 blogs.msdn.microsoft.com/freik/2006/03/06/…
phuclv
@phuclv: Siehe auch Ist es gültig, unter ESP zu schreiben? . Die Kommentare von Raymond zu meiner Antwort dort wiesen auf einige SEH-Details hin, von denen ich nicht wusste, warum x86 32/64 Windows derzeit keine de facto rote Zone hat. Sein Blog-Beitrag enthält einige plausible Fälle für dieselbe Code-Page-In-Handler-Möglichkeit, die ich in dieser Antwort erwähnt habe :) Also ja, Raymond hat es besser erklärt als ich (nicht überraschend, weil ich anfing, sehr wenig über Windows zu wissen). und die Tabelle der Rotzonengrößen für Nicht-x86 ist wirklich ordentlich.
Peter Cordes
13

Denken Sie daran, dass Microsoft anfangs "offiziell unverbindlich gegenüber den frühen AMD64-Bemühungen" war (aus "Eine Geschichte des modernen 64-Bit-Computing" von Matthew Kerner und Neil Padgett), weil sie starke Partner von Intel in Bezug auf die IA64-Architektur waren. Ich denke, dies bedeutete, dass sie, selbst wenn sie sonst offen gewesen wären, mit GCC-Ingenieuren an einem ABI zu arbeiten, um sowohl unter Unix als auch unter Windows zu arbeiten, dies nicht getan hätten, da dies bedeuten würde, die AMD64-Bemühungen öffentlich zu unterstützen, wenn sie dies nicht getan hätten. Dies wurde noch nicht offiziell getan (und hätte Intel wahrscheinlich verärgert).

Darüber hinaus hatte Microsoft damals absolut keine Lust, mit Open-Source-Projekten befreundet zu sein. Mit Sicherheit nicht Linux oder GCC.

Warum hätten sie bei einem ABI zusammengearbeitet? Ich würde vermuten, dass die ABIs einfach deshalb unterschiedlich sind, weil sie mehr oder weniger zur gleichen Zeit und isoliert entworfen wurden.

Ein weiteres Zitat aus "Eine Geschichte des modernen 64-Bit-Computing":

Parallel zur Microsoft-Zusammenarbeit beauftragte AMD die Open-Source-Community mit der Vorbereitung des Chips. AMD beauftragte Code Sorcery und SuSE mit der Arbeit an der Werkzeugkette (Red Hat wurde bereits von Intel für den IA64-Werkzeugkettenport beauftragt). Russell erklärte, dass SuSE C- und FORTRAN-Compiler und Code Sorcery einen Pascal-Compiler produzierte. Weber erklärte, dass das Unternehmen auch mit der Linux-Community zusammengearbeitet habe, um einen Linux-Port vorzubereiten. Diese Bemühungen waren sehr wichtig: Sie waren ein Anreiz für Microsoft, weiterhin in die AMD64-Windows-Bemühungen zu investieren, und stellten auch sicher, dass Linux, das zu dieser Zeit zu einem wichtigen Betriebssystem wurde, verfügbar sein würde, sobald die Chips veröffentlicht wurden.

Weber geht so weit zu sagen, dass die Linux-Arbeit für den Erfolg von AMD64 absolut entscheidend war, da AMD bei Bedarf ein End-to-End-System ohne die Hilfe anderer Unternehmen herstellen konnte. Diese Möglichkeit stellte sicher, dass AMD eine Überlebensstrategie im schlimmsten Fall hatte, selbst wenn andere Partner zurücktraten, was wiederum die anderen Partner aus Angst, zurückgelassen zu werden, engagierte.

Dies zeigt, dass selbst AMD nicht der Meinung war, dass die Zusammenarbeit zwischen MS und Unix unbedingt das Wichtigste ist, dass jedoch die Unterstützung von Unix / Linux sehr wichtig ist. Vielleicht war sogar der Versuch, eine oder beide Seiten zu Kompromissen oder Zusammenarbeit zu überreden, die Mühe oder das Risiko (?) Nicht wert, eine von beiden zu irritieren? Vielleicht dachte AMD, dass selbst das Vorschlagen eines gemeinsamen ABI das wichtigere Ziel, den Software-Support einfach bereit zu halten, wenn der Chip fertig ist, verzögern oder entgleisen könnte.

Spekulationen meinerseits, aber ich denke, der Hauptgrund, warum die ABIs unterschiedlich sind, war der politische Grund, warum MS und die Unix / Linux-Seiten einfach nicht zusammengearbeitet haben, und AMD sah das nicht als Problem an.

Michael Burr
quelle
Schöne Perspektive auf die Politik. Ich bin damit einverstanden, dass es nicht AMDs Schuld oder Verantwortung ist. Ich beschuldige Microsoft, eine schlechtere Anrufkonvention gewählt zu haben. Wenn sich ihre Calling-Konvention als besser herausgestellt hätte, hätte ich ein gewisses Mitgefühl, aber sie mussten von ihrem ursprünglichen ABI zu wechseln, __vectorcallweil das Weitergeben __m128des Stapels scheiße war. Es ist auch seltsam, eine aufruferhaltene Semantik für die niedrigen 128b einiger Vektorregs zu haben (teilweise Intels Fehler, keinen erweiterbaren Speicher- / Wiederherstellungsmechanismus mit SSE ursprünglich und immer noch nicht mit AVX zu entwerfen.)
Peter Cordes
1
Ich habe keine Erfahrung oder Kenntnisse darüber, wie gut die ABIs sind. Ich muss nur gelegentlich wissen, was sie sind, damit ich sie auf Assembly-Ebene verstehen / debuggen kann.
Michael Burr
1
Ein guter ABI minimiert die Codegröße und die Anzahl der Anweisungen und hält die Abhängigkeitsketten niedrig, da zusätzliche Roundtrips durch den Speicher vermieden werden. (für Args oder für Einheimische, die verschüttet / neu geladen werden müssen). Es gibt Kompromisse. Die rote Zone von SysV benötigt ein paar zusätzliche Anweisungen an einer Stelle (dem Signal-Handler-Dispatcher des Kernels), um einen relativ großen Vorteil für Blattfunktionen zu erzielen, da der Stapelzeiger nicht angepasst werden muss, um etwas Arbeitsbereich zu erhalten. Das ist also ein klarer Gewinn mit einem Nachteil nahe Null. Es wurde so gut wie ohne Diskussion angenommen, nachdem es für SysV vorgeschlagen wurde.
Peter Cordes
1
@dgnuff: Richtig, dass die Antwort auf ist Warum kann Kernel - Code verwendet eine Red Zone . Interrupts verwenden den Kernel-Stack und nicht den User-Space-Stack, selbst wenn sie eintreffen, wenn auf der CPU User-Space-Code ausgeführt wird. Der Kernel vertraut User-Space-Stacks nicht, da ein anderer Thread im selben User-Space-Prozess ihn ändern und so die Kontrolle über den Kernel übernehmen könnte!
Peter Cordes
1
@ DavidA.Gray: ja, wird das ABI nicht sagen , Sie haben RBP als Frame - Zeiger zu verwenden , so in der Regel optimierte Code nicht (außer in Funktionen , dass die Verwendung allocaoder ein paar andere Fälle). Dies ist normal, wenn Sie es gewohnt sind, gcc -fomit-frame-pointerunter Linux die Standardeinstellung zu sein. Der ABI definiert Stack-Unwind-Metadaten, mit denen die Ausnahmebehandlung weiterhin funktioniert. (Ich nehme an, es funktioniert so etwas wie das CFI-Zeug von GNU / Linux x86-64 System V .eh_frame). gcc -fomit-frame-pointerist seit jeher die Standardeinstellung (mit aktivierter Optimierung) auf x86-64, und andere Compiler (wie MSVC) tun dasselbe.
Peter Cordes
12

Win32 hat seine eigenen Verwendungszwecke für ESI und EDI und erfordert, dass sie nicht geändert werden (oder zumindest wiederhergestellt werden, bevor die API aufgerufen wird). Ich würde mir vorstellen, dass 64-Bit-Code dasselbe mit RSI und RDI macht, was erklären würde, warum sie nicht zum Weitergeben von Funktionsargumenten verwendet werden.

Ich konnte Ihnen jedoch nicht sagen, warum RCX und RDX umgeschaltet werden.

cHao
quelle
1
Alle aufrufenden Konventionen haben einige Register, die als Scratch bezeichnet sind, und einige, die wie ESI / EDI und RSI / RDI unter Win64 erhalten bleiben. Aber das sind Allzweckregister, die Microsoft ohne Probleme hätte wählen können, um sie anders zu verwenden.
JanKanis
1
@Somejan: Sicher, wenn sie die gesamte API neu schreiben und zwei verschiedene Betriebssysteme haben wollten. Ich würde das allerdings nicht "ohne Probleme" nennen. Seit Dutzenden von Jahren hat MS bestimmte Versprechungen gemacht, was mit x86-Registern geschehen soll und was nicht, und sie waren die ganze Zeit über mehr oder weniger konsistent und kompatibel. Sie werden das alles nicht aus dem Fenster werfen, nur wegen eines Edikts von AMD, insbesondere eines, das so willkürlich ist und außerhalb des Bereichs des "Bauens eines Prozessors" liegt.
CHao
5
@Somejan: Der AMD64 UN * X ABI war immer genau das - ein UNIX-spezifisches Stück. Das Dokument x86-64.org/documentation/abi.pdf trägt aus einem bestimmten Grund den Titel System V Application Binary Interface, AMD64 Architecture Processor Supplement . Die (allgemeinen) UNIX-ABIs (eine Sammlung mit mehreren Volumes, sco.com/developers/devspecs ) hinterlassen einen Abschnitt für prozessorspezifisches Kapitel 3 - das Supplement -, in dem die Konventionen für Funktionsaufrufe und Datenlayoutregeln für einen bestimmten Prozessor aufgeführt sind.
FrankH.
7
@Somejan: Microsoft Windows hat nie versucht, UN * X besonders nahe zu kommen, und als es darum ging, Windows auf x64 / AMD64 zu portieren, haben sie einfach beschlossen, ihre eigene __fastcall Aufrufkonvention zu erweitern . Sie behaupten , Win32 / Win64 nicht kompatibel sind, aber dann genau hinsehen: Eine Funktion , die dauert zwei 32bit 32bit args und kehrt, Win64 und Win32 __fastcalltatsächlich ist 100% kompatibel (gleiche regs für das Bestehen zwei 32 - Bit - args, gleicher Rückgabewert). Sogar ein binärer (!) Code kann in beiden Betriebsarten funktionieren. Die UNIX-Seite hat völlig mit "alten Methoden" gebrochen. Aus guten Gründen, aber eine Pause ist eine Pause.
FrankH.
2
@Olof: Es ist mehr als nur eine Compilersache. Ich hatte Probleme mit ESI und EDI, als ich eigenständige Sachen in NASM gemacht habe. Windows kümmert sich definitiv um diese Register. Aber ja, Sie können sie verwenden, wenn Sie sie vor dem Speichern speichern und wiederherstellen, bevor Windows sie benötigt.
CHao