เหตุใดจึงต้องใช้เซ็กเมนต์. bss


120

สิ่งที่ฉันรู้คือตัวแปรส่วนกลางและตัวแปรคงถูกเก็บไว้ใน.dataเซ็กเมนต์และข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้นจะอยู่ใน.bssเซ็กเมนต์ สิ่งที่ฉันไม่เข้าใจคือเหตุใดเราจึงมีเซ็กเมนต์เฉพาะสำหรับตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้น หากตัวแปรที่ไม่ได้เริ่มต้นมีค่าที่กำหนดในขณะรันตัวแปรจะยังคงอยู่ใน.bssเซ็กเมนต์เท่านั้นหรือไม่

ในโปรแกรมต่อไปนี้ aอยู่ใน.dataกลุ่มและbอยู่ใน.bssกลุ่ม ถูกต้องหรือไม่ กรุณาแก้ไขฉันหากความเข้าใจของฉันไม่ถูกต้อง

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

นอกจากนี้ให้พิจารณาโปรแกรมต่อไปนี้

#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 เป็นดีกว่าประหยัดพื้นที่
smwikipedia

คำตอบ:


89

เหตุผลคือการลดขนาดโปรแกรม ลองนึกภาพว่าโปรแกรม C ของคุณทำงานบนระบบฝังตัวโดยที่รหัสและค่าคงที่ทั้งหมดจะถูกบันทึกไว้ใน ROM จริง (หน่วยความจำแฟลช) ในระบบดังกล่าวต้องดำเนินการ "คัดลอกลง" เริ่มต้นเพื่อตั้งค่าออบเจ็กต์ระยะเวลาการจัดเก็บแบบคงที่ทั้งหมดก่อนที่จะเรียก main () โดยทั่วไปจะเป็นเหมือนหลอกนี้:

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

memset(.bss, 
       0, 
       all_implicitly_initialized_objects);

โดยที่. data และ. bss ถูกเก็บไว้ใน RAM แต่ init_value ถูกเก็บไว้ใน ROM หากเป็นส่วนเดียว ROM จะต้องเต็มไปด้วยศูนย์จำนวนมากซึ่งจะเพิ่มขนาด ROM อย่างมาก

ไฟล์ปฏิบัติการที่ใช้ RAM ทำงานในทำนองเดียวกันแม้ว่าจะไม่มี ROM จริงก็ตาม

นอกจากนี้ memset น่าจะเป็นแอสเซมเบลอร์แบบอินไลน์ที่มีประสิทธิภาพมากซึ่งหมายความว่าการคัดลอกลงเริ่มต้นสามารถดำเนินการได้เร็วขึ้น


7
เพื่อชี้แจง: ความแตกต่างเพียงอย่างเดียวระหว่าง. data และ. bss คือในการเริ่มต้นระบบ "คัดลอกลง" สามารถทำงานตามลำดับได้จึงเร็วกว่า หากไม่ได้แยกออกเป็นสองส่วนการเริ่มต้นจะต้องข้ามจุด RAM ที่เป็นของตัวแปรที่ไม่ได้เริ่มต้นทำให้เสียเวลา
CL22

80

.bssส่วนคือการเพิ่มประสิทธิภาพ .bssกลุ่มทั้งหมดอธิบายด้วยตัวเลขเดียวอาจเป็น 4 ไบต์หรือ 8 ไบต์ซึ่งให้ขนาดในกระบวนการทำงานในขณะที่.dataส่วนมีขนาดใหญ่เท่ากับผลรวมของขนาดของตัวแปรเริ่มต้น ดังนั้นจึง.bssทำให้ไฟล์ปฏิบัติการมีขนาดเล็กลงและโหลดได้เร็วขึ้น มิฉะนั้นตัวแปรอาจอยู่ใน.dataส่วนที่มีการกำหนดค่าเริ่มต้นเป็นศูนย์อย่างชัดเจน โปรแกรมจะกดยากเพื่อบอกความแตกต่าง (โดยละเอียดแล้วที่อยู่ของออบเจ็กต์ใน.bssอาจแตกต่างจากที่อยู่หากอยู่ใน.dataเซ็กเมนต์)

ในโปรแกรมแรกaจะอยู่ใน.dataเซ็กเมนต์และbจะอยู่ใน.bssส่วนของไฟล์ปฏิบัติการ เมื่อโหลดโปรแกรมแล้วความแตกต่างจะไม่เป็นสาระสำคัญ ในขณะทำงานbใช้20 * sizeof(int)ไบต์

ในโปรแกรมที่สองvarมีการจัดสรรพื้นที่และการกำหนดในการmain()ปรับเปลี่ยนพื้นที่นั้น มันเกิดขึ้นที่ช่องว่างสำหรับvarถูกอธิบายไว้ใน.bssเซ็กเมนต์แทนที่จะเป็น.dataเซ็กเมนต์ แต่นั่นไม่ส่งผลกระทบต่อวิธีการทำงานของโปรแกรมเมื่อทำงาน


16
ตัวอย่างเช่นพิจารณามีบัฟเฟอร์ที่ไม่ได้เริ่มต้นจำนวนมากที่มีความยาว 4096 ไบต์ คุณต้องการให้บัฟเฟอร์ 4k ทั้งหมดมีส่วนทำให้ขนาดของไบนารีหรือไม่? นั่นจะเป็นการเสียพื้นที่ไปมาก
Jeff Mercado

1
@jonathen killer: เหตุใดส่วน bss ทั้งหมดจึงอธิบายด้วยหมายเลขเดียว ??
Suraj Jain

@JonathanLeffler ฉันหมายถึงตัวแปรคงที่เริ่มต้นเป็นศูนย์ทั้งหมดอยู่ใน bss ดังนั้นค่าของมันไม่ควรเป็นแค่ศูนย์ใช่หรือไม่และเหตุใดพวกเขาจึงไม่ได้รับพื้นที่ในส่วน. data จะทำอย่างไรให้มันช้า?
Suraj Jain

2
@SurajJain: จำนวนที่เก็บไว้คือจำนวนไบต์ที่จะเติมด้วยศูนย์ เว้นแต่จะไม่มีตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นดังกล่าวความยาวของส่วน bss จะไม่เป็นศูนย์แม้ว่าไบต์ทั้งหมด I ส่วน bss จะเป็นศูนย์เมื่อโหลดโปรแกรมแล้ว
Jonathan Leffler

1
ส่วน. bss ในไฟล์ปฏิบัติการเป็นเพียงตัวเลข ส่วน. bss ในอิมเมจกระบวนการในหน่วยความจำโดยปกติแล้วหน่วยความจำที่อยู่ติดกับส่วน. data และบ่อยครั้งที่ส่วน. data ของรันไทม์จะรวมกับ. bss; ไม่มีความแตกต่างในหน่วยความจำรันไทม์ บางครั้งคุณสามารถค้นหาจุดที่ bss เริ่มต้น ( edata) ได้ ในทางปฏิบัติ. bss ไม่มีอยู่ในหน่วยความจำเมื่อประมวลผลอิมเมจเสร็จสิ้น ข้อมูลที่เป็นศูนย์เป็นส่วนง่ายๆของส่วน. data แต่รายละเอียดจะแตกต่างกันไปขึ้นอยู่กับ o / s เป็นต้น
Jonathan Leffler

15

จากภาษาแอสเซมบลีทีละขั้นตอน: การเขียนโปรแกรมด้วยลินุกซ์โดย Jeff Duntemann เกี่ยวกับส่วน. data :

ส่วน. dataประกอบด้วยข้อกำหนดข้อมูลของรายการข้อมูลที่เตรียมใช้งาน ข้อมูลเริ่มต้นคือข้อมูลที่มีค่าก่อนที่โปรแกรมจะเริ่มทำงาน ค่าเหล่านี้เป็นส่วนหนึ่งของไฟล์ปฏิบัติการ พวกเขาจะโหลดลงในหน่วยความจำเมื่อไฟล์ปฏิบัติการถูกโหลดลงในหน่วยความจำเพื่อดำเนินการ

สิ่งสำคัญที่ต้องจำเกี่ยวกับส่วน. data คือยิ่งคุณกำหนดรายการข้อมูลเริ่มต้นมากเท่าไหร่ไฟล์ปฏิบัติการก็จะมีขนาดใหญ่ขึ้นและจะใช้เวลาโหลดจากดิสก์ลงในหน่วยความจำนานขึ้นเมื่อคุณเรียกใช้

และส่วน. bss :

รายการข้อมูลบางรายการไม่จำเป็นต้องมีค่าก่อนที่โปรแกรมจะเริ่มทำงาน ตัวอย่างเช่นเมื่อคุณกำลังอ่านข้อมูลจากไฟล์ดิสก์คุณต้องมีที่สำหรับข้อมูลที่จะไปหลังจากที่ข้อมูลนั้นมาจากดิสก์ บัฟเฟอร์ข้อมูลที่กำหนดไว้ในส่วน. bssของโปรแกรมของคุณ คุณกำหนดจำนวนไบต์ไว้สำหรับบัฟเฟอร์และตั้งชื่อบัฟเฟอร์ แต่คุณไม่ได้บอกว่าจะมีค่าอะไรบ้างในบัฟเฟอร์

มีความแตกต่างที่สำคัญระหว่างรายการข้อมูลที่กำหนดไว้ในส่วน. data และรายการข้อมูลที่กำหนดในส่วน. bss: รายการข้อมูลในส่วน. data จะเพิ่มขนาดของไฟล์ปฏิบัติการของคุณ รายการข้อมูลในส่วน. bss ไม่ได้ บัฟเฟอร์ที่ใช้พื้นที่ถึง 16,000 ไบต์ (หรือมากกว่านั้นบางครั้งอาจมากกว่านั้น) สามารถกำหนดได้ใน. bss และแทบจะไม่ต้องเพิ่มอะไรเลย (ประมาณ 50 ไบต์สำหรับคำอธิบาย) ให้กับขนาดไฟล์ปฏิบัติการ


9

ก่อนอื่นตัวแปรเหล่านั้นในตัวอย่างของคุณไม่ได้กำหนดค่าเริ่มต้น C ระบุว่าตัวแปรคงที่ที่ไม่ได้กำหนดค่าเริ่มต้นจะเริ่มต้นเป็น 0

เหตุผลของ. bss คือการมีไฟล์ปฏิบัติการที่เล็กลงประหยัดพื้นที่และช่วยให้โหลดโปรแกรมได้เร็วขึ้นเนื่องจากตัวโหลดสามารถจัดสรรจำนวนศูนย์แทนการคัดลอกข้อมูลจากดิสก์

เมื่อรันโปรแกรมตัวโหลดโปรแกรมจะโหลด. data และ. bss ลงในหน่วยความจำ เขียนลงในวัตถุที่อยู่ใน. data หรือ. bss ดังนั้นจึงไปที่หน่วยความจำเท่านั้นพวกเขาจะไม่ถูกล้างไปยังไบนารีบนดิสก์เมื่อใดก็ตาม


5

System V ABI 4.1 (1997) (อาคาเอลฟ์สเปค) นอกจากนี้ยังมีคำตอบ:

.bssส่วนนี้เก็บข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้นซึ่งนำไปสู่อิมเมจหน่วยความจำของโปรแกรม ตามความหมายระบบเริ่มต้นข้อมูลด้วยศูนย์เมื่อโปรแกรมเริ่มทำงาน SHT_NOBITSส่วนพื้นที่ไม่มีแฟ้มตามที่ระบุไว้ตามประเภทส่วน

บอกว่าชื่อส่วน.bssที่สงวนไว้และมีลักษณะพิเศษโดยเฉพาะอย่างยิ่งในพื้นที่ไม่มีแฟ้ม.dataจึงเปรียบที่เหนือกว่า

ข้อเสียคือแน่นอนว่าต้องตั้งค่าไบต์ทั้งหมดเป็น0เมื่อ OS วางไว้ในหน่วยความจำซึ่งมีข้อ จำกัด มากกว่า แต่เป็นกรณีการใช้งานทั่วไปและทำงานได้ดีสำหรับตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้น

SHT_NOBITSเอกสารประเภทส่วนซ้ำยืนยันว่า

sh_sizeสมาชิกนี้กำหนดขนาดของส่วนเป็นไบต์ เว้นแต่เป็นประเภทSHT_NOBITSส่วนส่วนจะมีจำนวนsh_size ไบต์ในไฟล์ ส่วนของประเภทSHT_NOBITSอาจมีขนาดที่ไม่ใช่ศูนย์ แต่ไม่มีพื้นที่ว่างในไฟล์

มาตรฐาน C ไม่ได้บอกอะไรเกี่ยวกับส่วนต่างๆ แต่เราสามารถตรวจสอบได้อย่างง่ายดายว่าตัวแปรถูกเก็บไว้ที่ใดใน Linux ด้วยobjdumpและreadelfและสรุปได้ว่า globals ที่ไม่ได้เริ่มต้นนั้นถูกเก็บไว้ในไฟล์.bss. ดูตัวอย่างคำตอบนี้: จะเกิดอะไรขึ้นกับตัวแปรที่ประกาศและไม่ได้กำหนดค่าเริ่มต้นใน C


3

บทความวิกิพีเดีย. bssให้คำอธิบายทางประวัติศาสตร์ที่ดีเนื่องจากคำนี้มาจากกลางปี ​​1950 (yippee my birthday ;-)

ย้อนกลับไปในวันนั้นทุกบิตมีค่าดังนั้นวิธีการใด ๆ ในการส่งสัญญาณพื้นที่ว่างที่สงวนไว้ก็มีประโยชน์ นี่ ( .bss ) คืออันที่ติด

ส่วน. dataใช้สำหรับช่องว่างที่ไม่ว่าง แต่จะมี (ของคุณ) ที่กำหนดค่าไว้ป้อนลงไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.