Linux bölümleme değil sadece sayfalama kullanıyor mu?


24

Linux Programlama Arayüzü , bir sürecin sanal adres alanının düzenini gösterir. Diyagramdaki her bölge bir bölüm mü?

görüntü tanımını buraya girin

Gönderen Linux Kernel anlama ,

Aşağıdakiler, MMU’daki segmentasyon biriminin, segmentler içindeki segmentleri ve ofsetleri sanal bellek adresine eşlediğini ve çağrı ünitesinden sonra sanal bellek adresini fiziksel bellek adresine eşlediği anlamına mı geliyor?

Bellek Yönetim Birimi (MMU), mantıksal bir adresi, bölümleme birimi adı verilen bir donanım devresi aracılığıyla doğrusal bir adrese dönüştürür; daha sonra, çağrı birimi adı verilen ikinci bir donanım devresi, doğrusal adresi fiziksel bir adrese dönüştürür (bkz. Şekil 2-1).

görüntü tanımını buraya girin

Öyleyse neden Linux'un segmentasyonu kullanmadığını, sadece çağrı kullandığını söylüyor?

Segmentasyon, programcıları, uygulamalarını alt rutinler veya global ve yerel veri alanları gibi mantıksal olarak ilişkili varlıklara bölmeye teşvik etmek için 80x86 mikroişlemcilere dahil edilmiştir. Ancak, Linux bölümlemeyi çok sınırlı bir şekilde kullanır. Aslında, bölümleme ve sayfalama biraz gereksizdir, çünkü her ikisi de işlemlerin fiziksel adres alanlarını ayırmak için kullanılabilir: bölümleme, her bir işleme farklı bir doğrusal adres alanı atayabilirken, sayfalama aynı doğrusal adres alanını farklı fiziksel adres alanlarına eşleyebilir . Linux, aşağıdaki nedenlerle sayfalandırmayı tercih ediyor:

• Tüm işlemler aynı segment kayıt değerlerini kullandığında (yani aynı doğrusal adres kümesini paylaştığında) bellek yönetimi daha basittir.

• Linux'un tasarım hedeflerinden biri, geniş bir mimariye taşınabilirlik; Özellikle RISC mimarileri, bölümlendirme için sınırlı bir desteğe sahiptir.

Linux'un 2.6 sürümü, yalnızca 80x86 mimarisinin gerektirdiği durumlarda bölümlemeyi kullanır.


Lütfen sürümleri belirtebilir misiniz? Yazar adlarını belirtmek de yardımcı olabilir. En azından ilk tanınmış bir kişiden olduğunu biliyorum. Ancak, her iki başlık adının da biraz genel olduğu, ilk başta kitaplardan bahsettiğiniz bana açık değildi :-).
sourcejedi

2
Re "Bölümleme 80x86 mikroişlemcilere dahil edildi ...": Bu doğru değil. 16 bit veri işaretçisi ve 64 Kb bellek segmentine sahip 808x işlemcilerin mirası. Segment işaretçiler, daha fazla hafızaya yönlendirmek için segmentleri değiştirmenize izin verdi. Bu mimari 80x86'ya taşındı (işaretçi boyutu 33 bite yükseldi). Bugünlerde x86_64 modelinde 64 bitlik göstericiniz var (teorik olarak - sanırım sadece 48 bit kullanılıyor) 16 exabyte'a hitap ediyor, bu yüzden segmentler gerekli değil.
jamesqf

2
jamesqf, 386'daki 32 bit korumalı mod, 8086'da oldukları 16 baytlık ölçeklendiriciden oldukça farklı olan segmentleri destekliyor, bu yüzden sadece düz miras değil. Tabii ki faydaları hakkında bir şey söylemek değil.
ilkkachu

@jamesqf 80186 8086 ile aynı bellek modeline sahipti, "33 bit" yok
Jasen

Yanıtlamaya değmez, bu nedenle sadece bir yorum: Segmentler ve Sayfalar yalnızca takas bağlamında karşılaştırılabilir (örn. Sayfa takas vs rakip takas) ve bu bağlamda Sayfa takas sadece segmenti takas ederek sudan çıkarır. Segmentleri içeri / dışarı kaydırırsanız, 2-4GB olabilen tüm segmenti değiştirmeniz gerekir . Bu x86'da kullanılacak gerçek bir şey olmamıştı. Sayfalarla her zaman 4KB birimde çalışabilirsiniz. Belleğe erişim söz konusu olduğunda, bölümler ve sayfalar sayfa tablolarıyla ilişkilendirilir ve karşılaştırma elmalar ile portakal olur.
vhu

Yanıtlar:


20

X86-64 mimarisi, uzun modda bölümlendirme kullanmaz (64 bit mod).

Segment kayıtlarının dördü: CS, SS, DS ve ES 0'a ve limit 2 ^ 64'e zorlanır.

https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments

Artık OS'nin "doğrusal adreslerin" hangi aralıklarının mevcut olduğunu sınırlaması mümkün değildir. Bu nedenle bellek koruması için segmentasyon kullanamaz; tamamen sayfalamaya dayanması gerekir.

Yalnızca eski 32-bit modlarında çalışırken geçerli olacak x86 işlemcilerin ayrıntıları hakkında endişelenmeyin. 32-bit modları için Linux kadar kullanılmaz. Hatta "birkaç yıl boyunca iyi huysuz bir ihmal durumunda" olarak kabul edilebilir. Fedora'daki 32-Bit x86 desteğine bakın [LWN.net, 2017].

(32 bit Linux da segmentasyon kullanmıyor, olur. Fakat bunda bana güvenmene gerek yok, görmezden gelebilirsin :-).


Bu biraz fazla abartı. taban / limit, eski orijinal-8086 segmentleri (CS / DS / ES / SS) için uzun modda 0 / -1 olarak sabitlenir, ancak FS ve GS hala rasgele segment tabanına sahiptir. CS'ye yüklenen segment tanımlayıcısı, işlemcinin 32 veya 64 bit modunda çalışıp çalışmayacağını belirler. Ve x86-64'teki kullanıcı alanı Linux, iş parçacığı yerel depolama ( mov eax, [fs:rdi + 16]) için FS kullanır . Çekirdek swapgs, geçerli işlemin çekirdek yığınını syscallgiriş noktasındaki yerini bulmak için GS'yi (sonra ) kullanır . Ancak evet, segmentasyon ana işletim sistemi bellek yönetimi / bellek koruma mekanizmasının bir parçası olarak kullanılmaz.
Peter Cordes

Temelde, "Linux'un 2.6 sürümü yalnızca 80x86 mimarisinin gerektirdiği durumlarda segmentasyonu kullanıyor." Fakat 2. paragrafınız temelde yanlıştır. Linux, 32 ve 64 bit modlarında temel olarak aynı bölümleme kullanır. yani normal talimatlarla dolaylı olarak kullanılan klasik bölümler (CS / DS / ES / SS) için base = 0 / limit = 2 ^ 32 veya 2 ^ 64. 32 bit Linux kodunda endişelenecek "fazladan" hiçbir şey yok; HW işlevi var ancak kullanılmıyor.
Peter Cordes

@PeterCord, temelde cevabı yanlış yorumladığınızı :-) gösterir. Bu yüzden tartışmamı daha az belirsiz hale getirmek için denedim.
sourcejedi

İyi gelişme, şimdi yanıltıcı değil. Gerçek noktanıza tamamen katılıyorum, yani x86 segmentasyonunu tamamen görmezden gelebilirsiniz ve görmezden gelmelisiniz, çünkü sadece osdev sistem yönetimi işleri ve TLS için kullanılıyor. Sonunda öğrenmek istiyorsanız, düz bir bellek modeliyle x86 asm cihazını zaten anladıktan sonra anlamanız çok daha kolay.
Peter Cordes

8

X86 segmentlere sahip olduğundan, bunları kullanmamak mümkün değildir. Ancak hem cs(kod segmenti) hem de ( dsveri segmenti) temel adresleri sıfıra ayarlanmıştır, bu nedenle bölümlendirme gerçekten kullanılmaz. Bunun bir istisnası yerel veri iş parçacığıdır, normalde kullanılmayan segment kayıtlarından biri yerel veri iş parçacığına işaret eder. Ancak bu genel olarak bu amaç için genel amaçlı kayıtlardan birini rezerve etmekten kaçınmaktır.

Linux'un x86'da segmentasyonu kullanmadığı, mümkün olamayacağı söylenmiyor. Zaten bir bölümü vurguladınız, Linux bölümlemeyi çok sınırlı bir şekilde kullanıyor . İkinci bölüm Linux, yalnızca 80x86 mimarisinin gerektirdiği durumlarda segmentasyon kullanıyor

Nedenleri alıntı yaptınız, çağrı yapmak daha kolay ve daha taşınabilir.


7

Diyagramdaki her bölge bir bölüm mü?

Yok hayır.

Segmentasyon sistemi (x86'da 32 bit korumalı modda) ayrı kod, veri ve yığın segmentlerini destekleyecek şekilde tasarlanırken, pratikte tüm bölümler aynı hafıza alanına ayarlanmıştır. Yani, 0'da başlar ve hafızanın sonunda (*) biterler . Bu mantıksal adresleri ve doğrusal adresleri eşit yapar.

Buna "düz" bellek modeli denir ve farklı bölümlere sahip olduğunuzdan ve sonra bunların içindeki işaretçilerden biraz daha basittir. Özellikle, bir bölümlenmiş model, daha uzun işaretçiler gerektirir çünkü bölüm seçicisinin ofset işaretçisine ek olarak dahil edilmesi gerekir. (16-bit segment seçici + toplam 48 bit işaretçi için 32 bit ofset; yalnızca 32 bit düz işaretçi.)

64 bit uzunluğundaki mod, düz bellek modelinden başka bir bölümü bile desteklemiyor.

Eğer 286'da 16-bit korumalı modda programlayacak olsaydınız, adres alanı 24 bit, ancak işaretçiler sadece 16 bit olduğundan, segmentlere daha fazla ihtiyaç duyarsınız.

(* 32 bit Linux'un çekirdek / kullanıcı alanı ayrımını nasıl işlediğini hatırlayamadığımı unutmayın. Segmentasyon, kullanıcı alanı bölümlerinin sınırlarını ayarlayarak çekirdek alanını içermemelerini sağlayacak şekilde izin verir. sayfa başına koruma seviyesi.)

Öyleyse neden Linux'un segmentasyonu kullanmadığını, sadece çağrı kullandığını söylüyor?

X86 hala segmentlere sahip ve onları devre dışı bırakamazsınız. Sadece mümkün olduğunca az kullanılıyorlar. 32 bit korumalı modda, segmentlerin düz model için ayarlanması gerekir ve hatta 64 bit modda bile varlığını sürdürürler.


Huh, 32 bitlik bir çekirdeğin, kullanıcı alanını 2G veya 3G'den daha fazla erişmesini engelleyen CS / DS / ES / SS üzerinde bölüm sınırlarını belirleyerek Meltdown'u sayfa tablolarını değiştirmekten daha ucuz bir şekilde azaltabileceğini tahmin ediyorum. (Meltdown vuln, sayfa tablosu girişlerinde çekirdek / kullanıcı biti için bir geçici çözümdür, kullanıcı alanının yalnızca çekirdekli eşlenmiş sayfalardan okumasına izin verir). VDSO sayfaları 4G'nin üst kısmında eşleştirilebilir, ancak: / wrfsbasekorumalı / uyumlu modda yasadışı, sadece uzun modda, 32 bitlik bir çekirdek kullanıcı alanında FS tabanını yüksek ayarlayamadı.
Peter Cordes

64 bitlik bir çekirdekte, 32 bitlik bir kullanıcı alanı potansiyel olarak 64 bitlik bir kod segmentine atlayabilir, bu nedenle Meltdown koruması için yalnızca sınırsız 32 bitlik bir çekirdekte sınır sınırlarına güvenemezsiniz. (Çok fazla fiziksel RAM içeren makinelerde büyük dezavantajları vardır, örneğin iplik yığınları için düşük mem azalıyor.) Yine de, evet Linux çekirdek belleği disk belleği ile koruyarak, normal / kullanıcı alanında taban / limit = 0 / -1 bıraktı. bölümler (iş parçacığı yerel depolama için kullanılan FS / GS değil).
Peter Cordes

NX biti donanım sayfa tablolarında (PAE) desteklenmeden önce, bazı eski güvenlik yamaları, kullanıcı-alanı kodu için çalıştırılabilir olmayan yığınlar yapmak için segmentasyonu kullandı. örneğin linux.com/news/exec-shield-new-linux-security-feature (Ingo Molnar’ın görevinde "Solar Designer’ın mükemmel" icra edilmeyen yığın yaması "" yazıyor .)
Peter Cordes

3

Linux x86 / 32, bölümlemeyi tüm bölümleri aynı doğrusal adres ve sınırda başlatması anlamında kullanmaz. x86 mimarisi, programın bölümlere sahip olmasını gerektirir: kod yalnızca kod bölümünden yürütülebilir, yığın yalnızca yığın bölümünde bulunabilir, veriler yalnızca veri bölümlerinden birinde değiştirilebilir. Linux, bu bölümleri tüm bölümleri aynı şekilde (kitabınızın zaten bahsetmediği istisnalar dışında) aynı şekilde ayarlayarak atlar, böylece aynı mantıksal adres herhangi bir bölüm için geçerlidir. Bu aslında hiç bir kesime sahip olmamaya eşdeğerdir.


2

Diyagramdaki her bölge bir bölüm mü?

Bunlar "segment" kelimesinin neredeyse tamamen farklı 2 kullanımıdır

  • x86 segmentasyon / segment kayıtları: modern x86 işletim sistemleri, tüm segmentlerin aynı taban = 0 ve limit = 32-bit modunda maksimum olduğu, donanımın da 64-bit modda uyguladığı ve bölümleme türünü daha belirgin hale getirdiği düz bir bellek modeli kullanır . (FS veya GS hariç, 64 bit modunda bile yerel iş parçacığı depolaması için kullanılır.)
  • Bağlayıcı / program yükleyici bölümleri / bölümleri. ( ELF dosya formatındaki kesit ve segment farkı nedir )

Kullanımları ortak orjine sahip: eğer edildi parçalara ayrılmış bir hafıza modeli (özellikle disk belleği sanal bellek olmadan) kullanılarak, veri sahip olabilir ve BSS adresleri DS kademeli baz SS tabanına yığın göre ve kod göreli olarak göreli CS taban adresi.

Böylelikle birden fazla farklı program, farklı doğrusal adreslere yüklenebilir ya da bölüm tabanlarına göre 16 veya 32 bit ofsetleri değiştirmeden başlattıktan sonra bile taşınabilir.

Ancak bir işaretçinin hangi segmente göre olduğunu bilmeniz gerekir, bu yüzden "uzak işaretçiler" vb. Vardır. (Gerçek 16-bit x86 programları genellikle kodlarına veri olarak erişmeye ihtiyaç duymazlardı, bu nedenle bir yerde 64k kod segmentini ve belki de DS = SS ile başka bir 64k bloğunu kullanabilirdi; Ya da tüm segment bazları eşit olan küçük bir kod modeli).


X86 segmentasyonu sayfalama ile nasıl etkileşime girer?

32/64-bit modunda adres eşleme:

  1. segment: offset (ofseti tutan ya da bir talimat önekiyle geçersiz kılınan kayıt defterinde belirtilen bölüm tabanı)
  2. 32 veya 64-bit doğrusal sanal adres = base + offset. (Linux gibi düz bir bellek modelinde, işaretçiler / ofsetler = doğrusal adresler de geçerlidir. FS veya GS'ye göre TLS'ye erişme hariç.)
  3. sayfa tabloları (TLB tarafından önbelleğe alınmış), 32 (eski mod), 36 (eski PAE) veya 52 bit (x86-64) fiziksel adrese doğrusal eşlenir. ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).

    Bu adım isteğe bağlıdır: disk belleği, başlatma sırasında bir kontrol kaydında bir bit ayarlayarak etkinleştirilmelidir. Sayfalama olmadan, doğrusal adresler fiziksel adreslerdir.

Segmentasyon olmadığını Bildirimi değil tek bir süreç (veya iplik) sanal adres alanı fazla 32 veya 64 bit kullanmasına izin sadece uzaklıklar kendilerini bit aynı sayıda içine düz (doğrusal) adres alanı her şey eşleştirilmiş çünkü. (Bu, 16 bit x86 için geçerli değildi, burada bölümlendirme, çoğunlukla 16 bit kayıt ve ofsetlerde 64k'dan fazla bellek kullanmak için faydalıydı.)


CPU, segment tabanı da dahil olmak üzere GDT'den (veya LDT) yüklenen segment tanımlayıcılarını önbelleğe alır. Bir işaretçiyi tercih ettiğinizde, hangi kayıt defterine bağlı olduğuna bağlı olarak, varsayılan olarak DS veya SS olarak değişir. Kayıt değeri (işaretçi), segment tabanından bir kayma olarak değerlendirilir.

Segment tabanı normalde sıfır olduğundan, CPU'lar bunu özel olarak yapar. Eğer Veya başka bir perspektiften, do sıfır olmayan bir segmenti üssü var, yükler ekstra gecikme var çünkü taban adresi geçerli değildir ekleyerek atlatacak bir "özel" (normal) durumda.


Linux x86 segment kayıtlarını nasıl kurar:

CS / DS / ES / SS'nin tabanı ve sınırı 32 ve 64-bit modunda 0 / -1'dir. Buna tüm işaretçiler aynı adres alanına işaret ettiği için buna düz bellek modeli denir.

(AMD CPU , 64-bit modu için düz bellek modelini zorlayarak bölümlendirmeyi kısırlaştırır, çünkü ana işletim sistemleri zaten PAE veya x86 ile çağrı yaparak çok daha iyi bir şekilde sağlanan yürütme koruması dışında 64 sayfa tablosu formatı.)

  • TLS (Konu Yerel Depolama): FS ve GS edilir değil uzun modda tabanında = 0 sabit. (386 ile repyeniydiler ve ES kullanan -sürekli yönergeler bile değil, hiçbir talimatla örtük olarak kullanılmamışlardı ). x86-64 Linux, her iş parçacığı için FS temel adresini TLS bloğunun adresine ayarlar.

    örneğin mov eax, [fs: 16], bu iş parçacığı için 32 bitlik bir değeri 16 baytlık TLS bloğuna yükler.

  • CS segmenti tanımlayıcısı CPU'nun hangi modda olduğunu seçer (16/32/64-bit korumalı mod / uzun mod). Linux, tüm 64 bit kullanıcı alanı işlemleri için tek bir GDT girişi ve tüm 32 bit kullanıcı alanı işlemleri için başka bir GDT girişi kullanır. (İşlemcinin düzgün çalışması için DS / ES'nin de geçerli girişlere ayarlanması gerekir, SS de öyledir). Ayrıca, ayrıcalık seviyesini de seçer (çekirdek (ring 0) vs. kullanıcı (ring 3)), bu yüzden 64 bitlik bir kullanıcı alanına geri dönerken bile, çekirdeğin CS'yi normal bir yerine değiştirmek, kullanmak iretveya sysretyerine değiştirmek için düzenlemesi gerekir. atlama veya ret talimatı.

  • X86-64'te syscallgiriş noktası GS'yi swapgskullanıcı alanının GS'sinden çekirdeğe çevirmek için kullanır, bu iş parçacığı için çekirdek yığınını bulmak için kullanır. (Özel bir yerel iş parçacığı saklama durumu). syscallKullanıcı çekirdek yığını noktaya yığın işaretçisi değiştirmez; çekirdek, giriş noktası 1'e ulaştığında hala kullanıcı yığınına işaret ediyor .

  • DS / ES / SS'nin, CPU'nun korumalı modda / uzun modda çalışması için geçerli segment tanımlayıcılarına ayarlanması gerekir, ancak bu tanımlayıcılardan gelen taban / limit uzun modda göz ardı edilir.

Temelde x86 segmentasyonu, TLS ve donanımın gerektirdiği zorunlu x86 osdev işleri için kullanılır.


Dipnot 1: Eğlenceli tarih: AMD64 silikonu piyasaya sürülmesinden birkaç yıl önce çekirdek devleri ile AMD mimarları arasında mesaj listesi arşivleri var, bu da tasarımın üzerinde tweaks syscalloldu. Ayrıntılar için bu cevaptaki bağlantılara bakın .

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.