Çağrı yığını tam olarak nasıl çalışır? | Netgez.com
SORU
1 HAZÄ°RAN 2014, Pazar


Çağrı yığını tam olarak nasıl çalışır?

Programlama dilleri işlemleri nasıl çalıştığını ve özellikle OS/CPU ile etkileşim nasıl daha derin bir anlayış almak için çalışıyorum. Muhtemelen her her cevap Yığın Taşması/yığın ilgili konu burada yığın okudum, ve çok başarılılar. Ama hala henüz tam olarak anlayamadığım bir şey var.

Geçerli bir Pas kod eğiliminde olan sahte kod bu işlevi görür ;-)

fn foo() {
    let a = 1;
    let b = 2;
    let c = 3;
    let d = 4;

    // line X

    doSomething(a, b);
    doAnotherThing(c, d);
}

Bu satırda X gibi görünmeye yığın sanırım:

Stack

a  ------------- 
  | 1           | 
b  -------------      
  | 2           |  
c  ------------- 
  | 3           | 
d  -------------      
  | 4           | 
   -------------  

Şimdi, yığın nasıl çalıştığı hakkında okuduğum her şey kesinlikle FIFO kuralları (son giren ilk çıkar) itaat eder. Gibi bir yığın veri türü .NET, Java veya başka bir programlama dili.

Ama eğer durum buysa, o zaman ne satırdan sonra X olur? Açıkçası, biz gereken bir sonraki şey a b ile çalışmak ama OS CPU/çünkü bu (?) d c pop için ilk a b geri dönmek. Ama sonra bir sonraki satıra c d ihtiyacı var çünkü ayak kendini vur.

Ben ne merak ediyorumtam olaraksahneler? geride olur

İlgili bir diğer soru. Bu gibi diğer işlevler için referans verdiğimiz düşünün

fn foo() {
    let a = 1;
    let b = 2;
    let c = 3;
    let d = 4;

    // line X

    doSomething(&a, &b);
    doAnotherThing(c, d);
}

İşlerin nasıl olduğunu anlıyorum, bu doSomething parametreler a ve foo 19 *gibi aynı bellek adresi aslında şuna işaret ediyor demektir. Ama sonra tekrar, bu yok anlamına geliryığın a b varana kadar açılıroluyor.

Bu iki olgu bana tam olarak nasıl idrak edemediğimi düşünüyorumtam olarakbu kesinlikle takip nasıl çalışır yığını veFIFOkuralları.

CEVAP
1 HAZÄ°RAN 2014, Pazar


Çağrı yığını da bir yığın çerçevesi olarak adlandırılabilir.
Olan şeyleryığılmışFIFO prensibine sonra bunun nasıl çalıştığını görmek için çağrıldığını yerel değişkenler ama tüm yığın çerçeveler. Yerel değişkenler ve sözde function prologue epilogue, sırasıyla, o çerçeve ile birlikte itti attı.

Çerçeve içindeki değişkenlerin sırasını tamamen belirsiz; Derleyiciler işlemciye onları mümkün olduğunca çabuk getir, böylece 46* *uygun hizalamayı optimize etmek için. Önemli bir gerçeğibu değişkenler bazı sabit adresi için göreli uzaklık çerçeve ömrü boyunca sabittir- bağlantı adresi al, karenin adresini kendisi söylüyor, ve değişkenler için adres uzaklıklar ile çalışmak için yeterlidir.
Bu tabii ki derleme zamanında bilinen ve bu nedenle makine kodu içine kodlanmış olan uzaklık.

Bu X gibi görünebilir:

Address       value

 0xFEFD   return address

 0xFF01  d  ---------- 
           |    1     | 
 0xFF05  c  ----------      
           |    2     |  
 0xFF09  b  ---------- 
           |    3     | 
 0xFF0D  a  ----------      
           |    4     | 
            ----------  

    X is down here.

Çapa adresimiz 0xFF01 olabilir.
Böyle bir bağlantı adresi aslında sözde yer alıyortabanyaçerçeve işaretçisiEBP kasada saklı olan.

Picture of a stack

Adresi Kare işaretçisi içerdiği için erişmek istediğimiz bir değişken mahsup ekleyin ve bizim değişkenin adresi. Kısa bir süre sonra, kodu direkt olarak onları base pointer dan derleme zamanı sabiti uzaklıklar üzerinden erişir; basit işaretçi aritmetiği olduğunu söyledi.

Örnek

#include <iostream>

int main()
{
    char c = std::cin.get();
    std::cout << c;
}

gcc.godbolt.org bize verir

main:
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp

    movl    std::cin, íi
    call    std::basic_istream<char, std::char_traits<char> >::get()
    movb    %al, -1(%rbp)
    movsbl  -1(%rbp), êx
    movl    êx, %esi
    movl    std::cout, íi
    call    [... the insertion operator for char, long thing... ]

    movl    $0, êx
    leave
    ret

main... Üç bölümlere kodu ayırdım. Fonksiyon Prolog ilk üç işlemleri oluşur:

  • Temel iÅŸaretçi yığına itilir. Bu bizim dönüş adresi.
  • Yığın göstergesi ana iÅŸaretçi kaydedilir
  • Yığın iÅŸaretçisi yerel deÄŸiÅŸkenler için yer açmak için çıkarılır.

Sonra cin EDİ kayıt içine taşınır1get denir; dönüş değeri TÜR.

Şimdiye kadar çok iyi. Şimdi ilginç bir şey olur:

SES alt sıra bayt, 8-bit kayıt AL tarafından belirlenen alınırtemel işaretçiyi sonra bayt hakkı saklı: -1(%rbp) temel işaretçi offset -1.Bu bayt c bizim değişkendir. Uzaklık 86 üzerinde aşağıya doğru büyür yığını nedeniyle olumsuz. Sonraki operasyon mağazaları c SES: SES taşınır, ESI, cout taşınır EDİ ve sonra Ekleme operatörü ile adlandırılır cout c olmak argümanlar.

Son olarak

  • main dönüş deÄŸeri TÃœR saklanır: 0. return örtülü ifadesi yüzünden. Ayrıca xorl rax rax movl yerine görebilirsiniz.
  • bırakın site dönün. leave bu son söz ve örtülü olarak biraz daha kısa.
    • Temel iÅŸaretçisini, iÅŸaretçi yığını ve deÄŸiÅŸtirir
    • Babalık Bankası iÅŸaretçi.

İşaretçi İhmal Çerçeve

Ayrıca mümkündür. Aksi takdirde bu çerçeve işaretçi değeri keyfi olarak kullanılabilir-ama debugging impossible on some machines, yapabilirsiniz baskılarını EBP - kayıt yapar ve implicitly turned off for some functions olacak. 86 de dahil olmak üzere sadece birkaç kayıtları ile işlemci için derleme sırasında özellikle yararlıdır.

Bu optimizasyon FPO (çerçeve göstericisi ihmal) bilinen ve Çınlama GCC -fomit-frame-pointer -Oy tarafından ayarlanır; örtülü olarak her optimizasyon seviyesi ile tetiklenen olduğunu unutmayın >Eğer hata ayıklama herhangi bir masraf bunun dışında bir önemi yok, çünkü hala mümkün olup olmadığını, eğer 0 ve sadece. Daha fazla bilgi için bkz: here ve here.


1R ile başlayan kayıtları 64-bit E. SES atar RAX alt sıra dört bayt ile başlayan olanlar meslektaşları olduğunu unutmayın. Netlik için 32-bit kaydeder adlarını kullandım.

Bunu PaylaÅŸ:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VÄ°DEO

Rastgele Yazarlar

  • Official Android Tips

    Official And

    23 EYLÃœL 2009
  • Charles Renaud

    Charles Rena

    10 Kasım 2007
  • Louis C.K.

    Louis C.K.

    18 HAZÄ°RAN 2006