Scelta di quattro registri di argomenti su x64 - comune a UN * X / Win64
Una delle cose da tenere a mente riguardo a x86 è che il nome del registro per la codifica "numero di registro" non è ovvio; in termini di codifica dell'istruzione (il byte MOD R / M , vedere http://www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm ), i numeri di registro 0 ... 7 sono - in quest'ordine - ?AX, ?CX, ?DX, ?BX, ?SP, ?BP, ?SI, ?DI.
Quindi scegliere A / C / D (regs 0..2) per il valore di ritorno e i primi due argomenti (che è la __fastcallconvenzione "classica" a 32 bit ) è una scelta logica. Per quanto riguarda i 64 bit, vengono ordinati i reg "superiori", e sia Microsoft che UN * X / Linux hanno scelto R8/ R9come primi.
Tenendo questo in mente, la scelta di Microsoft di RAX(valore di ritorno) e RCX, RDX, R8, R9(arg [0..3]) sono una scelta comprensibile se si sceglie quattro registri per argomenti.
Non so perché l'AMD64 UN * X ABI abbia scelto RDXprima RCX.
Scelta di sei registri di argomenti su x64 - UN * X specifico
UN * X, su architetture RISC, ha tradizionalmente eseguito il passaggio di argomenti nei registri, in particolare per i primi sei argomenti (almeno così su PPC, SPARC, MIPS). Questo potrebbe essere uno dei motivi principali per cui i progettisti ABI AMD64 (UN * X) hanno scelto di utilizzare anche sei registri su quell'architettura.
Quindi, se volete sei registri per passare argomenti, ed è logico scegliere RCX, RDX, R8e R9per quattro di loro, che altri due si dovrebbe scegliere?
I reg "più alti" richiedono un byte di prefisso dell'istruzione aggiuntivo per selezionarli e quindi hanno un'impronta di dimensione dell'istruzione maggiore, quindi non vorresti sceglierne nessuna se hai delle opzioni. Dei registri classici, per il significato implicito di RBPe RSPquesti non sono disponibili, e RBXtradizionalmente ha un uso speciale su UN * X (tabella di offset globale) con cui apparentemente i progettisti ABI di AMD64 non volevano diventare inutilmente incompatibili.
Ergo, l' unica scelta era RSI/ RDI.
Quindi, se devi prendere RSI/ RDIcome registro degli argomenti, quali argomenti dovrebbero essere?
Farli arg[0]e arg[1]ha alcuni vantaggi. Vedi il commento di cHao.
?SIe ?DIsono operandi sorgente / destinazione di istruzioni di stringa e, come menzionato da cHao, il loro uso come registri di argomenti significa che con le convenzioni di chiamata UN * X di AMD64, la strcpy()funzione più semplice possibile , ad esempio, consiste solo delle due istruzioni della CPU repz movsb; retperché l'origine / destinazione gli indirizzi sono stati inseriti nei registri corretti dal chiamante. Esiste, in particolare nel codice "collante" generato dal compilatore e di basso livello (si pensi, ad esempio, ad alcuni allocatori di heap C ++ oggetti che riempiono zero durante la costruzione, o le pagine heap che riempiono lo zero del kernel susbrk(), o copy-on-write pagefaults) un'enorme quantità di block copy / fill, quindi sarà utile per il codice così frequentemente usato per salvare le due o tre istruzioni della CPU che altrimenti caricherebbero tali argomenti di indirizzo di origine / destinazione nel registri "corretti".
Quindi, in un certo senso, UN * X e Win64 sono diversi solo in quella UN * X "antepone" due argomenti aggiuntivi, in volutamente scelti RSI/ RDIregistri, per la scelta naturale di quattro argomenti a RCX, RDX, R8e R9.
Oltre a questo ...
Esistono più differenze tra le ABI UN * X e Windows x64 oltre alla semplice mappatura degli argomenti a registri specifici. Per la panoramica su Win64, controlla:
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64 e AMD64 UN * X differiscono notevolmente anche nel modo in cui viene utilizzato lo stackspace; su Win64, ad esempio, il chiamante deve allocare lo spazio dello stack per gli argomenti della funzione anche se gli argomenti 0 ... 3 vengono passati nei registri. Su UN * X d'altra parte, una funzione foglia (cioè una che non chiama altre funzioni) non è nemmeno richiesta per allocare lo spazio dello stack se non ha bisogno di più di 128 byte di esso (sì, tu possiedi e puoi usare una certa quantità di stack senza allocare ... beh, a meno che tu non sia codice del kernel, una fonte di bug ingegnosi). Tutte queste sono scelte di ottimizzazione particolari, la maggior parte delle ragioni per queste è spiegata nei riferimenti ABI completi a cui fa riferimento il riferimento di wikipedia del poster originale.