2009-03-04 5 views
41

यदि मैं सही ढंग से समझता हूं, तो ईएलएफ फ़ाइलों में .bss अनुभाग शून्य-प्रारंभिक चर के लिए स्थान आवंटित करने के लिए उपयोग किया जाता है। हमारी टूल श्रृंखला ईएलएफ फाइलें बनाती है, इसलिए मेरा प्रश्न: क्या .bss अनुभाग में वास्तव में उन सभी शून्य शामिल हैं? ऐसा लगता है कि रिक्त स्थानों का इतना भयानक अपशिष्ट है कि जब मैं कहता हूं, मैं एक वैश्विक दस मेगाबाइट सरणी आवंटित करता हूं, तो इसके परिणामस्वरूप ईएलएफ फ़ाइल में शून्य के दस मेगाबाइट होते हैं। मैं यहाँ क्या गलत देख रहा हूँ?क्या .bss अनुभाग शून्य प्रारंभिक चर elf फ़ाइल में स्थान पर कब्जा करते हैं?

+0

त्वरित जिस तरह से यह जवाब देने के लिए: एक 'पूर्णांक के साथ एक नमस्ते दुनिया बनाने के है [1000000]' और, बिना संकलन और संकलित आकार दिखाई :-) तो वास्तव में समझने के लिए, यह binutils साथ डिकंपाइल के लिए एक और, या '-S' के साथ असेंबली कोड को संकलित करें। –

उत्तर

63

कुछ समय हो गया है क्योंकि मैंने ईएलएफ के साथ काम किया था। लेकिन मुझे लगता है कि मुझे अभी भी यह सामान याद है। नहीं, यह भौतिक रूप से उन शून्यों को शामिल नहीं करता है। यदि आप ईएलएफ फ़ाइल प्रोग्राम हेडर में देखते हैं, तो आप देखेंगे कि प्रत्येक हेडर में दो नंबर हैं: फ़ाइल में आकार एक है। और एक और अनुभाग के रूप में आकार है जब आभासी स्मृति (readelf -l ./a.out) में आवंटित है:

प्रकार LOAD की
Program Headers: 
    Type   Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 
    PHDR   0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4 
    INTERP   0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1 
     [Requesting program interpreter: /lib/ld-linux.so.2] 
    LOAD   0x000000 0x08048000 0x08048000 0x00454 0x00454 R E 0x1000 
    LOAD   0x000454 0x08049454 0x08049454 0x00104 0x61bac RW 0x1000 
    DYNAMIC  0x000468 0x08049468 0x08049468 0x000d0 0x000d0 RW 0x4 
    NOTE   0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4 
    GNU_STACK  0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 

हेडर एक जब फ़ाइल निष्पादन के लिए भरी हुई है कि आभासी स्मृति में नकल कर रहे हैं। अन्य शीर्षकों में अन्य जानकारी होती है, जैसे साझा पुस्तकालयों की आवश्यकता होती है। इस उदाहरण कोड के लिए

0x00104 (file-size) 0x61bac (mem-size) 

: जैसा कि आप देख, FileSize और MemSiz काफी हैडर कि bss खंड (द्वितीय LOAD एक) शामिल हैं के लिए अलग

int a[100000]; 
int main() { } 

ELF विनिर्देश का कहना है कि एक सेगमेंट का हिस्सा है कि मेम-आकार फ़ाइल आकार से बड़ा है वर्चुअल मेमोरी में शून्य के साथ बस भरा हुआ है। दूसरा LOAD हैडर की धारा मानचित्रण करने के लिए खंड इस तरह है:

03  .ctors .dtors .jcr .dynamic .got .got.plt .data .bss 

तो वहाँ कुछ अन्य वर्गों में वहाँ भी कर रहे हैं। सी ++ कन्स्ट्रक्टर/विनाशकों के लिए। जावा के लिए एक ही बात है। इसके बाद इसमें .dynamic सेक्शन की एक प्रति और डायनामिक लिंकिंग के लिए उपयोगी अन्य सामान शामिल हैं (मुझे विश्वास है कि यह वह जगह है जिसमें अन्य सामानों के साथ आवश्यक साझा पुस्तकालय शामिल हैं)। उसके बाद .data अनुभाग जिसमें प्रारंभिक ग्लोबल्स और स्थानीय स्थैतिक चर शामिल हैं। अंत में, .bss अनुभाग प्रकट होता है, जो लोड समय पर शून्य से भरा होता है क्योंकि फ़ाइल-आकार इसमें शामिल नहीं होता है।

वैसे, आप देख सकते हैं कि आउटपुट-सेक्शन -M लिंकर विकल्प का उपयोग करके एक विशेष प्रतीक रखा जा रहा है। जीसीसी के लिए, आप लिंकर के माध्यम से विकल्प डालने के लिए -Wl,-M का उपयोग करें। उपरोक्त उदाहरण से पता चलता है कि a.bss के भीतर आवंटित किया गया है।

.bss   0x08049560 0x61aa0 
[many input .o files...] 
*(COMMON) 
*fill*   0x08049568  0x18 00 
COMMON   0x08049580 0x61a80 /tmp/cc2GT6nS.o 
       0x08049580    a 
       0x080ab000    . = ALIGN ((. != 0x0)?0x4:0x1) 
       0x080ab000    . = ALIGN (0x4) 
       0x080ab000    . = ALIGN (0x4) 
       0x080ab000    _end = . 

जीसीसी वर्ष compilers, कि वैश्विक दो बार परिभाषित किया है करने की अनुमति के साथ संगतता के लिए, डिफ़ॉल्ट रूप से एक आम खंड में अप्रारंभीकृत वैश्विक रहता है: यह आप देख लें कि आपके अप्रारंभीकृत वस्तुओं वास्तव में .bss में समाप्त और कहीं और नहीं मदद मिल सकती है बिना किसी परिभाषा त्रुटियों के एक कार्यक्रम में। GCC को ऑब्जेक्ट फ़ाइलों के लिए .bss अनुभागों का उपयोग करने के लिए -fno-common का उपयोग करें (अंतिम लिंक किए गए निष्पादन योग्य के लिए कोई फर्क नहीं पड़ता है, क्योंकि आप देखते हैं कि यह किसी भी .bss आउटपुट सेक्शन में जा रहा है। इसे लिंकर स्क्रिप्ट द्वारा नियंत्रित किया जाता है ।इसे ld -verbose के साथ प्रदर्शित करें)। लेकिन इससे आपको डरना नहीं चाहिए, यह सिर्फ एक आंतरिक विवरण है। जीसीसी का मैनपेज देखें।

+0

+1। बहुत बढ़िया। अच्छा और गहन – Eddie

+0

मुझे लगता है कि नोबिट्स अनुभाग प्रकार को अनुमति देने के लिए सेट किया जाना चाहिए? –

+0

वाउटर। हम्म मैंने कभी उस झंडे का उपयोग नहीं किया। जीसीसी के लिए मेरी मशीन हेडर फ़ाइल #define BSS_SECTION_ASM_OP "\ t.section \ t.bss, \" aw \ "" –

2

.bss अनुभाग निष्पादन योग्य फ़ाइल में संग्रहीत नहीं है। सबसे आम वर्गों में से (.text, .data, .bss), केवल .text (वास्तविक कोड) और .data (प्रारंभिक डेटा) ईएलएफ फ़ाइल में मौजूद हैं।

+1

ऐसा नहीं है जो मनमाने ढंग से निष्पादन योग्य पर मुझे बताता है। फ़ाइल में अनुभागों का एक horseload है, जिसमें .bss अनुभाग शामिल है। –

+0

यह ईएलएफ पर निर्भर नहीं है बल्कि आपकी संकलन श्रृंखला (भाषाओं, उपकरण, विकल्प जैसे डीबग, ...) पर निर्भर करता है। आप अपने स्वयं के कस्टम अनुभाग भी प्राप्त कर सकते हैं। – mouviciel

+0

'.bss' अनुभाग निष्पादन योग्य फ़ाइल में कम से कम ईएलएफ के लिए संग्रहीत किया जाता है। लेकिन इसकी सामग्री संग्रहित नहीं है, इसलिए फ़ाइल में '.bss' का आकार एक छोटा स्थिर है। मेमोरी सुरक्षा के साथ ऑपरेटिंग सिस्टम पर '.bss' सेक्शन को किसी भी तरीके से संग्रहीत करने की आवश्यकता है ताकि लोडर उस स्थान पर लिखने योग्य मेमोरी की व्यवस्था कर सके। बेशक यह सोचने योग्य होगा कि कुछ प्रारूपों में '.bss' से अधिक जो कुछ बचा है, वह आवंटित लेकिन प्रतिलिपि आकार क्षेत्र में योगदान नहीं है। – textshell

20

एक ELF फ़ाइल में .bss खंड स्थिर डेटा जो है प्रोग्राम के रूप में आरंभ नहीं किया लेकिन कार्यावधि में शून्य पर सेट होने की गारंटी के लिए प्रयोग किया जाता है। यहां एक छोटा सा उदाहरण दिया गया है जो अंतर को समझाएगा।

int main() { 
    static int bss_test1[100]; 
    static int bss_test2[100] = {0}; 
    return 0; 
} 

इस मामले bss_test1 में .bss में रखा जाता है, क्योंकि यह अप्रारंभीकृत है। bss_test2 हालांकि शून्य के समूह के साथ .data सेगमेंट में रखा गया है। रनटाइम लोडर मूल रूप से .bss के लिए आरक्षित स्थान की मात्रा आवंटित करता है और किसी भी उपयोगकर्तालैंड कोड को निष्पादित करने से पहले इसे शून्य करता है।

आप objdump, nm, या इसी तरह उपयोगिताओं का उपयोग कर अंतर देख सकते हैं:

moozletoots$ objdump -t a.out | grep bss_test 
08049780 l  O .bss 00000190    bss_test1.3 
080494c0 l  O .data 00000190    bss_test2.4 

यह आमतौर पर पहले में से एक है आश्चर्य कि एम्बेडेड डेवलपर्स स्पष्ट रूप से शून्य करने के लिए में ... प्रारंभ कभी नहीं स्टैटिक्स चलाते हैं। रनटाइम लोडर (आमतौर पर) इसका ख्याल रखता है। जैसे ही आप कुछ भी स्पष्ट रूप से प्रारंभ करते हैं, आप निष्पादन योग्य छवि में डेटा शामिल करने के लिए कंपाइलर/लिंकर को बता रहे हैं।

+0

मेरे प्लेटफ़ॉर्म जीसीसी पर bss_test2 को .bss अनुभाग में डाल दिया गया है। आप -फनो-शून्य-प्रारंभिक-इन-बीएसएस संकलन विकल्प का उल्लेख कर सकते थे जो इसे नियंत्रित करता है। – tristan

+0

मैन्युअल से: "यदि लक्ष्य किसी बीएसएस अनुभाग का समर्थन करता है, तो डिफ़ॉल्ट रूप से जीसीसी वैरिएबल को रखता है जो बीएसएस में शून्य में प्रारंभ होता है।" – OrangeDog

1

यह सही है, .ब्स फ़ाइल में भौतिक रूप से मौजूद नहीं है, बल्कि इसके आकार के बारे में जानकारी गतिशील लोडर के लिए आवेदन कार्यक्रम के लिए .bs अनुभाग को आवंटित करने के लिए मौजूद है। अंगूठे नियम केवल लोड के रूप में, टीएलएस सेगमेंट को एप्लिकेशन प्रोग्राम के लिए स्मृति मिलती है, शेष गतिशील लोडर के लिए उपयोग किया जाता है।

बारे में स्थिर निष्पादन योग्य फ़ाइल, वर्गों बीएसएस भी जहां कोई लोडर इस आम है वहाँ execuatble

एंबेडेड आवेदन में स्थान दिया गया है।

सुमन

+0

आप कहते हैं, टीएलएस भी लोड हो गए हैं, जैसे कि PT_LOAD? मैं देखता हूं कि PT_TLS को PT_LOAD में शामिल किया गया है – osgx

संबंधित मुद्दे