Bilgisayarlarda, bir işlemin yürütülebilir olması için belleğe yerleştirilmesi gerekir. Bunun için bellekteki bir işleme bir alan atanmalıdır. Bellek tahsisi, özellikle çekirdek ve sistem mimarilerinde dikkat edilmesi gereken önemli bir konudur.
Gelin, Linux bellek tahsisine ayrıntılı olarak bir göz atalım ve perde arkasında neler olduğunu anlayalım.
Bellek Tahsisi Nasıl Yapılır?
Çoğu yazılım mühendisi bu sürecin ayrıntılarını bilmiyor. Ancak bir sistem programcısı adayıysanız, bunun hakkında daha fazla bilgi sahibi olmalısınız. Tahsis sürecine bakarken, Linux ve Linux üzerinde biraz detaya girmek gerekiyor. glibc kütüphane.
Uygulamaların belleğe ihtiyacı olduğunda, işletim sisteminden talep etmeleri gerekir. Çekirdekten gelen bu istek, doğal olarak bir sistem çağrısı gerektirecektir. Kullanıcı modunda kendinize bellek ayıramazsınız.
bu malloc() Fonksiyon ailesi, C dilinde bellek tahsisinden sorumludur. Burada sorulması gereken soru, glibc işlevi olarak malloc()'un doğrudan sistem çağrısı yapıp yapmadığıdır.
Linux çekirdeğinde malloc adında bir sistem çağrısı yoktur. Ancak, uygulamaların bellek talepleri için iki sistem çağrısı vardır. brk ve harita.
Uygulamanızda glibc işlevleri aracılığıyla bellek talebinde bulunacağınız için, bu noktada glibc'nin bu sistem çağrılarından hangisinin kullanıldığını merak ediyor olabilirsiniz. Cevap her ikisi de.
İlk Sistem Çağrısı: brk
Her prosesin bitişik bir veri alanı vardır. brk sistem çağrısı ile veri alanının limitini belirleyen program kesme değeri arttırılır ve tahsis işlemi gerçekleştirilir.
Bu yöntemle bellek ayırma çok hızlı olsa da kullanılmayan alanı sisteme geri döndürmek her zaman mümkün değildir.
Örneğin, malloc() işlevi aracılığıyla brk sistem çağrısıyla her biri 16 KB boyutunda beş alan ayırdığınızı düşünün. Bu alanlardan iki tanesi ile işiniz bittiğinde, ilgili kaynağın (deallocation) sistemin kullanabilmesi için iade edilmesi mümkün değildir. Çünkü adres değerini iki numaralı alanınızın başladığı yeri gösterecek şekilde azaltırsanız, brk çağrısı ile üç, dört ve beş numaralı alanlar için ayırma işlemi yapmış olursunuz.
Bu senaryoda bellek kaybını önlemek için glibc'deki malloc uygulaması, işlem verileri alanında ayrılan yerleri izler ve daha sonra sistemin boş alanı daha fazla bellek için kullanabilmesi için free() işleviyle sisteme geri döndürüleceğini belirtir. tahsisler.
Diğer bir deyişle, beş adet 16 KB alan ayrıldıktan sonra, ikinci alan free() işlevi ve başka bir 16 KB alan ile döndürülürse bir süre sonra tekrar istenirse brk sistem çağrısı ile veri alanını genişletmek yerine önceki adrese dönülür.
Ancak yeni talep edilen alan 16 KB'den büyükse ikinci alan kullanılamayacağı için brk sistem çağrısı ile yeni bir alan ayrılarak veri alanı genişletilecektir. İki numaralı alan kullanımda olmasa da boyut farkından dolayı uygulama kullanamıyor. Bunun gibi senaryolar nedeniyle iç parçalanma denen bir durum var ve aslında nadiren hafızanın tüm kısımlarını tam olarak kullanabiliyorsunuz.
Daha iyi anlamak için aşağıdaki örnek uygulamayı derleyip çalıştırmayı deneyin:
#Dahil etmek <stdio.h>
#Dahil etmek <stdlib.h>
#Dahil etmek <unistd.h>
intana(int argc, karakter* argv[])
{
karakter *ptr[7];
int n;
yazdırf("%s özeti: %d", argv[0], getpid());
yazdırf("İlk program sonu: %p", sbrk (0));
için (n=0; n<5; n++) ptr[n] = malloc (16 * 1024);
yazdırf("5 x 16kB malloc'tan sonra: %p", sbrk (0));
Bedava(ptr[1]);
yazdırf("Ücretsiz ikinci 16kB'den sonra: %p", sbrk (0));
ptr[5] = malloc (16 * 1024);
yazdırf("16kB'nin 6.'sını ayırdıktan sonra: %p", sbrk (0));
Bedava(ptr[5]);
yazdırf("Son bloğu serbest bıraktıktan sonra: %p", sbrk (0));
ptr[6] = malloc (18 * 1024);
yazdırf("Yeni bir 18kB tahsis ettikten sonra: %p", sbrk (0));
getchar();
dönüş0;
}
Uygulamayı çalıştırdığınızda aşağıdaki çıktıya benzer bir sonuç elde edeceksiniz:
Pid ./a.out: 31990
Başlangıç programı kırmak: 0x55ebcadf4000
5 x 16kB malloc'tan sonra: 0x55ebcadf4000
İkinci 16kB'den sonra: 0x55ebcadf4000
16kB'nin 6.'sını ayırdıktan sonra: 0x55ebcadf4000
Son bloğu serbest bıraktıktan sonra: 0x55ebcadf4000
tahsis ettikten sonra yeni18kB: 0x55ebcadf4000
strace ile brk çıktısı aşağıdaki gibi olacaktır:
brk(BOŞ) = 0x5608595b6000
brk (0x5608595d7000) = 0x5608595d7000
Gördüğünüz gibi, 0x21000 veri alanının bitiş adresine eklenmiştir. Bunu değerden anlayabilirsiniz 0x5608595d7000. Yani yaklaşık 0x21000veya 132 KB bellek ayrıldı.
Burada dikkate alınması gereken iki önemli nokta vardır. Birincisi, örnek kodda belirtilen miktardan daha fazla tahsis edilmesidir. Bir diğeri, tahsisi sağlayan brk çağrısına hangi kod satırının neden olduğudur.
Adres Alanı Düzeni Rastgeleleştirme: ASLR
Yukarıdaki örnek uygulamayı arka arkaya çalıştırdığınızda her seferinde farklı adres değerleri göreceksiniz. Adres alanını bu şekilde rastgele değiştirmek, güvenlik saldırıları ve yazılım güvenliğini artırır.
Bununla birlikte, 32 bit mimarilerde, adres alanını rastgele yapmak için genellikle sekiz bit kullanılır. Kalan bitlerin üzerindeki adreslenebilir alan çok az olacağından bit sayısının arttırılması uygun olmayacaktır. Ayrıca sadece 8 bitlik kombinasyonların kullanılması saldırgan için işleri yeterince zorlaştırmaz.
64 bit mimarilerde ise ASLR işlemi için ayrılabilecek çok fazla bit olduğundan çok daha fazla rastgelelik sağlanır ve güvenlik derecesi artar.
Linux çekirdeği ayrıca güç sağlar Android tabanlı cihazlar ve ASLR özelliği Android 4.0.3 ve sonraki sürümlerde tamamen etkinleştirilmiştir. Sırf bu nedenle bile 64 bit akıllı telefonun 32 bit sürümlere göre ciddi bir güvenlik avantajı sağladığını söylemek yanlış olmaz.
Aşağıdaki komutla ASLR özelliği geçici olarak devre dışı bırakıldığında, önceki test uygulamasının her çalıştırıldığında aynı adres değerlerini döndürdüğü görülecektir:
Eko0 | sudo tee /proc/sys/kernel/randomize_va_space
Eski haline döndürmek için aynı dosyada 0 yerine 2 yazmanız yeterli olacaktır.
İkinci Sistem Çağrısı: mmap
mmap, Linux'ta bellek ayırma için kullanılan ikinci sistem çağrısıdır. mmap çağrısı ile, belleğin herhangi bir alanındaki boş alan, çağrı işleminin adres alanına eşlenir.
Bu şekilde yapılan bir bellek tahsisinde, bir önceki brk örneğindeki free() işleviyle ikinci 16KB'lık bölümü döndürmek istediğinizde, bu işlemi engelleyecek bir mekanizma yoktur. İlgili bellek segmenti işlemin adres alanından kaldırılır. Artık kullanılmıyor olarak işaretlenir ve sisteme iade edilir.
mmap ile bellek ayırmaları brk ile karşılaştırıldığında çok yavaş olduğundan, brk ayırma gereklidir.
mmap ile, herhangi bir boş bellek alanı işlemin adres alanıyla eşleştirilir, böylece bu işlem tamamlanmadan önce ayrılan alanın içeriği sıfırlanır. Reset bu şekilde yapılmadıysa, daha önce ilgili hafıza alanını kullanan işleme ait verilere, bir sonraki ilgisiz işlem tarafından da erişilebilir. Bu, sistemlerde güvenlik hakkında konuşmayı imkansız hale getirecektir.
Linux'ta Bellek Tahsisinin Önemi
Bellek tahsisi özellikle optimizasyon ve güvenlik konularında çok önemlidir. Yukarıdaki örneklerde de görüldüğü gibi, bu konuyu tam olarak anlamamak, sisteminizin güvenliğini yok etmek anlamına gelebilir.
Birçok programlama dilinde var olan push ve pop gibi kavramlar bile bellek ayırma işlemlerine dayanmaktadır. Sistem belleğini iyi kullanabilmek ve iyi yönetebilmek hem gömülü sistem programlamada hem de güvenli ve optimize edilmiş bir sistem mimarisi geliştirmede hayati önem taşır.
Ayrıca Linux çekirdeği geliştirmeye de ayak uydurmak istiyorsanız, önce C programlama dilinde uzmanlaşmayı düşünün.
C Programlama Diline Kısa Bir Giriş
Sonrakini Oku
İlgili konular
- Linux
- Bilgisayar hafızası
- Linux çekirdeği
Yazar hakkında
Matematik ve teknolojinin hayranı olan bir mühendis ve yazılım geliştiricisi. Bilgisayarları, matematiği ve fiziği her zaman sevmiştir. Oyun motoru projelerinin yanı sıra makine öğrenimi, yapay sinir ağları ve lineer cebir kütüphaneleri geliştirmiştir. Ayrıca makine öğrenmesi ve lineer matrisler üzerinde çalışmalarını sürdürmektedir.
Haber bültenimize abone ol
Teknik ipuçları, incelemeler, ücretsiz e-kitaplar ve özel fırsatlar için bültenimize katılın!
Abone olmak için buraya tıklayın