it-swarm.asia

Neden segmentasyon (değil)?

İşletim sistemlerini ve x86 mimarisini inceliyorum ve segmentasyon ve sayfalama hakkında okurken, modern işletim sistemlerinin bellek yönetimini nasıl ele aldığını doğal olarak merak ettim. Linux ve diğer işletim sistemlerinin çoğunu bulduğum kadarıyla bölümleme lehine disk belleği lehine çevirdi. Bulduğum bunun birkaç nedeni basitlik ve taşınabilirlikti.

Segmentasyon (x86 veya başka türlü) için hangi pratik kullanımlar vardır ve bunu kullanan sağlam işletim sistemleri görecek miyiz yoksa çağrı tabanlı bir sistemi desteklemeye devam edecekler mi?.

Şimdi bunun yüklü bir soru olduğunu biliyorum ama yeni geliştirilen işletim sistemleriyle segmentasyonun nasıl ele alınacağını merak ediyorum. Kimsenin daha 'bölümlere ayrılmış' bir yaklaşımı düşünmeyeceği, sayfalamayı tercih etmek o kadar anlamlı mı? Öyleyse neden?


Ve 'shun' segmentasyonu dediğimde Linux'un sadece gerektiği kadar kullandığını ima ediyorum. Kullanıcı ve çekirdek kodu/veri segmentleri için sadece 4 segment. Intel belgelerini okurken, segmentasyonun daha sağlam çözümler düşünülerek tasarlandığını hissettim. Sonra tekrar birçok kez x86'nın ne kadar karmaşık olabileceği söylendi.


Bu ilginç fıkrayı Linux Torvald'ın Linux için orijinal 'duyurusuna' bağlandıktan sonra buldum. Bunu birkaç yazı sonra söyledi:

Basitçe söylemek gerekirse, taşımanın imkansız olduğunu söyleyebilirim. Çoğunlukla C'dir, ancak çoğu insan C yazdığım şeyi söylemez. Bu, 386 hakkında bana öğretmek için bir proje olduğu için bulabildiğim 386'nın akla gelebilecek her özelliğini kullanıyor. Daha önce de belirtildiği gibi bir MMU kullanıyor , hem disk belleği (henüz diske değil) hem de segmentasyon için. GERÇEKTEN 386'yı bağımlı yapan bölümleme (her görevin kod ve veri için 64Mb'lik bir segmenti vardır - 4Gb'de maksimum 64 görev. 64Mb/görevden fazla zor çerezlere ihtiyaç duyan herkes).

Sanırım x86 ile yaptığım kendi deneyimlerim bu soruyu sormamı sağladı. Linus'un StackOverflow'u yoktu, bu yüzden denemek için uyguladı.

44
Mr. Shickadance

Segmentasyon ile, örneğin, dinamik olarak tahsis edilen her bir nesneyi (malloc) kendi bellek segmentine koymak mümkün olacaktır. Donanım, segment sınırlarını otomatik olarak kontrol eder ve tüm güvenlik hataları sınıfı (arabellek taşmaları) ortadan kaldırılır.

Ayrıca, tüm segment ofsetleri sıfırdan başladığı için derlenen tüm kodlar otomatik olarak konumdan bağımsız olur. Başka bir DLL çağrısı, sabit ofset (çağrılan işleve bağlı olarak) ile uzak bir çağrıya kaynatılır.Bu, bağlayıcıları ve yükleyicileri büyük ölçüde basitleştirir.

4 koruma halkası ile daha ince taneli erişim kontrolü (sayfalama ile sadece 2 koruma seviyeniz vardır: kullanıcı ve amir) ve daha sağlam işletim sistemi çekirdeği tasarlamak mümkündür. Örneğin, yalnızca 0 halkası donanıma tam erişime sahiptir. Çekirdek OS çekirdeğini ve aygıt sürücülerini 0 ve 1 halkalarına ayırarak, ilgili erişim denetimlerinin çoğunun HW tarafından yapılacağı daha sağlam ve çok hızlı bir mikro çekirdekli işletim sistemi yapabilirsiniz. (Aygıt sürücüleri, TSS'deki G/Ç erişim bitmap'i üzerinden donanıma erişebilir.)

Ancak .. x86 biraz sınırlı. Yalnızca 4 adet "serbest" veri segmenti kaydı vardır; bunları yeniden yüklemek oldukça pahalıdır ve aynı anda sadece 8192 segmente erişmek mümkündür. (Erişilebilir nesne sayısını en üst düzeye çıkarmak istediğinizi varsayarsak, GDT yalnızca sistem tanımlayıcılarını ve LDT tanımlayıcılarını tutar.)

Şimdi, 64-bit mod segmentasyonu ile "eski" olarak tanımlanır ve donanım limit kontrolleri sadece sınırlı durumlarda yapılır. IMHO, BÜYÜK bir hata. Aslında Intel'i suçlamıyorum, çoğunlukla geliştiricileri suçluyorum, çoğunluğu segmentasyonun "çok karmaşık" olduğunu ve düz adres alanını özlemişti. Ayrıca, segmentasyonu iyi kullanmak için hayal gücü olmayan OS yazarlarını da suçluyorum. (AFAIK, OS/2, segmentasyon özelliklerini tam olarak kullanan tek işletim sistemiydi.)

32
zvrba

Kısa cevap, segmentasyonun, belleği adresleme yeteneğine sahip bir işlemcinin bu sınırları aşması için kullanılan bir hack olmasıdır.

8086 durumunda, çip üzerinde 20 adres satırı vardı, yani 1Mb belleğe fiziksel olarak erişebiliyordu. Bununla birlikte, iç mimari, muhtemelen 8080 ile tutarlılığı sürdürme arzusundan dolayı 16 bit adreslemeye dayanıyordu. Bu nedenle, talimat kümesi, tam 1Mb belleğin adreslenmesine izin vermek için 16 bit dizinlerle birleştirilecek segment kayıtlarını içeriyordu. . 80286, segment tabanlı korumayı ve daha fazla belleğin (iirc, 16Mb) adreslenmesini desteklemek için bu modeli gerçek bir MMU ile genişletti.

PDP-11 durumunda, işlemcinin sonraki modelleri, yine 16 bit adres alanının sınırlamalarını desteklemek için Talimat ve Veri alanlarına bir bölümleme sağladı.

Segmentasyon ile ilgili sorun basittir: programınız mimarinin sınırlamaları üzerinde açıkça çalışmalıdır. 8086 örneğinde bu, erişebileceğiniz en büyük bitişik bellek bloğunun 64 bin olduğu anlamına geliyordu. bundan daha fazlasına erişmeniz gerekiyorsa segment kayıtlarınızı değiştirmeniz gerekir. Bu, bir C programcısı için, C derleyicisine ne tür işaretçiler üretmesi gerektiğini söylemeniz gerektiği anlamına geliyordu.

32 bit iç mimariye ve 24 bit fiziksel adres alanına sahip MC68k'yi programlamak çok daha kolaydı.

26
parsifal

80x86 için 4 seçenek vardır - "hiçbir şey", yalnızca segmentasyon, yalnızca sayfalama ve hem segmentasyon hem de sayfalama.

"Hiçbir şey" (bölümleme veya sayfalama yok) için, bir işlemi kendisinden korumanın kolay bir yolu yoktur, süreçleri birbirinden korumanın kolay bir yolu yoktur, fiziksel adres alanı parçalanması gibi şeyleri işlemenin bir yolu yoktur, konumdan kaçınmanın bir yolu yoktur Tüm bu sorunlara rağmen (teoride) bazı durumlarda (örneğin yalnızca bir uygulama çalıştıran gömülü cihaz veya belki de JIT kullanan ve her şeyi sanallaştıran bir şey) yararlı olabilir.

Yalnızca segmentasyon için; "bir işlemi kendinden koru" sorununu neredeyse çözer, ancak bir süreç 8192'den fazla segment (işlem başına bir LDT varsayarak) kullanmak istediğinde kullanılabilir hale getirmek için çok fazla çalışma gerektirir, bu da çoğunlukla kırılır. "Süreçleri birbirinden koruma" problemini neredeyse çözüyorsunuz; ancak aynı ayrıcalık düzeyinde çalışan farklı yazılım parçaları birbirlerinin segmentlerini yükleyebilir/kullanabilir (bunun üzerinde çalışmanın yolları vardır - kontrol aktarımları sırasında ve/veya LDT'leri kullanırken GDT girişlerini değiştirmek). Ayrıca çoğunlukla "konumdan bağımsız kod" sorununu çözer ("segmente bağlı kod" sorununa neden olabilir, ancak bu çok daha az önemlidir). "Fiziksel adres alanı parçalanması" sorunu için hiçbir şey yapmaz.

Yalnızca sayfalama için; "bir süreci kendinden koru" problemini çok fazla çözmez (ama burada dürüst olalım, bu sadece güvensiz dillerde yazılmış kod hata ayıklama/test için bir problemdir ve yine de valgrind gibi çok daha güçlü araçlar var). "İşlemleri birbirinden koruma" sorununu tamamen çözer, "konumdan bağımsız kod" sorununu tamamen çözer ve "fiziksel adres alanı parçalanması" sorununu tamamen çözer. Ek bir bonus olarak, disk belleği olmadan pratik bir yere yakın olmayan çok güçlü teknikler açar; "yazarken kopyala", bellek eşlemeli dosyalar, etkin takas alanı işleme vb.

Şimdi hem segmentasyon hem de sayfalama kullanmanın size her ikisinin de faydalarını sağlayacağını düşünürsünüz; ve teoride, segmentasyondan (sayfalama ile daha iyi yapılmayan) elde ettiğiniz tek kazancın, kimsenin gerçekten umursamadığı "bir süreci kendinden koru" sorununa bir çözüm olması dışında bunu yapabilir. Pratikte elde ettiğiniz şey, çok az fayda sağlamak için her ikisinin de karmaşıklığı ve her ikisinin de yüküdür.

Bu nedenle 80x86 için tasarlanan neredeyse tüm işletim sistemleri bellek yönetimi için segmentasyon kullanmazlar (CPU başına ve görev başına depolama gibi şeyler için kullanırlar, ancak bunlar genellikle daha kullanışlı bir genel amaçlı kayıt tüketmekten kaçınmak için kolaylık sağlar bir şeyler).

Elbette CPU üreticileri aptal değil - kimsenin kullanmadığı bir şeyi optimize etmek için zaman ve para harcamazlar (bunun yerine neredeyse herkesin kullandığı bir şeyi optimize edecekler). Bu nedenle CPU üreticileri segmentasyonu optimize etmez, bu da segmentasyonu olduğundan daha yavaş yapar, bu da OS geliştiricilerinin bundan daha fazla kaçınmasını ister. Çoğunlukla sadece geriye dönük uyumluluk için segmentasyonu muhafaza ettiler (bu önemlidir).

Sonunda AMD uzun modu tasarladı. Endişelenecek eski/mevcut 64 bit kod yoktu, bu yüzden (64 bit kod için) AMD ellerinden geldiğince fazla segmentasyondan kurtuldu. Bu, OS geliştiricilerine, segmentasyondan kaçınmaya devam etmeleri için başka bir neden (64-bit'e segmentasyon için tasarlanmış port kodunun kolay bir yolu yok) verdi.

16
Brendan

Bu sorunun gönderildiği günden bu yana hiç kimsenin bölümlere ayrılmış bellek mimarilerinin kökenlerinden ve karşılayabilecekleri gerçek güçten bahsetmediğinden oldukça şaşırdım.

Bölünmüş disk belleği olan sanal bellek sistemlerinin (simetrik çoklu işlem ve hiyerarşik dosya sistemleri ile birlikte) tasarımını ve kullanımını çevreleyen tüm özellikleri icat eden veya yararlı bir forma dönüştüren orijinal sistem Multics (ve bkz. ayrıca Multicians sitesi). Bölünmüş bellek, Multics'in kullanıcıya her şeyin (sanal) bellekte olduğunu ve her şey doğrudan biçimde (yani doğrudan bellekte adreslenebilir). Dosya sistemi, bellekteki tüm segmentlerin bir haritası haline gelir. Düzgün bir şekilde sistematik bir şekilde kullanıldığında (Multics'te olduğu gibi) bölümlenmiş bellek, kullanıcıyı ikincil depolamayı yönetme, veri paylaşımı ve süreçler arası iletişimin birçok yükünden kurtarır. Diğer cevaplar, bölünmüş hafızanın kullanımının daha zor olduğu konusunda bazı el yapımı dalgalı iddialarda bulundu, ancak bu sadece doğru değil ve Multics, on yıl önce başarılı bir başarı ile kanıtladı.

Intel, 80286'nın oldukça güçlü olmasına rağmen, sınırlamalarının gerçekten kullanışlı herhangi bir şey için kullanılmasını engellediği, bölünmüş bir bellek parçası oluşturdu. 80386, bu sınırlamalara göre iyileşti, ancak o zamanki piyasa güçleri, bu iyileştirmelerden gerçekten yararlanabilecek herhangi bir sistemin başarısını hemen hemen engelledi. Görünüşünden bu yana çok fazla insan geçmişin derslerini görmezden gelmeyi öğrendi.

Intel ayrıca, o zamanlar başka bir şeyi aşacak olan iAPX 432 adında daha yetenekli bir süper mikro inşa etmeye çalıştı ve segmentli bir bellek mimarisine ve nesneye yönelik olarak yönlendirilmiş diğer özelliklere sahipti. programlama. Orijinal uygulama çok yavaştı ve düzeltmek için başka bir girişimde bulunulmadı.

Multics'in segmentasyon ve sayfalamayı nasıl kullandığı hakkında daha ayrıntılı bir tartışma Paul Green'in makalesinde bulunabilir Multics Sanal Bellek - Eğitim ve Yansımalar

14
Greg A. Woods

Segmentasyon, 16 bit işlemci tarafından 1 MB'a kadar belleğin adreslenmesine izin veren bir saldırı/geçici çözümdü - normalde yalnızca 64K belleğe erişilebiliyordu.

32 bit işlemciler geldiğinde, düz bir bellek modeliyle 4GB'a kadar belleğe hitap edebilirsiniz ve artık segmentasyona gerek kalmadı - Segment kayıtları, korumalı modda GDT/sayfalama için seçici olarak yeniden tasarlandı ( 16-bit korumalı moda sahip).

Ayrıca düz bir bellek modu derleyiciler için çok daha uygundur - yazabilirsiniz C 16 bit bölümlü programlar , ama biraz hantal. Düz bellek modeli her şeyi kolaylaştırır.

6
Justin

Bazı mimariler (ARM gibi) bellek segmentlerini desteklemez. Linux parçalara kaynağa bağlı olsaydı, bu mimarilere çok kolay taşınamazdı.

Daha geniş resme bakıldığında, bellek segmentlerinin başarısızlığı, C ve işaretçi aritmetiğinin sürekli popülaritesi ile ilgilidir. C geliştirme düz belleğe sahip bir mimaride daha pratiktir; ve düz bellek istiyorsanız, bellek disk belleği seçersiniz.

Bir organizasyon olarak Intel'in Ada'nın ve diğer üst düzey programlama dillerinin gelecekteki popülaritesini tahmin ettiği 80'li yılların başlarında bir zaman vardı. Temelde, korkunç APX432 ve 286 bellek segmentasyonu gibi daha muhteşem arızalarının bir kısmı burada ortaya çıktı. 386 ile düz bellek programcılarına teslim oldular; sayfalama yapıldı ve bir TLB eklendi ve segmentler 4GB'a yeniden boyutlandırılabilir hale getirildi. Ve sonra AMD temelde x86_64 ile segmentleri temel reg'i bir dont-care/zımni-0 yaparak kaldı (TLS için fs? Hariç mi?)

Bununla birlikte, bellek segmentlerinin avantajları açıktır - bir TLB'yi yeniden doldurmak zorunda kalmadan adres alanlarını değiştirmek. Belki bir gün birisi segmentasyonu destekleyen performans açısından rekabetçi bir CPU yapacak, bunun için segmentasyon odaklı bir işletim sistemi programlayabiliriz ve programcılar Ada/Pascal/D/Rust/düz-gerektirmeyen bir başka langage yapabilir -hafıza için bellek programları.

5
Ted Middleton

Segmentasyon, uygulama geliştiricileri için büyük bir yüktür. Büyük Push'un segmentasyonu ortadan kaldırmak için geldiği yer burasıdır.

İlginçtir ki, Intel bu eski modlar için tüm eski desteği çıkarırsa i86'nın ne kadar iyi olabileceğini merak ediyorum. Burada daha iyi daha düşük güç ve daha hızlı çalışma anlamına gelir.

Sanırım Intel'in sütü 16bit segmentle eklediğini iddia edebilirdi. Ancak 64k adres alanının özellikle modern uygulamaya baktığınızda hiçbir şey olmadığını kabul edelim. Sonunda bir şeyler yapmak zorundaydılar çünkü rekabet, i86'nın adres alanı sorunlarına karşı etkili bir şekilde pazarlanabilirdi ve pazarladı.

1
Dave

Segmentasyon daha yavaş sayfa çevirisine ve değiştirilmesine yol açar

Bu nedenlerden dolayı, segmentasyon büyük ölçüde x86-64'e düşürüldü.

Aralarındaki ana fark şudur:

  • disk belleği belleği sabit boyutlu parçalara ayırır
  • segmentasyon her yığın için farklı genişliklere izin verir

Yapılandırılabilir segment genişliklerine sahip olmak daha akıllı görünebilir, ancak bir işlem için bellek boyutunu artırdığınızda, parçalanma kaçınılmazdır, örneğin:

|   | process 1 |       | process 2 |                        |
     -----------         -----------
0                                                            max

sonunda süreç 1 büyüdükçe:

|   | process 1        || process 2 |                        |
     ------------------  -------------
0                                                            max

bir bölünme kaçınılmaz olana kadar:

|   | process 1 part 1 || process 2 |   | process 1 part 2 | |
     ------------------  -----------     ------------------
0                                                            max

Bu noktada:

  • sayfaları çevirmenin tek yolu, işlem 1'in tüm sayfaları üzerinde kabul edilemez bir günlük (n) alan ikili aramalar yapmaktır
  • süreç 1 bölüm 1 dışında bir takas büyük olabilir, çünkü bu segment çok büyük olabilir

Ancak sabit boyutlu sayfalarda:

  • her 32 bit çeviri sadece 2 bellek okuması yapar: dizin ve sayfa tablosu yürüyüşü
  • her takas kabul edilebilir bir 4KiB'dir

Sabit boyutlu bellek parçaları daha kolay yönetilebilir ve mevcut işletim sistemi tasarımına hakim olmuştur.

Ayrıca bakınız: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work