डिस्कनेक्ट विश्लेषण के साथ लिनक्स न्यूनतम रननीय उदाहरण
चूंकि यह एक कार्यान्वयन विवरण है जो मानकों द्वारा निर्दिष्ट नहीं किया गया है, आइए एक नज़र डालते हैं कि संकलक किसी विशेष कार्यान्वयन पर क्या कर रहा है।
इस उत्तर में, मैं या तो उन विशिष्ट उत्तरों से जुड़ूंगा जो विश्लेषण करते हैं, या सीधे यहां विश्लेषण प्रदान करते हैं, और यहां सभी परिणामों को संक्षेप में प्रस्तुत करते हैं।
वे सभी विभिन्न उबंटू / जीसीसी संस्करणों में हैं, और परिणाम संभावित रूप से संस्करणों में बहुत स्थिर हैं, लेकिन यदि हमें कोई भिन्नता मिलती है तो अधिक सटीक संस्करण निर्दिष्ट करें।
एक समारोह के अंदर स्थानीय चर
यह हो main
या कोई अन्य समारोह:
void f(void) {
int my_local_var;
}
के रूप में दिखाया गया है: क्या करता है <मान बाहर अनुकूलित> जीडीबी में मतलब है?
-O0
: ढेर
-O3
: रजिस्टर अगर वे फैल नहीं करते हैं, अन्यथा ढेर
स्टैक मौजूद क्यों है पर प्रेरणा के लिए: x86 असेंबली में रजिस्टरों पर उपयोग किए जाने वाले पुश / पॉप निर्देशों का क्या कार्य है?
वैश्विक चर और static
फ़ंक्शन चर
/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;
/* DATA */
int my_global_implicit_explicit_1 = 1;
void f(void) {
/* BSS */
static int my_static_local_var_implicit;
static int my_static_local_var_explicit_0 = 0;
/* DATA */
static int my_static_local_var_explicit_1 = 1;
}
char *
तथा char c[]
जैसा कि दिखाया गया है: C और C ++ में स्थिर वैरिएबल कहाँ संग्रहीत हैं?
void f(void) {
/* RODATA / TEXT */
char *a = "abc";
/* Stack. */
char b[] = "abc";
char c[] = {'a', 'b', 'c', '\0'};
}
TODO बहुत बड़े स्ट्रिंग शाब्दिक भी स्टैक पर रखा जाएगा? या .data
? या संकलन विफल हो जाता है?
तर्क वितर्क
void f(int i, int j);
प्रासंगिक कॉलिंग कन्वेंशन के माध्यम से जाना चाहिए, जैसे: https://en.wikipedia.org/wiki/X86_calling_conctionions X86 के लिए, जो प्रत्येक चर के लिए विशिष्ट रजिस्टरों या स्टैक स्थानों को निर्दिष्ट करता है।
फिर जैसा कि दिखाया गया है कि <मान अनुकूलित किया गया> जीडीबी में क्या मतलब है? , -O0
फिर सब कुछ ढेर में डाल देता है, जबकि -O3
संभव के रूप में रजिस्टरों का उपयोग करने की कोशिश करता है।
हालाँकि, यदि फ़ंक्शन इनलाइन हो जाता है, तो उन्हें नियमित स्थानीय लोगों की तरह ही व्यवहार किया जाता है।
const
मेरा मानना है कि इससे कोई फर्क नहीं पड़ता क्योंकि आप इसे टाइपकास्ट कर सकते हैं।
इसके विपरीत, यदि कंपाइलर यह निर्धारित करने में सक्षम है कि कुछ डेटा कभी नहीं लिखा गया है, तो यह सिद्धांत रूप में इसे जगह दे सकता है .rodata
भले ही वह न हो।
TODO विश्लेषण।
संकेत
वे चर हैं (जिसमें पते शामिल हैं, जो संख्याएं हैं), इसलिए सभी शेष :-)
malloc
एक फ़ंक्शन है, और: इस सवाल का बहुत मतलब नहीं है malloc
,malloc
int *i = malloc(sizeof(int));
*i
एक चर है जिसमें एक पता होता है, इसलिए यह उपरोक्त मामले पर पड़ता है।
जैसे कि मॉलॉक आंतरिक रूप से कैसे काम करता है, जब आप इसे कहते हैं तो लिनक्स कर्नेल अपने आंतरिक डेटा संरचनाओं पर लिखने योग्य के रूप में कुछ पते चिह्नित करता है, और जब उन्हें प्रोग्राम द्वारा शुरू में छुआ जाता है, तो एक गलती होती है और कर्नेल पृष्ठ तालिकाओं को सक्षम करता है, जो एक्सेस की सुविधा देता है बिना सेगफुल के होता है: x86 पेजिंग कैसे करता है?
ध्यान दें कि यह मूल रूप से वही है जो exec
syscall हुड के नीचे करता है जब आप एक निष्पादन योग्य चलाने की कोशिश करते हैं: यह उन पृष्ठों को चिह्नित करता है जो इसे लोड करना चाहते हैं, और वहां प्रोग्राम लिखते हैं, यह भी देखें: कर्नेल को एक निष्पादन योग्य बाइनरी फ़ाइल के तहत कैसे चल रहा है linux? सिवाय इसके कि exec
कुछ अतिरिक्त सीमाएँ हैं जहाँ पर लोड करना है (जैसे कि कोड स्थानांतरित नहीं है )।
सटीक के लिए इस्तेमाल किया syscall malloc
है mmap
आधुनिक 2020 कार्यान्वयन में, और अतीत में brk
इस्तेमाल किया गया था: क्या malloc () उपयोग brk () या mmap ()?
गतिशील पुस्तकालय
मूल रूप mmap
से स्मृति में एड करें: /unix/226524/what-system-call-is-used-to-load-lbooks-in-linux/462710#462710
एनवायरनमेंट वेरिएबल्स और main
एसargv
प्रारंभिक स्टैक के ऊपर: /unix/75939/where-is-the-environment-string-actual-stored TODO क्यों नहीं .data में?