Çoğu modern sistemde yığın büyümesinin yönü nedir?


Yanıtlar:


147

Yığın büyümesi genellikle işletim sisteminin kendisine değil, üzerinde çalıştığı işlemciye bağlıdır. Örneğin Solaris, x86 ve SPARC üzerinde çalışır. Mac OSX (bahsettiğiniz gibi) PPC ve x86 üzerinde çalışır. Linux, işteki büyük dostum System z'den cılız küçük bir kol saatine kadar her şeyde çalışıyor .

CPU herhangi bir seçenek sunuyorsa, işletim sistemi tarafından kullanılan ABI / çağrı kuralı, kodunuzun diğer herkesin kodunu çağırmasını istiyorsanız hangi seçimi yapmanız gerektiğini belirtir.

İşlemciler ve yönleri:

  • x86: aşağı.
  • SPARC: seçilebilir. Standart ABI aşağı kullanır.
  • PPC: aşağı, sanırım.
  • System z: bağlantılı bir listede sizi şaka yapmıyorum (ama yine de aşağıda, en azından zLinux için).
  • ARM: seçilebilir, ancak Thumb2 yalnızca aşağı için kompakt kodlamalara sahiptir (LDMIA = sonra artış, STMDB = önce azalma).
  • 6502: aşağı (ancak yalnızca 256 bayt).
  • RCA 1802A: SCRT uygulamasına tabi olarak istediğiniz şekilde.
  • PDP11: aşağı.
  • 8051: yukarı.

Son birkaçında yaşımı gösteren 1802, erken mekikleri kontrol etmek için kullanılan çipti (kapıların açık olup olmadığını algılamak, sanırım sahip olduğu işlem gücüne dayanarak :-) ve ikinci bilgisayarım COMX-35 ( ZX80'imi takip ederek ).

PDP11 panoda ayrıntıları buradan itibaren, 8051 ayrıntıları burada .

SPARC mimarisi, kayan pencere kayıt modeli kullanır. Mimari olarak görülebilen ayrıntılar, aynı zamanda, geçerli olan ve dahili olarak önbelleğe alınan, üst / alt akış durumunda tuzaklarla birlikte, kayıt pencerelerinin dairesel bir arabelleğini içerir. Ayrıntılar için buraya bakın. As SPARCv8 manuel açıklıyor , TASARRUF ve RESTORE talimatları ADD talimatları gibidir artı kayıt pencere rotasyonunu. Normal negatif yerine pozitif bir sabit kullanmak, yukarı doğru büyüyen bir yığın sağlar.

Yukarıda bahsedilen SCRT tekniği başka bir tekniktir - 1802, SCRT için bazılarını veya on altı 16-bitlik kayıtlarını kullandı (standart çağrı ve dönüş tekniği). Biri program sayacıydı, SEP Rntalimatla herhangi bir kaydı PC olarak kullanabilirsiniz . Biri yığın göstericisiydi ve ikisi her zaman SCRT kod adresini gösterecek şekilde ayarlandı, biri çağrı için, biri dönüş için. Hiçbir kayıt özel bir şekilde ele alınmadı. Unutmayın, bu detaylar hafızadan geliyor, tamamen doğru olmayabilirler.

Örneğin, R3 PC, R4 SCRT çağrı adresi, R5 SCRT dönüş adresi ve R2 "yığın" ise (yazılımda uygulandığı şekliyle tırnak işaretleri), SEP R4R4'ü PC olarak ayarlar ve SCRT'yi çalıştırmaya başlar çağrı kodu.

Daha sonra, R2, bir "yığın" (R6nın geçici depolama için kullanılan düşünüyorum) ile R3 depolamak o kadar ayarlama ya da aşağı, R3, aşağıdaki iki bayt kapmak, bunları yüklenmektedir içine daha sonra yapılacak, R3 SEP R3ve yeni adresteki çalışmalıdır.

Geri dönmek için, SEP R5eski adresi R2 yığınından çeker, ona iki tane ekler (çağrının adres baytlarını atlamak için), R3'e yükler SEP R3ve önceki kodu çalıştırmaya başlar.

Tüm 6502/6809 / z80 yığın tabanlı kodlardan sonra başınızı döndürmek çok zor, ancak yine de kafanızı duvara çarpacak şekilde zarif. Ayrıca, yonganın en büyük satış özelliklerinden biri, bunlardan 7'sini (SCRT için 5, DMA için iki ve bellekten kesinti) hemen kaybetmenize rağmen, 16 16 bitlik kayıtlardan oluşan eksiksiz bir paketti. Ahh, pazarlamanın gerçekliğe karşı zaferi :-)

System z aslında çağrı / dönüş için R14 ve R15 kayıtlarını kullanarak oldukça benzerdir.


3
Listeye eklemek için, ARM her iki yönde de büyüyebilir, ancak belirli bir silikon uygulamasıyla birine veya diğerine ayarlanabilir (veya yazılım tarafından seçilebilir olarak bırakılabilir). Ele aldığım birkaç kişi her zaman büyüme modunda olmuştur.
Michael Burr

1
Şimdiye kadar gördüğüm ARM dünyasında (ARM7TDMI) yığın tamamen yazılımla işleniyor. İade adresleri, gerekirse yazılım tarafından kaydedilen bir kayıtta saklanır ve ön / son artırma / azaltma talimatları, her iki yönde de yığının üzerine koymaya izin verir.
starblue

1
Bir HPPA, yığın büyüdü! Makul modern mimariler arasında oldukça nadir.
tml


1
Anlayışınız için teşekkürler @paxdiablo. Bazen böyle bir yorum yaptığınızda, özellikle de daha yaşlı olduğunda, insanlar bunu kişisel bir hakaret olarak görürler. Sadece bir fark olduğunu biliyorum çünkü geçmişte ben de aynı hatayı yaptım. Kendine iyi bak.
CasaDeRobison

23

C ++ 'da (C'ye uyarlanabilir) stack.cc :

static int
find_stack_direction ()
{
    static char *addr = 0;
    auto char dummy;
    if (addr == 0)
    {
        addr = &dummy;
        return find_stack_direction ();
    }
    else
    {
        return ((&dummy > addr) ? 1 : -1);
    }
}

14
Vay canına, "otomatik" anahtar kelimesini görmeyeli uzun zaman oldu.
paxdiablo

9
(& dummy> addr) tanımsız. İlişkisel bir operatöre iki işaretçi beslemenin sonucu, yalnızca iki işaretçi aynı dizi veya yapıyı gösteriyorsa tanımlanır.
sigjuice

2
Kendi yığınınızın düzenini araştırmaya çalışmak - C / C ++ 'nın hiç belirtmediği bir şey - başlangıçta "taşınamaz", bu yüzden bunu gerçekten umursamam. Görünüşe göre bu işlev yalnızca bir kez düzgün çalışacak.
efemient

9
Bunun için a kullanmaya gerek yok static. Bunun yerine, adresi yinelemeli bir çağrıya argüman olarak iletebilirsiniz.
R .. GitHub BUZA YARDIM ETMEYİ DURDUR

5
artı, a kullanarak static, bunu birden fazla ararsanız, sonraki çağrılar başarısız olabilir ...
Chris Dodd

7

Büyümenin avantajı, eski sistemlerde yığın tipik olarak belleğin en üstündeydi. Programlar tipik olarak alttan başlayarak belleği doldurdu, bu nedenle bu tür bir bellek yönetimi, yığının altını ölçmek ve makul bir yere yerleştirmek ihtiyacını en aza indirdi.


3
Bir 'avantaj' değil, bir totoloji gerçekten.
Marquis of Lorne

1
Bir totoloji değil. @Valenok'un belirttiği gibi, önemli olan iki büyüyen bellek bölgesine müdahale etmemek (zaten bellek dolu değilse).
Yvesgere ·

6

Yığın x86'da küçülür (mimari, pop artışları yığın işaretçisi, itme azaltmalarıyla tanımlanır.)


5

MIPS ve birçok modern olarak RISC mimarileri (PowerPC, RISC-V, SPARC ... gibi) hiçbir vardır pushve poptalimatlar. Bu işlemler, yığın işaretçisini manuel olarak ayarlayarak ve ardından değeri ayarlanan işaretçiye göre göreceli olarak yükleyerek / depolayarak açıkça yapılır. Tüm yazmaçlar (sıfır yazmacı hariç) genel amaçlıdır, bu nedenle teoride herhangi bir kayıt bir yığın işaretçisi olabilir ve yığın , programcının istediği herhangi bir yönde büyüyebilir.

Bununla birlikte, yığın, muhtemelen yığın ve program verilerinin veya yığın verilerinin büyüdüğü ve birbiriyle çatıştığı durumdan kaçınmak için çoğu mimaride büyür. Ayrıca sh-'nin cevabından bahseden harika adresleme nedenleri var . Bazı örnekler: MIPS ABI'ler aşağı doğru büyür ve yığın işaretçisi olarak $29(AKA $sp) kullanır , RISC-V ABI da aşağı doğru büyür ve yığın işaretçisi olarak x2'yi kullanır

Intel 8051'de yığın büyür, muhtemelen bellek alanı çok küçük olduğundan (orijinal sürümde 128 bayt) yığın yoktur ve yığın büyümesinden ayrılması için yığını en üste koymanıza gerek yoktur. Alttan

Çeşitli mimarilerde yığın kullanımı hakkında daha fazla bilgiyi https://en.wikipedia.org/wiki/Calling_convention adresinde bulabilirsiniz.

Ayrıca bakınız


2

Görebildiğim kadarıyla bu noktaya değinmeyen diğer cevaplara sadece küçük bir ekleme:

Yığının aşağı doğru büyümesi, yığın içindeki tüm adreslerin yığın işaretçisine göre pozitif bir kaymaya sahip olmasını sağlar. Negatif kaydırmalara gerek yoktur, çünkü bunlar yalnızca kullanılmayan yığın alanına işaret ederler. Bu, işlemci yığın işaretleyiciye göre adreslemeyi desteklediğinde yığın konumlarına erişimi kolaylaştırır.

Çoğu işlemcinin, bazı kayıtlara göre yalnızca pozitif bir kayma ile erişime izin veren talimatları vardır. Bunlar birçok modern mimariyi ve bazı eski mimarileri içerir. Örneğin, ARM Başparmak ABI, tek bir 16 bitlik talimat sözcüğü içinde kodlanmış bir pozitif ofset ile yığın işaretleyiciye göre erişim sağlar.

Yığın yukarı doğru büyürse, yığın işaretleyiciye göre tüm yararlı kaydırmalar negatif olur, bu daha az sezgiseldir ve daha az uygundur. Aynı zamanda, örneğin bir yapının alanlarına erişim için, diğer yazmaç-göreceli adresleme uygulamaları ile çelişmektedir.


2

Çoğu sistemde yığın büyüyor ve https://gist.github.com/cpq/8598782 adresindeki makalem NEDEN büyüdüğünü açıklıyor. Çok basit: Sabit bir bellek yığınında büyüyen iki bellek bloğu (yığın ve yığın) nasıl düzenlenir? En iyi çözüm, onları zıt uçlara koymak ve birbirlerine doğru büyümelerine izin vermektir.


bu öz şimdi ölü gibi görünüyor :(
Ven

@Ven - Ona ulaşabilirim
Brett Holman

1

Programa ayrılan bellekte "kalıcı veriler" yani programın kodunun altta, ardından ortada yığının olması nedeniyle küçülür. Yığını referans almak için başka bir sabit noktaya ihtiyacınız var, böylece sizi en üstte bırakır. Bu, yığının potansiyel olarak öbek üzerindeki nesnelere bitişik oluncaya kadar büyüyeceği anlamına gelir.


0

Bu makro, UB olmadan çalışma zamanında onu algılamalıdır:

#define stk_grows_up_eh() stk_grows_up__(&(char){0})
_Bool stk_grows_up__(char *ParentsLocal);

__attribute((__noinline__))
_Bool stk_grows_up__(char *ParentsLocal) { 
    return (uintptr_t)ParentsLocal < (uintptr_t)&ParentsLocal;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.