2010-02-02 9 views
16

निष्पादित होने पर, प्रोग्राम वर्चुअल एड्रेस 0x80482c0 से चलना शुरू हो जाएगा। यह पता हमारी main() प्रक्रिया को इंगित नहीं करता है, लेकिन _start नामक एक प्रक्रिया के लिए जो लिंकर द्वारा बनाया गया है।ईएलएफ निष्पादन प्रविष्टि 0x80xxxxx के आभासी पते को इंगित करता है और शून्य 0x0 नहीं है?

मेरा गूगल अनुसंधान अब तक सिर्फ मुझे इस तरह कुछ (अस्पष्ट) ऐतिहासिक अटकलों को जन्म दिया:

लोकगीत है कि एक बार STACK_TOP था 0x08048000 नहीं है (जो है, ढेर नीचे की ओर 0 की ओर 0x08048000 के पास से बड़े हुए) * NIX से i386 के बंदरगाह पर जिसे सांताक्रूज, कैलिफ़ोर्निया के एक समूह द्वारा प्रख्यापित किया गया था। यह तब था जब 128 एमबी रैम महंगा था, और 4 जीबी रैम असंभव था।

क्या कोई इसे पुष्टि/अस्वीकार कर सकता है?

+0

यदि '0x08048000' कभी भी' STACK_TOP' था, तो यह _very_ बहुत पहले था। उत्तरार्द्ध [2.0.40] (http://lxr.free-electrons.com/source/include/asm-i386/a.out.h?v=2.0.40#L22) के लिए सभी तरह से 'TASK_SIZE' है) । –

उत्तर

31

मैड्स ने इंगित किया कि, नल पॉइंटर्स के माध्यम से अधिकतर पहुंच प्राप्त करने के लिए, यूनिक्स-जैसी प्रणाली पृष्ठ को शून्य "अप्रयुक्त" पते पर बनाती है। इस प्रकार, एक्सेस एक सीपीयू अपवाद को तुरंत ट्रिगर करता है, दूसरे शब्दों में एक segfault। आवेदन को बदनाम करने से यह काफी बेहतर है। अपवाद वेक्टर तालिका, हालांकि, कम से कम x86 प्रोसेसर पर किसी भी पते पर हो सकती है (इसके लिए एक विशेष रजिस्टर है, lidt ऑपोड के साथ लोड किया गया है)।

प्रारंभ बिंदु बिंदु सम्मेलनों के एक समूह का हिस्सा है जो वर्णन करता है कि स्मृति कैसे निर्धारित की जाती है। लिंकर, जब यह निष्पादन योग्य बाइनरी उत्पन्न करता है, तो इन सम्मेलनों को जानना चाहिए, इसलिए उन्हें बदलने की संभावना नहीं है। मूल रूप से, लिनक्स के लिए, स्मृति लेआउट सम्मेलन को 90 के दशक के आरंभ में लिनक्स के पहले संस्करणों से विरासत में मिलाया जाता है। एक प्रक्रिया में कई क्षेत्रों तक पहुंच होनी चाहिए:

  • कोड एक श्रेणी में होना चाहिए जिसमें प्रारंभिक बिंदु शामिल है।
  • वहां एक ढेर होना चाहिए।
  • brk() और sbrk() सिस्टम कॉल के साथ बढ़ी सीमा के साथ एक ढेर होना चाहिए।
  • साझा लाइब्रेरी लोडिंग सहित mmap() सिस्टम कॉल के लिए कुछ कमरा होना चाहिए।

आजकल, ढेर, जहां malloc() चला जाता है, mmap() कॉल जो जो कुछ भी पता गिरी फिट देखता है पर स्मृति का हिस्सा प्राप्त द्वारा समर्थित है। लेकिन पुराने समय में, लिनक्स पिछले यूनिक्स जैसी प्रणालियों की तरह था, और इसके ढेर को एक निर्बाध खंड में एक बड़ा क्षेत्र चाहिए, जो बढ़ते पते की ओर बढ़ सकता है। तो जो कुछ भी सम्मेलन था, उसे कोड को भरना था और कम पते की तरफ ढेर करना था, और ढेर को दिए गए बिंदु के बाद पता स्थान के हर हिस्से को देना था।

लेकिन स्टैक भी है, जो आमतौर पर काफी छोटा होता है लेकिन कुछ मौकों पर काफी नाटकीय रूप से बढ़ सकता है। ढेर बढ़ता है, और जब ढेर भरा होता है, हम वास्तव में प्रक्रिया को कुछ डेटा ओवरराइट करने की बजाए अनुमानित रूप से क्रैश करना चाहते हैं। तो उस क्षेत्र के निचले सिरे पर, एक अप्रत्याशित पृष्ठ के साथ, स्टैक के लिए एक विस्तृत क्षेत्र होना था। और लो! नल पॉइंटर डिटेरेंस को पकड़ने के लिए, शून्य पते पर एक अनपढ़ पृष्ठ है। इसलिए यह परिभाषित किया गया था कि पहले पृष्ठ को छोड़कर, स्टैक को पहले 128 एमबी पता स्थान मिलेगा। इसका मतलब है कि 0x080xxxxx के समान पते पर कोड 128 एमबी के बाद जाना था।

जैसा कि माइकल बताते हैं, 128 एमबी पता स्थान "खोना" कोई बड़ा सौदा नहीं था क्योंकि वास्तव में उपयोग किए जा सकने वाले संबंधों के संबंध में पता स्थान बहुत बड़ा था। उस समय, लिनक्स कर्नेल एक ही प्रक्रिया के लिए एड्रेस स्पेस को 1 जीबी तक सीमित कर रहा था, हार्डवेयर द्वारा अधिकतम 4 जीबी की अनुमति थी, और इसे एक बड़ा मुद्दा नहीं माना जाता था।

6

पता 0x0 पर क्यों शुरू नहीं करें? इसके लिए कम से कम दो कारण हैं:

  • क्योंकि पता शून्य को नल पॉइंटर के रूप में जाना जाता है, और प्रोग्रामिंग भाषाओं द्वारा सैने चेक पॉइंटर्स के लिए उपयोग किया जाता है। यदि आप वहां कोड निष्पादित करने जा रहे हैं, तो आप उसके लिए पता मूल्य का उपयोग नहीं कर सकते हैं।
  • पता 0 पर वास्तविक सामग्री अपवाद वेक्टर तालिका अक्सर होती है (लेकिन हमेशा नहीं), और इसलिए गैर-विशेषाधिकार प्राप्त मोड में पहुंच योग्य नहीं है। अपने विशिष्ट वास्तुकला के दस्तावेज़ीकरण से परामर्श लें।

entrypoint _start बनाम main के लिए के रूप में: आप सी क्रम (सी मानक पुस्तकालयों) के खिलाफ लिंक करते हैं, पुस्तकालय समारोह main नामित लपेटता, तो यह पर्यावरण को प्रारंभ करने से पहले main कहा जाता है। लिनक्स पर, ये argc और argv एप्लिकेशन के पैरामीटर, env चर, और शायद कुछ सिंक्रनाइज़ेशन प्राइमेटिव और ताले हैं। यह भी सुनिश्चित करता है कि स्थिति कोड पर मुख्य पास से लौट रहा है, और _exit फ़ंक्शन को कॉल करता है, जो प्रक्रिया को समाप्त करता है।

+5

सी नल पॉइंटर्स में निम्नतम स्तर पर 0 से पूरी तरह अलग मूल्य हो सकता है। सी (स्रोत कोड) के दायरे में मशीन के अमान्य सूचक मूल्य को 0 पर नक्शा करना चाहिए। तकनीकी रूप से सी शून्य सूचक के लिए वास्तव में शून्य को संबोधित करने के लिए मानचित्र की आवश्यकता नहीं है। – datenwolf

+0

'_GLOBAL_OFFSET_TABLE_' भी Binutils 2.24 में' 0x200XXX' रेंज में इंगित करता है। –

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