Wybór czterech rejestrów argumentów na x64 - wspólny dla UN * X / Win64
Jedną z rzeczy, o których należy pamiętać w przypadku x86, jest to, że nazwa rejestru do kodowania „numeru rejestru” nie jest oczywista; pod względem kodowania instrukcji ( bajt MOD R / M , patrz http://www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm ), numery rejestrów 0 ... 7 są - w tej kolejności - ?AX
, ?CX
, ?DX
, ?BX
, ?SP
, ?BP
, ?SI
, ?DI
.
Dlatego wybranie A / C / D (regs 0..2) jako wartości zwracanej i pierwszych dwóch argumentów (co jest "klasyczną" __fastcall
konwencją 32-bitową ) jest logicznym wyborem. Jeśli chodzi o wersję 64-bitową, zamawiane są „wyższe” regy, a Microsoft i UN * X / Linux wybrali R8
/ R9
jako pierwsi.
Mając to na uwadze, wybór przez Microsoft RAX
(wartości zwracanej) oraz RCX
, RDX
, R8
, R9
(arg [0..3]) są zrozumiałe wybór jeśli zdecydujesz cztery rejestry argumentów.
Nie wiem, dlaczego AMD64 UN * X ABI wybrało RDX
wcześniej RCX
.
Wybór sześciu rejestrów argumentowych na x64 - specyficzny dla UN * X
UN * X, na architekturach RISC, tradycyjnie przekazywał argumenty w rejestrach - konkretnie dla pierwszych sześciu argumentów (tak jest przynajmniej w przypadku PPC, SPARC, MIPS). Co może być jednym z głównych powodów, dla których projektanci AMD64 (UN * X) ABI zdecydowali się na użycie sześciu rejestrów również w tej architekturze.
Więc jeśli chcesz sześć rejestrów przekazać argumenty, i to jest logiczne, aby wybrać RCX
, RDX
, R8
a R9
dla czterech z nich, co dwa pozostałe należy wybrać?
„Wyższe” rejestry wymagają dodatkowego bajtu przedrostka instrukcji, aby je wybrać i dlatego mają większy rozmiar instrukcji, więc nie chciałbyś wybierać żadnej z nich, jeśli masz opcje. Z klasycznych rejestrów, ze względu na ukryte znaczenie RBP
i RSP
nie są one dostępne, a RBX
tradycyjnie ma specjalne zastosowanie w UN * X (globalna tabela offsetów), z którymi najwyraźniej projektanci AMD64 ABI nie chcieli niepotrzebnie stać się niekompatybilnymi.
Ergo, jedynym wyborem były RSI
/ RDI
.
Więc jeśli musisz wziąć RSI
/ RDI
jako rejestry argumentów, jakie powinny to być argumenty?
Wykonanie ich arg[0]
i arg[1]
ma pewne zalety. Zobacz komentarz cHao.
?SI
i ?DI
są operandami źródłowymi / docelowymi instrukcji łańcuchowych, a jak wspomniało cHao, ich użycie jako rejestrów argumentów oznacza, że w przypadku konwencji wywoływania AMD64 UN * X najprostsza możliwa strcpy()
funkcja składa się na przykład tylko z dwóch instrukcji procesora, repz movsb; ret
ponieważ źródło / cel adresy zostały wprowadzone przez dzwoniącego do odpowiednich rejestrów. Występuje, szczególnie w niskopoziomowym i generowanym przez kompilator kodzie „klejowym” (pomyśl, na przykład, niektóre alokatory sterty w C ++ wypełniające zerami obiekty w konstrukcji lub strony jądra wypełniające stertysbrk()
lub błędy stronicowania przy kopiowaniu przy zapisie) ogromną ilość kopiowania / wypełniania bloków, dlatego będzie to przydatne w przypadku kodu tak często używanego do zapisywania dwóch lub trzech instrukcji procesora, które w przeciwnym razie ładowałyby takie argumenty adresu źródłowego / docelowego do „prawidłowe” rejestry.
Więc w pewnym sensie, UN * X i Win64 różnią się tylko tym, że UN * X „wstawia” dwa dodatkowe argumenty, w celowo wybranych RSI
/ RDI
rejestrów, z naturalnym wyborem cztery argumenty RCX
, RDX
, R8
i R9
.
Ponadto ...
Istnieje więcej różnic między interfejsami ABI UN * X i Windows x64 niż tylko mapowanie argumentów do określonych rejestrów. Aby zapoznać się z przeglądem systemu Win64, sprawdź:
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64 i AMD64 UN * X również uderzająco różnią się sposobem wykorzystania przestrzeni stosowej; na przykład w Win64 wywołujący musi przydzielić przestrzeń stosu dla argumentów funkcji, mimo że argumenty 0 ... 3 są przekazywane w rejestrach. Z drugiej strony w UN * X funkcja liścia (tj. Taka, która nie wywołuje innych funkcji) nie jest nawet wymagana do przydzielania miejsca na stosie, jeśli nie potrzebuje więcej niż 128 bajtów (tak, posiadasz i możesz używać pewna ilość stosu bez przydzielania go ... no chyba, że jesteś kodem jądra, źródłem sprytnych błędów). Wszystko to są określone wybory optymalizacyjne, większość ich uzasadnienia jest wyjaśniona w pełnych odniesieniach ABI, na które wskazuje wikipedia pierwotnego postu.