x86 çağrı kuralları - x86 calling conventions

Bu makalede, x86 mimarisi mikroişlemcileri programlanırken kullanılan çağrı kuralları açıklanmaktadır .

Çağrı kuralları, çağrılan kodun arayüzünü tanımlar:

  • Atomik (skaler) parametrelerin veya karmaşık bir parametrenin ayrı bölümlerinin tahsis edildiği sıra
  • Parametreler nasıl geçirilir (yığına gönderilir, kayıtlara yerleştirilir veya her ikisinin karışımı)
  • Çağrılan işlevin arayan için saklaması gereken kayıtlar (aynı zamanda: callee tarafından kaydedilen kayıtlar veya geçici olmayan kayıtlar olarak da bilinir)
  • Yığını bir işlev çağrısı için hazırlama ve sonrasında geri yükleme görevi, arayan ve aranan arasında nasıl bölünür?

Bu, programlama dili türlerine boyutların ve biçimlerin atanmasıyla yakından ilgilidir. Bir diğer yakından ilgili konu, koddaki sembol adlarının bağlayıcı tarafından kullanılan sembol adlarıyla nasıl eşleştiğini belirleyen ad yönetimidir. Çağrı kuralları, tür temsilleri ve ad yönetimi, uygulama ikili arabirimi (ABI) olarak bilinen şeyin bir parçasıdır .

Çeşitli derleyicilerin bu kuralları nasıl uyguladıkları konusunda genellikle küçük farklılıklar vardır, bu nedenle farklı derleyiciler tarafından derlenen kodun arabirimini oluşturmak genellikle zordur. Öte yandan, bir API standardı olarak kullanılan (stdcall gibi) konvansiyonlar çok düzgün bir şekilde uygulanmaktadır.

Tarihsel arka plan

Mikrobilgisayarlardan önce , makine üreticisi genellikle çeşitli programlama dilleri için bir işletim sistemi ve derleyiciler sağlıyordu . Çağırma kuralı her platform için (ler) üreticinin programlama araçları tarafından tanımlanan bileşiklerdir.

Commodore Pet ve Apple II'den önceki ilk mikro bilgisayarlar genellikle bir işletim sistemi veya derleyici olmadan geldi. IBM PC , Windows, Disk İşletim Sistemi (Microsoft'un ön-koşucu ile geldi DOS ), ama bir derleyici ile gelmedi. IBM PC uyumlu makineler için tek donanım standardı , Intel işlemciler (8086, 80386) ve IBM'in sunduğu gerçek donanım tarafından tanımlandı . Donanım uzantıları ve tüm yazılım standartları ( BIOS çağrı kuralı hariç) pazar rekabetine açık hale getirildi.

Çok sayıda bağımsız yazılım firması, birçok programlama dili için işletim sistemleri, derleyiciler ve uygulamalar sundu. Firmalar tarafından, farklı gereksinimlere, tarihsel uygulamalara ve programcı yaratıcılığına dayalı olarak, genellikle birbirini dışlayan birçok farklı arama şeması uygulandı.

IBM uyumlu pazar sarsıntısından sonra, Microsoft işletim sistemleri ve programlama araçları (farklı sözleşmelere sahip) hakim olurken, Borland ve Novell gibi ikinci kademe firmalar ve GCC gibi açık kaynaklı projeler hala kendi standartlarını koruyorlardı. Satıcılar ve ürünler arasındaki birlikte çalışabilirlik hükümleri sonunda kabul edildi ve uygulanabilir bir sözleşme seçme sorununu basitleştirdi.

arayan temizleme

Bu kurallarda, çağıran argümanları yığından temizler.

cdecl

Cdecl (açılımı C beyanı ) için Microsoft'un derleyici kaynaklanır ki çağıran kuralıdır C programlama dili ve birçok C derleyicileri tarafından kullanılan x86 mimarisi . cdecl'de, altyordam argümanları yığına iletilir . Tamsayı değerleri ve bellek adresleri, EAX kaydında , kayan nokta değerleri ise ST0 x87 kaydında döndürülür . EAX, ECX ve EDX kayıtları arayan tarafından kaydedilir ve geri kalanı arananlar tarafından kaydedilir. Yeni bir işlev çağrılırken ST0 ila ST7 arasındaki x87 kayan nokta kayıtları boş ( açılmış veya serbest bırakılmış) olmalıdır ve bir işlevden çıkarken ST1 ila ST7 boş olmalıdır. ST0 ayrıca bir değer döndürmek için kullanılmadığında da boş olmalıdır.

C programlama dili bağlamında, fonksiyon argümanları sağdan sola sırayla yığın üzerinde itilir, yani ilk önce son argüman itilir.

Aşağıdaki C kaynak kodu parçacığını göz önünde bulundurun:

int callee(int, int, int);

int caller(void)
{
	return callee(1, 2, 3) + 5;
}

Açık x86 , aşağıdaki doğurabileceğini montaj kodu ( Intel sözdizimi ):

caller:
    ; make new call frame
    ; (some compilers may produce an 'enter' instruction instead)
    push    ebp       ; save old call frame
    mov     ebp, esp  ; initialize new call frame
    ; push call arguments, in reverse
    ; (some compilers may subtract the required space from the stack pointer,
    ; then write each argument directly, see below.
    ; The 'enter' instruction can also do something similar)
    ; sub esp, 12      : 'enter' instruction could do this for us
    ; mov [ebp-4], 3   : or mov [esp+8], 3
    ; mov [ebp-8], 2   : or mov [esp+4], 2
    ; mov [ebp-12], 1  : or mov [esp], 1
    push    3
    push    2
    push    1
    call    callee    ; call subroutine 'callee'
    add     esp, 12   ; remove call arguments from frame
    add     eax, 5    ; modify subroutine result
                      ; (eax is the return value of our callee,
                      ; so we don't have to move it into a local variable)
    ; restore old call frame
    ; (some compilers may produce a 'leave' instruction instead)
    mov     esp, ebp  ; most calling conventions dictate ebp be callee-saved,
                      ; i.e. it's preserved after calling the callee.
                      ; it therefore still points to the start of our stack frame.
                      ; we do need to make sure
                      ; callee doesn't modify (or restores) ebp, though,
                      ; so we need to make sure
                      ; it uses a calling convention which does this
    pop     ebp       ; restore old call frame
    ret               ; return

Arayan, işlev çağrısı döndükten sonra yığını temizler.

Cdecl çağırarak kongre genellikle x86 C için varsayılan çağıran konvansiyonudur derleyici birçok derleyiciler otomatik olarak kullanılır arama kuralları değiştirmek için seçenekler sunar rağmen,. Bir işlevi cdecl olarak manuel olarak tanımlamak için bazıları aşağıdaki sözdizimini destekler:

return_type __cdecl func_name();

Varyasyonlar

cdecl'nin yorumlanmasında bazı farklılıklar vardır. Sonuç olarak, farklı işletim sistemi platformları için ve/veya farklı derleyiciler tarafından derlenen x86 programları, her ikisi de "cdecl" kuralını kullansa ve temel ortama çağrı yapmasalar bile uyumsuz olabilir.

Değerlerin nasıl döndürüleceğiyle ilgili olarak, bazı derleyiciler, EAX:EDX kayıt çiftinde 2 veya daha az kayıt uzunluğunda basit veri yapıları ve istisna işleyicisi tarafından özel muamele gerektiren daha büyük yapılar ve sınıf nesneleri (örneğin, tanımlanmış bir kurucu, yıkıcı veya atama) bellekte döndürülür. "Hafızada" geçmek için, arayan kişi bellek ayırır ve ona gizli bir ilk parametre olarak bir işaretçi iletir; aranan kişi belleği doldurur ve işaretçiyi döndürür, dönerken gizli işaretçiyi ortaya çıkarır.

In Linux , GCC setleri fiili kuralları çağırmak için standart. GCC sürüm 4.5'ten bu yana, bir işlev çağrılırken yığının 16 baytlık bir sınıra hizalanması gerekir (önceki sürümler yalnızca 4 baytlık bir hizalama gerektiriyordu).

Bir cdecl sürümü, i386 sistemleri için System V ABI'de açıklanmıştır.

sistem çağrısı

Bu, argümanların sağdan sola itilmesi bakımından cdecl'ye benzer. EAX, ECX ve EDX korunmaz. Parametre listesinin doublewords cinsinden boyutu AL'de iletilir.

Sistem çağrısı, 32 bit OS/2 API için standart çağrı kuralıdır .

optlink

Argümanlar sağdan sola itilir. İlk üç (en soldaki) argüman EAX, EDX ve ECX'te geçirilir ve ST0'dan ST3'e kadar dört kayan nokta argümanı iletilir, ancak bunlar için yığındaki argüman listesinde yer ayrılmıştır. Sonuçlar EAX veya ST0 olarak döndürülür. EBP, EBX, ESI ve EDI kayıtları korunur.

Optlink, IBM VisualAge derleyicileri tarafından kullanılır .

callee temizliği

Bu sözleşmelerde, aranan kişi yığındaki argümanları temizler. Bu kuralları kullanan işlevlerin ASM kodunda tanınması kolaydır, çünkü döndükten sonra yığını çözerler. x86 ret komutu, arayana döndükten sonra bırakılacak yığın bayt sayısını belirten isteğe bağlı 16 bitlik bir parametreye izin verir. Böyle bir kod şöyle görünür:

ret 12

Sözleşmeleri başlıklı fastcall veya kayıt standardize edilmemiştir ve derleyici satıcı bağlı olarak farklı uygulanmaktadır. Tipik olarak, kayıt tabanlı çağrı kuralları, çağrı için gereken bellek erişimlerinin sayısını azaltan ve böylece onları genellikle daha hızlı hale getiren kayıtlarda bir veya daha fazla argüman iletir.

paskalya

Dayanarak Borland Pascal programlama dilinin çağrı kuralı, parametreler soldan sağa sırayla (CDECL tersi) 'de yığına ve callee yığınından çıkardıktan sorumludur edilir.

Sonucu döndürmek şu şekilde çalışır:

  • Sıra değerleri AL (8 bit değerler), AX (16 bit değerler), EAX (32 bit değerler) veya DX:AX (16 bit sistemlerde 32 bit değerler) olarak döndürülür.
  • Gerçek değerler DX:BX:AX olarak döndürülür.
  • Kayan nokta (8087) değerleri ST0'da döndürülür.
  • İşaretçiler, 32 bit sistemlerde EAX'te ve 16 bit sistemlerde AX'te döndürülür.
  • Dizeler, @Result simgesiyle gösterilen geçici bir konumda döndürülür.

Bu çağrı kuralı aşağıdaki 16 bit API'lerde yaygındı: OS/2 1.x, Microsoft Windows 3.x ve Borland Delphi sürüm 1.x. Windows API'sinin modern sürümleri stdcall kullanır ; bu, arananın Pascal kuralında olduğu gibi yığını geri yüklemesini sağlar, ancak parametreler artık sağdan sola itilir.

standart çağrı

stdcall çağrı kuralı, arananın yığını temizlemekten sorumlu olduğu Pascal çağrı kuralının bir varyasyonudur, ancak parametreler _cdecl çağrı kuralında olduğu gibi sağdan sola sırayla yığına itilir. EAX, ECX ve EDX registerleri, fonksiyon içinde kullanılmak üzere belirlenmiştir. Dönüş değerleri EAX kaydında saklanır.

stdcall, Microsoft Win32 API ve Open Watcom C++ için standart çağrı kuralıdır .

Microsoft hızlı arama

Microsoft __fastcall kuralı (aka __msfastcall ), ECX ve EDX'e uyan ilk iki bağımsız değişkeni (soldan sağa değerlendirilir) geçirir. Kalan argümanlar yığına sağdan sola doğru itilir. Derleyici IA64 veya AMD64 için derlendiğinde , __fastcall anahtar sözcüğünü yok sayar ve bunun yerine tek 64 bitlik çağrı kuralını kullanır.

Bu çok yaygın bir çağrı kuralı olduğundan, GCC, Clang ve ICC gibi diğer derleyiciler de hızlı aramayı destekler.

Aşağıdaki C snippet'ini göz önünde bulundurun:

__attribute__((fastcall)) void printnums(int num1, int num2, int num3){
	printf("The numbers you sent are: %d %d %d", num1, num2, num3);
}

int main(){
	printnums(1, 2, 3);
	return 0;
}

ana işlevin x86 ayrıştırması şöyle görünecektir (Intel sözdiziminde):

main:
	; stack setup
	push ebp
	mov ebp, esp
	push 3 ; immediate 3 (third argument is pushed to the stack)
	mov edx, 0x2 ; immediate 2 (second argument) is copied to edx register.
	mov ecx, 0x1 ; immediate 1 (first argument) is copied to ecx register.
	call printnums
	mov eax, 0 ; return 0
	leave
	retn

İlk iki argüman soldan sağa sırayla iletilir ve üçüncü argüman yığına itilir. Yığın temizleme, aranan tarafından gerçekleştirildiğinden yığın temizleme yoktur. Callee fonksiyonunun demontajı şu şekildedir:

printnums:
	; stack setup
	push ebp
	mov ebp, esp
	sub esp, 0x08
	mov [ebp-0x04], ecx    ; in x86, ecx = first argument.
	mov [ebp-0x08], edx    ; arg2
	push [ebp+0x08]        ; arg3 is pushed to stack.
	push [ebp-0x08]        ; arg2 is pushed
	push [ebp-0x04]        ; arg1 is pushed
	push 0x8065d67         ; "The numbers you sent are %d %d %d"
	call printf
	; stack cleanup
	add esp, 0x10
	nop
	leave
	retn 0x04

İki argüman kayıtlardan geçirildiğinden ve yığına yalnızca bir parametre itildiğinden, x86 sistemlerinde int boyutu 4 bayt olduğundan, itilen değer retn komutu tarafından temizlenir.

Microsoft vektör çağrısı

Visual Studio 2013'te Microsoft , oyun, grafik, video/ses ve kodek geliştiricilerinden gelen verimlilik endişelerine yanıt olarak __vectorcall çağrı kuralını tanıttı . Şema , yığın yerine yazmaçlarda daha büyük vektör türlerinin ( float , double , __m128 , __m256 ) geçirilmesine izin verir .

IA-32 ve x64 kodu için __vectorcall , sırasıyla __fastcall ve orijinal x64 çağırma kurallarına benzer , ancak bunları SIMD kayıtlarını kullanarak vektör argümanlarının iletilmesini destekleyecek şekilde genişletir . IA-32'de, tamsayı değerleri her zamanki gibi iletilir ve ilk altı SIMD ( XMM / YMM 0-5) kaydı, gerçek konumlardan bağımsız olarak soldan sağa sıralı olarak altı adede kadar kayan nokta, vektör veya HVA değeri tutar. neden, örneğin aralarında görünen bir int argümanı. Bununla birlikte, x64'te, orijinal x64 kuralından gelen kural hala geçerlidir, böylece XMM/YMM0-5, altıncıdan birinciye kadar olduklarında yalnızca kayan nokta, vektör veya HVA bağımsız değişkenlerini tutar.

__vectorcall , aynı altı kaydı kullanarak yalnızca en fazla dört özdeş vektör türünden oluşan bileşik türler (yapılar) olan homojen vektör toplama (HVA) değerlerinin iletilmesi için destek ekler. Kayıtlar vektör tipi argümanlar için tahsis edildikten sonra, kullanılmayan kayıtlar soldan sağa HVA argümanlarına tahsis edilir. Konumlandırma kuralları hala geçerlidir. Ortaya çıkan vektör tipi ve HVA değerleri, ilk dört XMM/YMM kaydı kullanılarak döndürülür.

Clang derleyicisi ve Intel C++ derleyicisi de vektör çağrısını uygular. Intel C++ derleyicisinin __regcall adında benzer, daha önceki bir kuralı vardı ; aynı zamanda clang tarafından da desteklenir.

Borland kaydı

Argümanları soldan sağa değerlendirerek, EAX, EDX, ECX üzerinden üç argüman iletir. Kalan argümanlar da soldan sağa olmak üzere yığına itilir. Bu, register olarak bilinen 32-bit Delphi derleyicisinin varsayılan çağrı kuralıdır . Bu çağrı kuralı, Embarcadero'nun C++Builder'ı tarafından da kullanılır ve burada __fastcall olarak adlandırılır . Bu derleyici olarak, Microsoft'un fastcall olarak kullanılabilir __msfastcall .

GCC ve Clang __stdcall, regparmfunction niteliği veya -mregparm=3anahtar kullanılarak benzer bir çağrı kuralı kullanmak üzere yapılabilir . (Yığın sırası ters çevrilir.) Bir arayan temizleme varyantı üretmek cdeclveya bunu SSE kayıtlarını kullanacak şekilde genişletmek de mümkündür . Bir cdecltabanlı versiyonu sürümü 2.6.20 beri i386 üzerindeki Linux çekirdeğinin tarafından kullanılır (Şubat 2007'de yayınlanan).

Watcom kaydı

Watcom , __fastcall anahtar sözcüğünü boş olarak adlandırmak dışında desteklemez . Kayıt çağırma kuralı, komut satırı anahtarı ile seçilebilir. (Ancak, IDA tekdüzelik için yine de __fastcall kullanır .)

EAX, EDX, EBX, ECX sırasına göre argümanlara 4 adede kadar kayıt atanır. Bağımsız değişkenler kayıtlara soldan sağa atanır. Herhangi bir argüman bir kayda atanamazsa (çok büyük olduğunu söyleyin) ve sonraki tüm argümanlar yığına atanır. Yığına atanan argümanlar sağdan sola doğru itilir. İsimler, son ekli bir alt çizgi eklenerek karıştırılır.

Değişken işlevler, Watcom yığını tabanlı çağrı kuralına geri döner.

Watcom C/C++ derleyicisi ayrıca , kullanıcının kendi çağrı kurallarını belirlemesine izin veren #pragma aux yönergesini kullanır . El kitabında belirtildiği gibi, "Çok az kullanıcının bu yönteme ihtiyacı olması muhtemeldir, ancak gerekirse, bir cankurtaran olabilir".

TopSpeed ​​/ Clarion / JPI

İlk dört tamsayı parametresi eax, ebx, ecx ve edx kayıtlarında geçirilir. Kayan nokta parametreleri kayan nokta yığınına iletilir – st0, st1, st2, st3, st4, st5 ve st6 kayıtlarını yapar. Yapı parametreleri her zaman yığına iletilir. Kayıtlar tükendikten sonra yığına ek parametreler geçirilir. Tamsayı değerleri eax'ta, işaretçiler edx'te ve kayan nokta türleri st0'da döndürülür.

güvenli çağrı

In Delphi ve Free Pascal üzerinde Microsoft Windows , safecall çağrı kuralı kapsülleri COM ( Component Object Model ) hata işleme, böylece istisnalar arayana dışarı sızdırılmış değil, ancak raporlanır HRESULT COM / OLE gerektirdiği gibi, dönüş değeri. Delphi kodundan güvenli çağrı işlevi çağrılırken, Delphi ayrıca döndürülen HRESULT'u otomatik olarak kontrol eder ve gerekirse bir istisna oluşturur.

Güvenli çağrı çağrı kuralı, istisnaların EAX'te arayan kişiye HResult (FS:[0] yerine) olarak geri gönderilmesi dışında, stdcall çağrı kuralıyla aynıdır; son bir "çıkış" parametresi olmasına rağmen. Delphi'den bir Delphi işlevi çağrılırken, bu çağrı kuralı diğer çağrı kuralları gibi görünecektir, çünkü istisnalar EAX'te geri iletilse de, arayan tarafından otomatik olarak uygun istisnalara geri dönüştürülür. Diğer dillerde oluşturulan COM nesnelerini kullanırken, HResults istisna olarak otomatik olarak oluşturulur ve Get işlevlerinin sonucu bir parametre yerine sonuçta olur. Güvenli çağrı ile Delphi'de COM nesneleri oluştururken, istisnalar normal olarak ortaya çıkabileceğinden ancak diğer dillerde HResults olarak görüleceğinden, HResults hakkında endişelenmenize gerek yoktur.

function function_name(a: DWORD): DWORD; safecall;

Bir sonuç döndürür ve normal bir Delphi işlevi gibi istisnalar oluşturur, ancak değerleri ve istisnaları sanki şöyleymiş gibi iletir:

function function_name(a: DWORD; out Result: DWORD): HResult; stdcall;

Arayan veya aranan temizlik

bu çağrı

Bu çağırma kuralı, C++ statik olmayan üye işlevlerini çağırmak için kullanılır. Bu çağrının derleyiciye ve işlevin değişken sayıda argüman kullanıp kullanmadığına bağlı olarak kullanılan iki ana sürümü vardır .

GCC derleyicisi için, thiscall hemen hemen aynıdır CDECL arayan yığın temizler ve parametreler sağdan sola amacıyla geçirilir. Aradaki fark, fonksiyon prototipindeki ilk parametreymiş gibi yığına en son itilen this işaretçisinin eklenmesidir .

Microsoft Visual C ++ derleyicisi günü, bu işaretçi ECX içinde geçirilir ve öyle Aranan yansıtma yığını temizler stdcall bu derleyici ve Windows API fonksiyonları C'de kullanılan kongre. Fonksiyonlar değişken sayıda argüman kullandığında, yığını temizleyen çağırandır (cf. cdecl ).

Thiscall çağıran kongre sadece açıkça Microsoft Visual C ++ 2005 ve daha sonra belirtilebilir. Başka bir derleyicide bu çağrı bir anahtar sözcük değildir. (Ancak, IDA gibi sökücüler bunu belirtmelidir. Dolayısıyla IDA bunun için __thiscall anahtar sözcüğünü kullanır .)

Kayıt koruma

Çağırma kuralının başka bir kısmı, bir alt program çağrısından sonra hangi kayıtların değerlerini korumalarının garanti edildiğidir.

Arayanın kaydettiği (geçici) kayıtlar

Derleyicilerin büyük çoğunluğunun uyduğu Intel ABI'ye göre, EAX, EDX ve ECX, bir prosedür veya işlev içinde kullanım için serbesttir ve korunmaları gerekmez.

Adından da anlaşılacağı gibi, bu genel amaçlı kayıtlar genellikle herhangi bir alt program tarafından üzerine yazılabilen geçici (geçici) bilgileri tutar.

Bu nedenle, bir altyordam çağrısından sonra değerlerini geri yüklemek istiyorsa, bu kayıtların her birini yığına itmek arayan kişinin sorumluluğundadır.

Callee tarafından kaydedilen (geçici olmayan) kayıtlar

Diğer kayıtlar, çağrılar arasında korunması gereken uzun ömürlü değerleri (geçici olmayan) tutmak için kullanılır.

Başka bir deyişle, arayan bir prosedür çağrısı yaptığında, aranan kişi döndükten sonra bu kayıtların aynı değeri tutmasını bekleyebilir.

Böylece, arayana geri dönmeden önce onları hem kaydetmek (başta itmek) hem de geri yüklemek (buna göre açılır) arayan kişinin sorumluluğundadır. Bir önceki durumda olduğu gibi, bu uygulama sadece callee'nin değiştirdiği kayıtlar üzerinde yapılmalıdır.

x86-64 çağrı kuralları

x86-64 çağrı kuralları, kayıtlarda daha fazla argüman iletmek için ek kayıt alanından yararlanır. Ayrıca, uyumsuz çağrı kurallarının sayısı azaltılmıştır. Ortak kullanımda iki tane var.

Microsoft x64 çağrı kuralı

Microsoft x64 çağrı kuralı, Windows'ta ve önyükleme öncesi UEFI'de izlenir ( x86-64'te uzun mod için ). İlk dört argüman kayıtlara yerleştirilir. Bu, tamsayı, yapı veya işaretçi bağımsız değişkenleri (bu sırayla) için RCX, RDX, R8, R9 ve kayan nokta bağımsız değişkenleri için XMM0, XMM1, XMM2, XMM3 anlamına gelir. Ek argümanlar yığına gönderilir (sağdan sola). Tamsayı dönüş değerleri (x86'ya benzer), 64 bit veya daha az ise RAX'te döndürülür. Kayan nokta dönüş değerleri XMM0'da döndürülür. 64 bitten daha kısa olan parametreler sıfır uzatılmaz; yüksek bitler sıfırlanmaz.

Tamsayılarla eşleşen boyutlara sahip yapılar ve birlikler, tamsayılarmış gibi geçirilir ve döndürülür. Aksi takdirde, argüman olarak kullanıldığında bir işaretçi ile değiştirilirler. Büyük boyutlu bir yapı dönüşü gerektiğinde, arayan tarafından sağlanan alana başka bir işaretçi ilk argüman olarak eklenir ve diğer tüm argümanlar bir yer sağa kaydırılır.

Bir Windows bağlamında (Microsoft veya Microsoft dışı araçlar kullanarak) x64 mimarisini derlerken, stdcall, thiscall, cdecl ve fastcall bu kuralı kullanmaya karar verir.

Microsoft x64 çağrı kuralında, işlevi çağırmadan hemen önce yığında 32 baytlık "gölge alanı" ayırmak (kullanılan gerçek parametre sayısından bağımsız olarak) ve çağrıdan sonra yığını açmak, arayanın sorumluluğundadır. Gölge alanı, RCX, RDX, R8 ve R9'u dökmek için kullanılır, ancak dörtten az parametreye sahip olanlar da dahil olmak üzere tüm işlevler için kullanılabilir hale getirilmelidir.

RAX, RCX, RDX, R8, R9, R10, R11 kayıtları geçici olarak kabul edilir (arayanın kaydettiği).

RBX, RBP, RDI, RSI, RSP, R12, R13, R14 ve R15 kayıtları kalıcı olarak kabul edilir (arayan kişi tarafından kaydedilir).

Örneğin, 5 tamsayı argümanı alan bir işlev, kayıtlarda birinciden dördüncüye kadar alacak ve beşinci, gölge uzayının üstüne itilecektir. Böylece çağrılan işlev girildiğinde, yığın (artan sırada) dönüş adresinden, ardından gölge alandan (32 bayt) ve ardından beşinci parametreden oluşacaktır.

Gelen x86-64 , Visual Studio XMM6 ve (XMM15 yanı sıra tarafımıza XMM8) xmm7 içinde kayan nokta sayıları 2008 saklar; bunun sonucu olarak, için x86-64 , kullanıcı tarafından yazılan montaj dili rutinleri korumalıdır XMM6 ve xmm7 (şekilde göre x 86 kullanıcı tarafından yazılan montaj dili rutinleri XMM6 ve xmm7 korumak için gerek yoktu eder). Diğer bir deyişle, kullanıcı yazılı montaj dil rutinleri taşıdık edilirken işlevi önce / sonra / kaydetme XMM6 ve xmm7 geri güncellenmelidir x86 için x86-64 .

Visual Studio 2013'ten başlayarak Microsoft , x64 kuralını genişleten __vectorcall çağrı kuralını tanıttı .

Sistem V AMD64 ABI

System V AMD64 ABI'nin çağrı kuralı Solaris , Linux , FreeBSD , macOS'ta izlenir ve Unix ve Unix benzeri işletim sistemleri arasında fiili standarttır. OpenVMS x86-64 Standardı çağrı için geriye dönük uyumluluk için gerekli bazı uzantılı Sistem V ABI dayanmaktadır. İlk altı tamsayı veya işaretçi argümanı RDI, RSI, RDX, RCX, R8, R9 (R10, iç içe işlevler durumunda statik zincir işaretçisi olarak kullanılır) kayıtlarında iletilirken, XMM0, XMM1, XMM2, XMM3, XMM4, XMM5 , XMM6 ve XMM7, ilk kayan nokta bağımsız değişkenleri için kullanılır. Microsoft x64 çağırma kuralında olduğu gibi, yığında ek bağımsız değişkenler iletilir. 64 bit boyutuna kadar tamsayı dönüş değerleri RAX'ta saklanırken 128 bit'e kadar olan değerler RAX ve RDX'de saklanır. Kayan nokta dönüş değerleri benzer şekilde XMM0 ve XMM1'de saklanır. Daha geniş YMM ve ZMM kayıtları, var olduklarında XMM yerine daha geniş değerleri iletmek ve döndürmek için kullanılır.

Aranan kişi RBX, RSP, RBP ve R12–R15 kayıtlarını kullanmak isterse, kontrolü arayana geri vermeden önce orijinal değerlerini geri yüklemesi gerekir. Diğer tüm kayıtlar, değerlerini korumak istiyorsa, arayan tarafından kaydedilmelidir.

Yaprak düğüm işlevleri için (başka işlev(ler) çağırmayan işlevler), işlevin yığın işaretçisinin hemen altında 128 baytlık bir boşluk saklanır. Boşluğa kırmızı bölge denir . Bu bölge herhangi bir sinyal veya kesme işleyicisi tarafından engellenmeyecektir. Derleyiciler bu nedenle yerel değişkenleri kaydetmek için bu bölgeyi kullanabilir. Derleyiciler, bu bölgeyi kullanarak işlevin başlangıcında (RSP, RBP'nin ayarlanması) bazı talimatları atlayabilir. Ancak, diğer işlevler bu bölgeyi tıkayabilir. Bu nedenle, bu bölge yalnızca yaprak düğüm işlevleri için kullanılmalıdır. gccve kırmızı bölge optimizasyonlarını devre dışı bırakmak clangiçin -mno-red-zonebayrağı sunun .

Çağrılan değişken bir işlevse , vektör kayıtlarında fonksiyona geçirilen kayan noktalı argümanların sayısı, AL kaydındaki arayan tarafından sağlanmalıdır.

Microsoft çağrı kuralından farklı olarak, bir gölge alanı sağlanmaz; işlev girişinde, dönüş adresi yığındaki yedinci tamsayı argümanına bitişiktir.

x86 arama kurallarının listesi

Bu, x86 çağrı kurallarının bir listesidir. Bunlar, öncelikle C/C++ derleyicileri (özellikle aşağıdaki 64 bitlik kısım) ve dolayısıyla büyük ölçüde özel durumlar için tasarlanmış kurallardır. Diğer diller, uygulamalarında diğer biçimleri ve kuralları kullanabilir.

Mimari İsim İşletim sistemi, derleyici parametreler Yığın temizleme Notlar
Kayıtlar yığın sırası
8086 cdecl RTL (C) arayan
paskal LTR (Paskal) arayan
hızlı arama (üye olmayan) Microsoft AX, DX, BX LTR (Paskal) arayan BX'te işaretçiyi döndür.
hızlı arama (üye işlevi) Microsoft AX, DX LTR (Paskal) arayan thisyığın düşük adreste. AX'te işaretçiyi döndür.
hızlı arama Turbo C AX, DX, BX LTR (Paskal) arayan thisyığın düşük adreste. Yığın yüksek adresinde işaretçiyi döndür.
watcom AX, DX, BX, CX RTL (C) arayan SI'da işaretçiyi döndür.
IA-32 cdecl Unix benzeri ( GCC ) RTL (C) arayan struct/class döndürülürken, çağıran kod boşluk ayırır ve yığındaki gizli bir parametre aracılığıyla bu alana bir işaretçi iletir. Çağrılan işlev, dönüş değerini bu adrese yazar.

Bir hata nedeniyle yığın 16 baytlık sınırda hizalandı.

cdecl Microsoft RTL (C) arayan struct/class döndürürken,
  • Düz eski veri (POD) dönüş değerleri 32 bit veya daha küçük EAX kaydındadır
  • 33-64 bit boyutundaki POD dönüş değerleri, EAX:EDX kayıtları aracılığıyla döndürülür.
  • POD olmayan dönüş değerleri veya 64 bitten büyük değerler, çağıran kod alan tahsis eder ve yığındaki gizli bir parametre aracılığıyla bu alana bir işaretçi iletir. Çağrılan işlev, dönüş değerini bu adrese yazar.

4 baytlık sınırda hizalanmış yığın.

standart çağrı Microsoft RTL (C) arayan GCC tarafından da desteklenmektedir.
hızlı arama Microsoft ECX, EDX RTL (C) arayan Üye işlevi değilse, işaretçiyi yığında döndürün. GCC tarafından da desteklenmektedir.
Kayıt ol Delphi ve Ücretsiz Pascal EAX, EDX, ECX LTR (Paskal) arayan
bu çağrı Windows ( Microsoft Visual C++ ) ECX RTL (C) arayan Üye işlevleri için varsayılan.
vektörel çağrı Windows ( Microsoft Visual C++ ) ECX, EDX, [XY]MM0–5  RTL (C) arayan Fastcall'dan genişletildi. Ayrıca ICC ve Clang tarafından da desteklenir.
Watcom derleyicisi EAX, EDX, EBX, ECX RTL (C) arayan ESI'de işaretçiyi döndür.
x86-64 Microsoft x64 çağrı kuralı Windows ( Microsoft Visual C++ , GCC , Intel C++ Derleyici , Delphi ), UEFI RCX/XMM0, RDX/XMM1, R8/XMM2, R9/XMM3 RTL (C) arayan 16 bayta hizalanmış yığın. Yığında 32 bayt gölge alanı. Belirtilen 8 kayıt yalnızca 1 ile 4 arasındaki parametreler için kullanılabilir. C++ sınıfları için, gizli thisparametre ilk parametredir ve RCX'te geçirilir.
vektörel çağrı Windows ( Microsoft Visual C++ , Clang, ICC) RCX/[XY]MM0, RDX/[XY]MM1, R8/[XY]MM2, R9/[XY]MM3 + [XY]MM4–5 RTL (C) arayan MS x64'ten genişletildi.
Sistem V AMD64 ABI Solaris , Linux , BSD , macOS , OpenVMS ( GCC , Intel C++ Derleyici , Clang , Delphi ) RDI, RSI, RDX, RCX, R8, R9, [XYZ]MM0–7 RTL (C) arayan 16 bayt sınırında hizalanmış yığın. Yığın altında 128 bayt kırmızı bölge . Çekirdek arabirimi RDI, RSI, RDX, R10, R8 ve R9'u kullanır. C++ this'da ilk parametredir.

Referanslar

Dipnotlar

Diğer kaynaklar

daha fazla okuma