Mengapa segmen .bss diperlukan?

120

Yang saya tahu adalah bahwa variabel global dan statis disimpan di .datasegmen, dan data yang tidak diinisialisasi ada di .bsssegmen tersebut. Yang tidak saya mengerti adalah mengapa kami memiliki segmen khusus untuk variabel yang tidak diinisialisasi? Jika variabel yang tidak diinisialisasi memiliki nilai yang ditetapkan pada waktu proses, apakah variabel tersebut masih ada di .bsssegmen saja?

Dalam program berikut, aada di .datasegmen, dan bdi .bsssegmen; Apakah itu benar? Mohon koreksi saya jika pemahaman saya salah.

#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 ()
{
   ;
}  

Juga, pertimbangkan program berikut,

#include <stdio.h>
#include <stdlib.h>
int var[10];  /* Uninitialized so in .bss */
int main ()
{
   var[0] = 20  /* **Initialized, where this 'var' will be ?** */
}
Siapa saya
sumber
3
Anda dapat membaca BSS sebagai Better Save Space .
smwikipedia

Jawaban:

89

Alasannya adalah untuk mengurangi ukuran program. Bayangkan bahwa program C Anda berjalan pada sistem tertanam, di mana kode dan semua konstanta disimpan dalam ROM yang sebenarnya (memori flash). Dalam sistem seperti itu, "penyalinan" awal harus dijalankan untuk menyetel semua objek durasi penyimpanan statis, sebelum main () dipanggil. Biasanya akan seperti ini semu:

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

memset(.bss, 
       0, 
       all_implicitly_initialized_objects);

Di mana .data dan .bss disimpan di RAM, tetapi init_value disimpan di ROM. Jika tadinya satu segmen, maka ROM harus diisi dengan banyak angka nol, meningkatkan ukuran ROM secara signifikan.

Eksekutabel berbasis RAM bekerja dengan cara yang sama, meskipun tentu saja mereka tidak memiliki ROM yang sebenarnya.

Selain itu, memset kemungkinan merupakan assembler sebaris yang sangat efisien, yang berarti bahwa penyalinan awal dapat dijalankan lebih cepat.

Lundin
sumber
7
Untuk memperjelas: satu-satunya perbedaan antara .data dan .bss adalah bahwa saat start-up, "copy-down" dapat dijalankan secara berurutan, sehingga lebih cepat. Jika tidak dipecah menjadi dua segmen maka inisialisasi harus melewati tempat RAM milik variabel yang tidak diinisialisasi, sehingga membuang-buang waktu.
CL22
80

The .bsssegmen adalah optimasi. Seluruh .bsssegmen dideskripsikan dengan satu angka, mungkin 4 byte atau 8 byte, yang memberikan ukurannya dalam proses yang sedang berjalan, sedangkan .databagian tersebut sebesar jumlah ukuran variabel yang diinisialisasi. Dengan demikian, .bssmembuat executable lebih kecil dan lebih cepat dimuat. Jika tidak, variabel dapat berada di .datasegmen dengan inisialisasi eksplisit menjadi nol; program akan kesulitan untuk membedakannya. (Secara rinci, alamat objek di .bssmungkin akan berbeda dari alamat jika berada di .datasegmen tersebut.)

Pada program pertama, aakan berada di .datasegmen dan bakan berada di .bsssegmen yang dapat dieksekusi. Setelah program dimuat, perbedaannya menjadi tidak penting. Saat menjalankan, bmenempati 20 * sizeof(int)byte.

Dalam program kedua, vardialokasikan ruang dan tugas dalam main()memodifikasi ruang itu. Kebetulan ruang untuk vardijelaskan di .bsssegmen daripada .datasegmen, tetapi itu tidak memengaruhi cara program berperilaku saat berjalan.

Jonathan Leffler
sumber
16
Misalnya, pertimbangkan untuk memiliki banyak buffer yang tidak diinisialisasi dengan panjang 4096 byte. Apakah Anda ingin semua buffer 4k tersebut berkontribusi pada ukuran biner? Itu akan menjadi banyak ruang yang terbuang.
Jeff Mercado
1
@jonathen killer: Mengapa seluruh segmen bss digambarkan dengan satu nomor ??
Suraj Jain
@JonathanLeffler Maksud saya semua variabel statis yang diinisialisasi nol masuk dalam bss. Jadi bukankah nilainya harus nol? Dan juga mengapa mereka tidak diberi ruang pada bagian .data bagaimana melakukannya membuatnya lambat?
Suraj Jain
2
@SurajJain: angka yang disimpan adalah jumlah byte yang harus diisi dengan angka nol. Kecuali jika tidak ada variabel yang tidak diinisialisasi, panjang bagian bss tidak akan nol, meskipun semua byte I bagian bss akan menjadi nol setelah program dimuat.
Jonathan Leffler
1
Bagian .bss dalam file yang dapat dieksekusi hanyalah sebuah angka. Bagian .bss dalam gambar proses dalam memori biasanya merupakan memori yang berdekatan dengan bagian .data dan seringkali bagian .data runtime digabungkan dengan .bss; tidak ada perbedaan yang dibuat dalam memori runtime. Terkadang, Anda dapat menemukan di mana bss dimulai ( edata). Dalam istilah praktis, .bss tidak ada dalam memori setelah image proses selesai; data yang dibidik adalah bagian sederhana dari bagian .data. Tetapi detailnya bervariasi tergantung pada o / s dll.
Jonathan Leffler
15

Dari Bahasa Perakitan Langkah-demi-Langkah: Pemrograman dengan Linux oleh Jeff Duntemann, terkait bagian .data :

Bagian .data berisi definisi data dari item data yang diinisialisasi. Data yang diinisialisasi adalah data yang memiliki nilai sebelum program mulai dijalankan. Nilai-nilai ini adalah bagian dari file yang dapat dieksekusi. Mereka dimuat ke dalam memori ketika file yang dapat dieksekusi dimuat ke dalam memori untuk dieksekusi.

Hal penting yang harus diingat tentang bagian .data adalah semakin banyak item data yang Anda tentukan, semakin besar file yang dapat dieksekusi, dan semakin lama waktu yang dibutuhkan untuk memuatnya dari disk ke dalam memori saat Anda menjalankannya.

dan bagian .bss :

Tidak semua item data harus memiliki nilai sebelum program mulai berjalan. Saat Anda membaca data dari file disk, misalnya, Anda perlu memiliki tempat untuk menyimpan data setelah masuk dari disk. Buffer data seperti itu didefinisikan di bagian .bss program Anda. Anda menyisihkan beberapa byte untuk buffer dan memberi nama buffer, tetapi Anda tidak mengatakan nilai apa yang akan ada di buffer.

Ada perbedaan penting antara item data yang ditentukan di bagian .data dan item data yang ditentukan di bagian .bss: item data di bagian .data menambah ukuran file yang dapat dieksekusi. Item data di bagian .bss tidak. Buffer yang membutuhkan 16.000 byte (atau lebih, terkadang lebih banyak) dapat didefinisikan dalam .bss dan hampir tidak menambahkan apa-apa (sekitar 50 byte untuk deskripsi) ke ukuran file yang dapat dieksekusi.

mihai
sumber
9

Pertama-tama, variabel tersebut dalam contoh Anda tidak diinisialisasi; C menentukan bahwa variabel statis yang tidak diinisialisasi diinisialisasi ke 0.

Jadi, alasan untuk .bss adalah memiliki file executable yang lebih kecil, menghemat ruang dan memungkinkan pemuatan program yang lebih cepat, karena pemuat hanya dapat mengalokasikan sejumlah nol daripada harus menyalin data dari disk.

Saat menjalankan program, program loader akan memuat .data dan .bss ke dalam memori. Menulis ke objek yang berada dalam .data atau .bss sehingga hanya masuk ke memori, mereka tidak dipindahkan ke biner pada disk kapan pun.

janneb.dll
sumber
5

The System V ABI 4.1 (1997) (AKA ELF spesifikasi) juga mengandung jawabannya:

.bssBagian ini menyimpan data yang tidak diinisialisasi yang berkontribusi pada gambar memori program. Menurut definisi, sistem menginisialisasi data dengan nol saat program mulai dijalankan. Bagian tidak menempati ruang file, seperti yang ditunjukkan oleh jenis bagian SHT_NOBITS,.

mengatakan bahwa nama bagian .bssdicadangkan dan memiliki efek khusus, khususnya tidak menempati ruang file , sehingga lebih menguntungkan .data.

Kelemahannya tentu saja bahwa semua byte harus diatur ke 0saat OS menempatkannya di memori, yang lebih membatasi, tetapi kasus penggunaan umum, dan berfungsi dengan baik untuk variabel yang tidak diinisialisasi.

The SHT_NOBITSbagian jenis dokumentasi mengulangi penegasan bahwa:

sh_sizeAnggota ini memberikan ukuran bagian dalam byte. Kecuali jika tipe bagiannya SHT_NOBITS, bagian tersebut menempati sh_size byte dalam file. Bagian tipe SHT_NOBITSmungkin memiliki ukuran bukan nol, tetapi tidak menempati ruang di file.

Standar C tidak mengatakan apa-apa tentang section, tetapi kita dapat dengan mudah memverifikasi di mana variabel disimpan di Linux dengan objdumpdan readelf, dan menyimpulkan bahwa global yang tidak diinisialisasi sebenarnya disimpan di .bss. Lihat misalnya jawaban ini: Apa yang terjadi pada variabel yang dideklarasikan dan tidak diinisialisasi di C?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
3

Artikel wikipedia .bss memberikan penjelasan sejarah yang bagus, mengingat istilah tersebut berasal dari pertengahan tahun 1950-an (yippee my birthday ;-).

Dulu, setiap bit berharga, jadi metode apa pun untuk memberi sinyal pada ruang kosong yang dicadangkan, berguna. Ini ( .bss ) adalah salah satu yang macet.

Bagian .data adalah untuk ruang yang tidak kosong, melainkan akan memiliki nilai yang ditentukan (Anda) dimasukkan ke dalamnya.

Philip Oakley
sumber