2 puan yazan GN⁺ 2024-04-04 | 1 yorum | WhatsApp'ta paylaş

Bilgisayarlarda stack ve heap yokken antik çağın alt program çağrısı

  • Modern bilgi işlemde stack ve heap’i doğal kabul ederiz, ancak bilgi işlemin ilk dönemlerinde bilgisayarlar stack veya heap olmadan çalışıyordu.
  • Dinamik bellek ayırma olmadan bilgi işlemi hayal etmek o kadar da zor değil. Her şey için sabit boyutlu bellek tamponları kullanmanız gerekir.
  • Değişken boyutlu verileri işlemeniz gerekiyorsa, öngörülebilir verileri barındırabilecek kadar büyük sabit boyutlu bir tampon ayırırsınız.
  • Derleme zamanı yapılandırması sağlayarak istemcinin azami kapasiteyi ayarlamasına izin verebilir ya da sabit boyutlu bir tampondan belleği "ayırıp" "serbest bırakabilen" özel bir ayırıcı yazabilirsiniz.

Stack olmadan fonksiyon çağırmak

  • Derleyici, her fonksiyonun gelen parametreleri, dönüş adresi ve yerel değişkenleri için gizli global değişkenler tanımlar.
  • Derleyici bir fonksiyon çağrısı üretmek için parametre değerlerini ilgili gizli global değişkenlere atar, dönüş adresini fonksiyonun gizli "dönüş adresi değişkenine" yazar ve ardından fonksiyonun başlangıcına atlar.
  • Fonksiyon, parametreleri gizli global değişkenlerden okur ve mantıksal olarak yerel değişkenlere karşılık gelen önceden tanımlı gizli global değişkenleri kullanır.
  • Fonksiyon bittiğinde, fonksiyonun gizli "dönüş adresi değişkeninde" bulunan adrese atlar.

ABI optimizasyonu

  • ABI’yi optimize etmek için bazı değerler global değişkenler yerine register’lar üzerinden geçirilir.
  • Çoğu işlemcide bir "link" register’ı ve bir "branch with link" komutu bulunur; bu komut, link register’ını otomatik olarak "branch with link" komutundan sonraki adresle ayarlar.
  • İlk iki parametreyi register ile ileten çağrı kuralı optimize edilir.

Özyinelemeli çağrının imkânsızlığı

  • Özyinelemeli çağrılar çalışmaz. Çünkü özyinelemeli çağrı, dönüş adresi değişkenini kendi dönüş adresiyle ezer; bu da dış çağrı tamamlandığında yanlış konuma atlanmasına yol açar.
  • O dönemin programlama dilleri, özyinelemeyi desteklemediklerini ilan ederek bu sorunu çözerdi.

Bonus sohbet

  • Bazı derleyiciler, daha kurnaz çalışmak için kendini değiştiren kod kullanıyordu: özel dönüş adresi değişkeni aslında fonksiyon sonundaki atlama komutunun adres alanıydı.
  • İşlemci dolaylı atlamayı desteklemiyorsa, bu yöntem pratik bir zorunluluk olarak kullanılıyordu.
  • Alt programların pratik değeri fark edildikten sonra, birçok işlemci alt program çağrı komutları ekledi; bunlar dönüş adresini alt programın ilk sözcüğüne yazar ve yürütmeye alt programın ikinci sözcüğünden başlardı.
  • Alt programdan dönmek için, alt programın başlangıç etiketi üzerinden dolaylı bir atlama gerçekleştirilirdi.

GN⁺ görüşü

  • Bu yazı, bilgi işlemin ilk dönemlerinde stack ve heap olmadığında programlamanın nasıl yapıldığını anlatarak, modern yazılım geliştirmede kullanılan bellek yönetimi tekniklerinin evrimini anlamaya yardımcı oluyor.
  • Stack ve heap’in olmadığı dönemin programlama tarzı, modern geliştiricilere çok yabancı ve verimsiz görünebilir; ancak teknolojinin bilgi işlem tarihi boyunca nasıl geliştiğini anlamak için önemli bir arka plan bilgisi sunuyor.
  • Özyinelemeli çağrıların imkânsız olduğu dönemin programlama kısıtları, bugün özyinelemeli algoritmalar kullanan geliştiriciler için ilgi çekici bir tarihsel ayrıntı sunuyor.
  • Eleştirel bir bakışla değerlendirildiğinde, bu erken dönem programlama yöntemleri modern çağın karmaşık ve çeşitli gereksinimlerini karşılamak için oldukça sınırlıydı.

1 yorum

 
GN⁺ 2024-04-04
Hacker News görüşleri
  • "Bilgisayar Programlamanın Sanatı" kitabına olumlu bir değerlendirme

    • Kitap eski görünüyor olsa da, heap ya da stack öncesi dönemde çeşitli dinamik dizileri veya veri yapılarını değiştiren algoritmaları ele alıyor.
    • Kitap ayrıca garbage collection ve Lisp liste uygulamasını açıklıyor; Knuth’un insanda beklenti uyandıran ansiklopedik bilgilerini sunuyor.
  • İki dizinin tek bir alanı dinamik olarak paylaşma yöntemine dair açıklama

    • Bir dizi #0 konumundan normal şekilde büyürken, diğerinin #End konumundan ters yönde büyümesini sağlayarak iki dizi statik olarak ayrılmış alanı verimli biçimde paylaşır.
    • Bu yöntem birden fazla diziye genişletilebilir, ancak o noktada Malloc ve Realloc kullanmak daha iyi olabilir.
  • ALGOL diline özyinelemeli fonksiyonların eklenmesinin tartışmalı oluşuna dair ilginç bir hikâye bağlantısı paylaşımı

    • Bağlantı üzerinden, özyinelemenin programlama dillerine nasıl girdiğine dair ilgi çekici bir tarih anlatısı paylaşılıyor.
  • SUBLEQ makinesi ve bit-seri makineler için Forth yorumlayıcısı yazma deneyimi paylaşımı

    • Bu iki makinede de Forth’un temel unsuru olan fonksiyon çağrı stack’i bulunmuyor.
    • SUBLEQ dolaylı yükleme ve saklamaya izin vermiyor; alışılmadık işleri yapmak için self-modifying code gerekiyor.
    • Bu işlevleri yerine getirmek ve cooperative multithreading desteklemek için bir sanal makine kuruluyor.
    • Gerektiğinde heap Forth ile yazılıyor ve yazılım fonksiyonlarıyla gerçekleştirilmiş kayan nokta işlemleri de buna dahil ediliyor.
  • PDP-8 işlemcisinde subroutine çağrısıyla ilgili teknik evrime dair açıklama

    • Başlangıçta JMS komutu dönüş adresini fonksiyonun ilk sözcüğüne kaydediyordu.
    • Daha sonra auto-increment konumları kullanılarak basit bir stack oluşturuldu ve fonksiyon prologue/epilogue bölümleri bu stack’i elle yöneterek tam özyinelemeyi mümkün kıldı.
    • Sonraki aşamada performansı artırmak için mikroişlemci uygulamasına donanımsal stack eklendi.
  • Uzun süredir fonksiyonel programlama deneyimi olan bir kullanıcının özyineleme tercihini paylaşması

    • Özyinelemeli algoritmaları yinelemeli algoritmalara nasıl dönüştüreceğini biliyor, ancak özyinelemeyi tercih ediyor.
    • Çoğu durumda özyineleme yeterince hızlı; derleyici tail recursion destekliyorsa daha da öyle.
    • Commodore 64 oyunlarını hack’leyerek geçmişte programlamanın nasıl yapıldığını öğrenmeye çalışıyor.
  • 1991 civarında RS232 seri çoklayıcı tasarlama deneyimi paylaşımı

    • Z80 işlemci, EPROM ve Z80-SIO seri aygıtı kullanılan bir donanım tasarımı.
    • Stack olmadığı için fonksiyon çağrılarında dönüş adreslerini önceden register çiftlerine yükleme yöntemi kullanılmış.
  • Heap genişletilebilir olmadan önce programcıların girdilerin olası dağılımını hesaba katıp ara depolamanın boyutunu uygun ayarlamak zorunda kaldığı geçmiş duruma değinilmesi

    • Bu da "hatalar ve sınırlar" ortaya çıkarıyordu.
  • Özyinelemenin kullanılamadığı dönemlerde tail recursion’ın mümkün olduğuna dair açıklama

    • İlk çağrıda kullanılan branch_with_link dışında normal branch komutlarının kullanılması gerekiyordu.
  • Enhanced GNU Awk içinde, fonksiyon dışındaki @let bloklarına derleyicinin gizli global değişkenler atama biçimine dair açıklama

    • Bu değişkenler mümkün olduğunca yeniden kullanılıyor.
  • "Goto considered harmful" makalesinin dünyasını tasvir eden bir gönderiye değinilmesi

    • Çoğu insan yalnızca başlığı biliyor; makale, subroutine’lere tek bir giriş noktası sağlanmasını savunuyor.
    • Bazen assembly kodu başka bir subroutine’e atlayacak şekilde yazılıyor, ancak tüm assembly kodunun böyle olmasını istemiyorlar.