.Bss segmenti neden gereklidir?


120

Bildiğim şey, global ve statik değişkenlerin .datasegmentte depolandığı ve başlatılmamış verilerin .bsssegmentte olduğu. Anlamadığım şey, neden başlatılmamış değişkenler için ayrılmış bir segmentimiz var? Başlatılmamış bir değişkenin çalışma zamanında atanmış bir değeri varsa, değişken hala .bssyalnızca segmentte mi var?

Aşağıdaki programında, aiçinde .datasegmanı ve biçinde .bsssegmenti; bu doğru mu? Anlayışım yanlışsa lütfen beni düzeltin.

#include <stdio.h>
#include <stdlib.h>

int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[20]; /* Uninitialized, so in the .bss and will not occupy space for 20 * sizeof (int) */

int main ()
{
   ;
}  

Ayrıca, aşağıdaki programı düşünün,

#include <stdio.h>
#include <stdlib.h>
int var[10];  /* Uninitialized so in .bss */
int main ()
{
   var[0] = 20  /* **Initialized, where this 'var' will be ?** */
}

3
BSS'yi Better Save Space olarak okuyabilirsiniz .
smwikipedia

Yanıtlar:


89

Nedeni, program boyutunu küçültmektir. C programınızın, kodun ve tüm sabitlerin gerçek ROM'da (flash bellek) kaydedildiği gömülü bir sistemde çalıştığını hayal edin. Bu tür sistemlerde, main () çağrılmadan önce, tüm statik depolama süresi nesnelerini ayarlamak için bir ilk "kopya aşağı" çalıştırılmalıdır. Tipik olarak şu sözde olacaktır:

for(i=0; i<all_explicitly_initialized_objects; i++)
{
  .data[i] = init_value[i];
}

memset(.bss, 
       0, 
       all_implicitly_initialized_objects);

.Data ve .bss RAM'de saklanır, ancak init_value ROM'da saklanır. Tek bir segment olsaydı, ROM'un çok sayıda sıfırla doldurulması ve ROM boyutunu önemli ölçüde artırması gerekirdi.

RAM tabanlı yürütülebilir dosyalar benzer şekilde çalışır, ancak elbette gerçek ROM'ları yoktur.

Ayrıca, memset muhtemelen çok verimli bir satır içi derleyicidir, bu da başlangıç ​​kopyalamasının daha hızlı yürütülebileceği anlamına gelir.


7
Açıklığa kavuşturmak gerekirse: .data ve .bss arasındaki tek fark, başlangıçta "kopyala" işleminin sırayla, dolayısıyla daha hızlı çalıştırılabilmesidir. Eğer iki bölüme ayrılmamış olsaydı, ilklendirmenin başlatılmamış değişkenlere ait RAM noktalarını atlaması gerekecekti, böylece zaman kaybedecekti.
CL22

80

.bssSegmenti bir optimizasyon olduğunu. Tüm .bsssegment, muhtemelen 4 bayt veya 8 baytlık tek bir sayı ile tanımlanır ve bu, çalışan işlemdeki boyutunu verirken, .databölüm, başlatılan değişkenlerin boyutlarının toplamı kadar büyüktür. Böylece, .bssçalıştırılabilir dosyaların daha küçük ve daha hızlı yüklenmesini sağlar. Aksi takdirde, değişkenler .data, sıfırlara açık ilklendirme ile segmentte olabilir ; program farkı söylemek için zorlanacaktır. (Ayrıntılı olarak, içindeki nesnelerin .bssadresi, .datasegmentte olsaydı adresten muhtemelen farklı olurdu .)

İlk programında, aolacağını .datasegment ve bolacağını .bssyürütülebilir segmenti. Program yüklendikten sonra ayrım önemsiz hale gelir. Çalışma zamanında baytları bkaplar 20 * sizeof(int).

İkinci programda varalan tahsis edilir ve içindeki atama main()bu alanı değiştirir. O kadar uzay olur vartarif edilmiştir .bsssegmentinde ziyade .datasegmentinde, ama bu programın davranacağını çalışan şeklini etkilemez.


16
Örneğin, 4096 bayt uzunluğunda birçok başlatılmamış arabellek bulundurmayı düşünün. Tüm bu 4k arabelleklerin ikilinin boyutuna katkıda bulunmasını ister miydiniz? Bu çok fazla boşa harcanan alan olur.
Jeff Mercado

1
@jonathen killer: Neden tüm bss segmenti tek bir sayı ile tanımlanıyor?
Suraj Jain

@JonathanLeffler Demek istediğim, tüm sıfır başlatılmış statik değişkenler bss'ye gider. Öyleyse değeri sadece sıfır olmamalı mı? Ve ayrıca neden .data bölümünde yer verilmiyor, bunu yapmak onu nasıl yavaşlatabilir?
Suraj Jain

2
@SurajJain: Saklanan sayı, sıfırlarla doldurulacak bayt sayısıdır. Bu tür başlatılmamış değişkenler olmadıkça, program yüklendikten sonra bss bölümündeki tüm baytlar sıfır olacak olsa bile, bss bölümünün uzunluğu sıfır olmayacaktır.
Jonathan Leffler

1
Yürütülebilir dosyadaki .bss bölümü sadece bir sayıdır. Bellek içi işlem görüntüsündeki .bss bölümü normalde .data bölümüne bitişik bellektir ve genellikle çalışma zamanı .data bölümü .bss ile birleştirilir; çalışma zamanı belleğinde hiçbir ayrım yapılmaz. Bazen, bss'nin nerede başladığını bulabilirsiniz ( edata). Pratik anlamda, işlem görüntüsü tamamlandıktan sonra .bss bellekte mevcut değildir; sıfırlanan veriler, .data bölümünün basit bir parçasıdır. Ancak ayrıntılar o / s vb.
Göre

15

Gönderen Linux ile Programlama: Assembly Dili Adım Adım ilgili Jeff Duntemann tarafından .data bölüm:

.Data bölümü başlatıldı veri öğelerinin veri tanımlarını içerir. Başlatılan veriler, program çalışmaya başlamadan önce bir değeri olan verilerdir. Bu değerler, yürütülebilir dosyanın parçasıdır. Yürütülebilir dosya yürütme için belleğe yüklendiğinde belleğe yüklenirler.

.Data bölümü hakkında hatırlanması gereken önemli şey, ne kadar başlatılmış veri öğeleri tanımlarsanız, yürütülebilir dosyanın o kadar büyük olacağı ve çalıştırdığınızda onu diskten belleğe yüklemenin o kadar uzun süreceğidir.

ve .bss bölümü:

Program çalışmaya başlamadan önce tüm veri öğelerinin değerlere sahip olması gerekmez. Örneğin, bir disk dosyasından veri okurken, verilerin diskten geldikten sonra gidecekleri bir yere ihtiyacınız vardır. Bunun gibi veri tamponları , programınızın .bss bölümünde tanımlanır . Bir arabellek için bir miktar bayt ayırır ve arabelleğe bir ad verirsiniz, ancak arabellekte hangi değerlerin bulunacağını söylemezsiniz.

.Data bölümünde tanımlanan veri öğeleri ile .bss bölümünde tanımlanan veri öğeleri arasında önemli bir fark vardır: .data bölümündeki veri öğeleri yürütülebilir dosyanızın boyutuna eklenir. .Bss bölümündeki veri öğeleri bunu yapmaz. 16.000 bayt (veya daha fazla, bazen çok daha fazla) alan bir arabellek .bss olarak tanımlanabilir ve çalıştırılabilir dosya boyutuna neredeyse hiçbir şey (açıklama için yaklaşık 50 bayt) ekleyemez.


9

Öncelikle, örneğinizdeki bu değişkenler ilklendirilmemiş değildir; C, aksi takdirde başlatılmayan statik değişkenlerin 0 olarak başlatıldığını belirtir.

Bu nedenle .bss'nin nedeni, daha küçük yürütülebilir dosyalara sahip olmak, yerden tasarruf sağlamak ve programın daha hızlı yüklenmesine izin vermektir, çünkü yükleyici, verileri diskten kopyalamak zorunda kalmadan yalnızca bir grup sıfır atayabilir.

Programı çalıştırırken, program yükleyici .data ve .bss'yi belleğe yükleyecektir. .Data veya .bss'de bulunan nesnelere yazar, bu nedenle yalnızca belleğe gider, herhangi bir noktada diskteki ikiliye boşaltılmazlar.


5

Sistem V ABI 4,1 (1997) (aka ELF spesifikasyon) da cevap içerir:

.bssBu bölüm, programın bellek görüntüsüne katkıda bulunan başlatılmamış verileri tutar. Tanım gereği, program çalışmaya başladığında sistem verileri sıfırlarla başlatır. Bölüm tipinde belirtildiği gibi, bölüm dosya alanı kaplamaz SHT_NOBITS.

bölüm adının .bssrezerve edildiğini ve özel efektlere sahip olduğunu, özellikle dosya alanı kaplamadığını , dolayısıyla avantajı olduğunu söylüyor .data.

Dezavantajı, elbette 0, işletim sistemi onları belleğe koyduğunda tüm baytların ayarlanması gerektiğidir , bu daha kısıtlayıcıdır, ancak yaygın bir kullanım durumudur ve başlatılmamış değişkenler için iyi çalışır.

SHT_NOBITSBölüm tipi dokümantasyon olumlama tekrarlar:

sh_sizeBu üye, bölümün boyutunu bayt cinsinden verir. Bölüm türü olmadığı sürece SHT_NOBITSbölüm kaplarsh_size dosyada baytları . Bir tür bölümü SHT_NOBITSsıfır olmayan bir boyuta sahip olabilir, ancak dosyada yer kaplamaz.

C standart bölümler hakkında hiçbir şey söylemiyor, ama biz kolayca değişken ile Linux nerede depolandığını doğrulayabilir objdumpve readelfve başlatılmamış globaller aslında saklanır sonucuna .bss. Örneğin şu cevaba bakın: C'de bildirilmiş, başlatılmamış değişkene ne olur?


3

Wikipedia makalesi .bss , terimin 1950'lerin ortalarına ait olduğu göz önüne alındığında güzel bir tarihsel açıklama sağlar (yippee benim doğum günümü ;-).

Eskiden her bit değerliydi, bu nedenle ayrılmış boş alanı işaretlemek için herhangi bir yöntem yararlıydı. Bu ( .bss ) sıkışmış olandır .

.data bölümleri boş olmayan alan içindir, bunun yerine (sizin) tanımlı değerlerin içine girilmiş olacaktır.

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.