मैंने कोड जनरेशन कन्वेंशनों के लिए जीसीसी के विकल्पों के बारे में पढ़ा है , लेकिन समझ नहीं सका कि "स्थिति-स्वतंत्र कोड (पीआईसीआर) क्या करता है"। कृपया मुझे यह समझाने के लिए एक उदाहरण दें कि इसका क्या मतलब है।
मैंने कोड जनरेशन कन्वेंशनों के लिए जीसीसी के विकल्पों के बारे में पढ़ा है , लेकिन समझ नहीं सका कि "स्थिति-स्वतंत्र कोड (पीआईसीआर) क्या करता है"। कृपया मुझे यह समझाने के लिए एक उदाहरण दें कि इसका क्या मतलब है।
जवाबों:
पोजीशन इंडिपेंडेंट कोड का अर्थ है कि उत्पन्न मशीन कोड काम करने के लिए किसी विशिष्ट पते पर स्थित होने पर निर्भर नहीं है।
एग जंप्स को पूर्ण के बजाय सापेक्ष के रूप में उत्पन्न किया जाएगा।
छद्म विधानसभा:
तस्वीर: यह काम करेगा कि क्या कोड पता 100 या 1000 पर था
100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL CURRENT+10
...
111: NOP
नॉन-पीआईसी: यह तभी काम करेगा जब कोड 100 पते पर होगा
100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL 111
...
111: NOP
EDIT: टिप्पणी के जवाब में।
यदि आपका कोड -fPIC के साथ संकलित है, तो यह एक पुस्तकालय में शामिल करने के लिए उपयुक्त है - पुस्तकालय को अपने पसंदीदा स्थान से दूसरे पते पर मेमोरी में स्थानांतरित करने में सक्षम होना चाहिए, आपके पुस्तकालय के पते पर पहले से ही भरी हुई लाइब्रेरी हो सकती है।
-fPIC
किसी प्रोग्राम या स्टैटिक लाइब्रेरी को संकलित करते समय आप चूक सकते हैं , क्योंकि एक प्रक्रिया में केवल एक मुख्य कार्यक्रम मौजूद होगा, इसलिए कोई रनटाइम स्थानांतरण कभी आवश्यक नहीं होता है। कुछ प्रणालियों पर, कार्यक्रमों को अभी भी बढ़ाया सुरक्षा के लिए स्वतंत्र बनाया गया है ।
मैं समझाने की कोशिश करूँगा कि पहले से ही सरल तरीके से क्या कहा गया है।
जब भी एक साझा लिबर लोड किया जाता है, तो लोडर (ओएस पर कोड जो आपके द्वारा चलाए जा रहे किसी भी प्रोग्राम को लोड करता है) उस कोड के कुछ पते को बदल देता है जहां ऑब्जेक्ट को लोड किया गया था।
उपरोक्त उदाहरण में, गैर-PIC कोड में "111" को लोडर द्वारा पहली बार लोड किया गया था।
साझा नहीं की गई वस्तुओं के लिए, आप यह चाहते हैं कि ऐसा हो क्योंकि संकलक उस कोड पर कुछ अनुकूलन कर सकते हैं।
साझा किए गए ऑब्जेक्ट के लिए, यदि कोई अन्य प्रक्रिया उस कोड को "लिंक" करना चाहेगी तो उसे उसी वर्चुअल पते पर पढ़ना होगा या "111" से कोई मतलब नहीं होगा। लेकिन वह वर्चुअल-स्पेस पहले से ही दूसरी प्रक्रिया में उपयोग में हो सकता है।
Whenever a shared lib is loaded, the loader changes some addresses in the code depending on where the object was loaded to.
मुझे लगता है कि यह सही नहीं है अगर -fpic के साथ संकलित किया गया है और कारण -fpic मौजूद है अर्थात प्रदर्शन कारणों से या क्योंकि आपके पास एक लोडर है जो स्थानांतरित करने में सक्षम नहीं है या क्योंकि आपको विभिन्न स्थानों में या कई और कारणों से कई प्रतियों की आवश्यकता है।
साझा पुस्तकालयों में बनाया गया कोड आम तौर पर स्थिति-स्वतंत्र कोड होना चाहिए, ताकि साझा पुस्तकालय को मेमोरी में किसी भी पते पर आसानी से लोड किया जा सके। -fPIC
विकल्प सुनिश्चित करता है कि जीसीसी इस तरह के कोड पैदा करता है।
-fPIC
ध्वज पर ध्वज के बिना किसी भी पते पर लोड क्यों नहीं किया जाएगा ? क्या यह कार्यक्रम से जुड़ा नहीं है? जब प्रोग्राम चल रहा होता है, ऑपरेटिंग सिस्टम इसे मेमोरी में अपलोड करता है। क्या मैं कुछ भूल रहा हूँ?
-fPIC
यह सुनिश्चित करने के लिए कि इस लिंक को जोड़ने वाली प्रक्रिया में किसी भी आभासी पते पर लोड किया जा सकता है, यह सुनिश्चित करने के लिए ध्वज का उपयोग किया गया है? 5 मिनट की दोहरी टिप्पणियों के लिए खेद है कि पिछले एक को संपादित नहीं किया जा सकता है।
libwotnot.so
) और इसके साथ जोड़ने ( -lwotnot
) के बीच भेद । लिंक करते समय, आपको उपद्रव करने की आवश्यकता नहीं है -fPIC
। यह मामला हुआ करता था कि साझा पुस्तकालय का निर्माण करते समय, आपको यह सुनिश्चित करने की आवश्यकता थी कि -fPIC
सभी ऑब्जेक्ट फ़ाइलों को साझा पुस्तकालय में बनाया जाए। इन दिनों नियमों में बदलाव हो सकता है क्योंकि इन दिनों डिफ़ॉल्ट रूप से PIC कोड के साथ कंपाइलर का निर्माण होता है। तो, 20 साल पहले क्या महत्वपूर्ण था, और 7 साल पहले महत्वपूर्ण हो सकता है, इन दिनों कम महत्वपूर्ण है, मुझे विश्वास है। ओ / एस कर्नेल के बाहर के पते 'हमेशा' वर्चुअल पते होते हैं।
-fPIC
। इस ध्वज को पास किए बिना, .so का निर्माण करते समय उत्पन्न कोड विशिष्ट वर्चुअल पते पर लोड किए जाने की आवश्यकता है जो उपयोग में हो सकते हैं?
आगे जोड़ना ...
हर प्रक्रिया में एक ही वर्चुअल एड्रेस स्पेस होता है (यदि linux OS में फ्लैग का उपयोग करके वर्चुअल एड्रेस का रेंडमाइजेशन रोक दिया जाता है) (अधिक जानकारी के लिए एड्रेस स्पेस लेआउट को फिर से इनेबल और री-इनेबल करें अपने लिए )
इसलिए अगर इसका कोई साझा लिंकिंग (हाइपोटेटिकल परिदृश्य) है, तो हम बिना किसी नुकसान के एक ही समान निर्देश के लिए एक ही वर्चुअल एड्रेस दे सकते हैं।
लेकिन जब हम साझा किए गए ऑब्जेक्ट को exe से लिंक करना चाहते हैं, तो हम साझा किए गए ऑब्जेक्ट को दिए गए प्रारंभ पते के बारे में निश्चित नहीं हैं क्योंकि यह साझा ऑब्जेक्ट से जुड़े हुए आदेश पर निर्भर करेगा। कहा जा रहा है, अंदर का निर्देश हमेशा रहेगा। इसके लिंकिंग की प्रक्रिया के आधार पर अलग-अलग वर्चुअल एड्रेस।
तो एक प्रक्रिया अपने स्वयं के वर्चुअल स्पेस में 0x45678910 के रूप में .so को एड्रेस एड्रेस दे सकती है और उसी समय अन्य प्रक्रिया 0x12131415 का स्टार्ट एड्रेस दे सकती है और यदि वे सापेक्ष एड्रेसिंग का उपयोग नहीं करते हैं, तो .so बिल्कुल भी काम नहीं करेगा।
इसलिए उन्हें हमेशा सापेक्ष एड्रेसिंग मोड और इसलिए fpic विकल्प का उपयोग करना पड़ता है।
डायनामिक लाइब्रेरी में किसी फ़ंक्शन का लिंक तब हल किया जाता है जब लाइब्रेरी लोड होती है या रन टाइम पर होती है। इसलिए, प्रोग्राम चलाने पर निष्पादन योग्य फ़ाइल और डायनेमिक लाइब्रेरी दोनों को मेमोरी में लोड किया जाता है। स्मृति पता जिस पर एक डायनेमिक लायब्रेरी लोड है, उसे पहले से निर्धारित नहीं किया जा सकता है, क्योंकि एक निश्चित एड्रेस उसी डायनेमिक लाइब्रेरी के साथ उसी पते की आवश्यकता हो सकती है।
इस समस्या से निपटने के लिए आमतौर पर इस्तेमाल की जाने वाली दो विधियाँ हैं:
1.Relocation। कोड में सभी संकेत और पते को संशोधित किया जाता है, यदि आवश्यक हो, तो वास्तविक लोड पते को फिट करने के लिए। स्थानांतरण लिंकर और लोडर द्वारा किया जाता है।
2.Position- स्वतंत्र कोड। कोड के सभी पते वर्तमान स्थिति के सापेक्ष हैं। यूनिक्स जैसे सिस्टम में साझा की गई वस्तुएं डिफ़ॉल्ट रूप से स्थिति-स्वतंत्र कोड का उपयोग करती हैं। यह स्थानांतरण से कम कुशल है यदि प्रोग्राम लंबे समय तक चलता है, खासकर 32-बिट मोड में।
नाम " स्थिति-स्वतंत्र कोड " वास्तव में निम्नलिखित का अर्थ है:
कोड अनुभाग में कोई पूर्ण पते नहीं होते हैं, जिन्हें स्थानांतरण की आवश्यकता होती है, लेकिन केवल स्वयं सापेक्ष पते। इसलिए, कोड अनुभाग एक अनियंत्रित मेमोरी पते पर लोड किया जा सकता है और कई प्रक्रियाओं के बीच साझा किया जा सकता है।
डेटा अनुभाग कई प्रक्रियाओं के बीच साझा नहीं किया जाता है क्योंकि इसमें अक्सर लेखन योग्य डेटा होता है। इसलिए, डेटा सेक्शन में ऐसे पॉइंटर्स या एड्रेस हो सकते हैं, जिन्हें रिलोकेशन की ज़रूरत होती है।
सभी सार्वजनिक कार्यों और सार्वजनिक डेटा को लिनक्स में ओवरराइड किया जा सकता है। यदि मुख्य निष्पादन योग्य किसी फ़ंक्शन का साझा ऑब्जेक्ट में फ़ंक्शन के समान नाम है, तो मुख्य में संस्करण पूर्ववर्तीता लेगा, न केवल जब मुख्य से बुलाया जाता है, बल्कि साझा ऑब्जेक्ट से भी कॉल किया जाता है। इसी तरह, जब मुख्य में एक वैश्विक चर साझा वस्तु में एक वैश्विक चर के रूप में एक ही नाम है, तो मुख्य में उदाहरण का उपयोग किया जाएगा, यहां तक कि जब साझा वस्तु से एक्सेस किया जाएगा।
यह तथाकथित प्रतीक अंतर्क्रिया स्थैतिक पुस्तकालयों के व्यवहार की नकल करना है।
एक साझा ऑब्जेक्ट में अपने फ़ंक्शन के लिए पॉइंटर्स की एक तालिका होती है, जिसे प्रक्रिया लिंक टेबल (PLT) कहा जाता है और इस "ओवरराइड" सुविधा को लागू करने के लिए ग्लोबल ऑफ़सेट टेबल (GOT) नामक इसके चर के लिए पॉइंटर्स की एक तालिका। फ़ंक्शंस और सार्वजनिक चर तक सभी पहुंच इस तालिका के माध्यम से जाती हैं।
ps जहाँ डायनेमिक लिंकिंग से बचा नहीं जा सकता है, वहाँ स्थिति-स्वतंत्र कोड की टाइमकोन्सुमिंग सुविधाओं से बचने के विभिन्न तरीके हैं।
आप इस लेख से और अधिक पढ़ सकते हैं: http://www.agner.org/optimize/optimizing_cpp.pdf
पहले से ही पोस्ट किए गए उत्तरों के लिए एक मामूली जोड़: ऑब्जेक्ट फ़ाइलें जो स्वतंत्र होने के लिए संकलित नहीं हैं, वे स्थानांतरित करने योग्य हैं; उनमें स्थानांतरण तालिका प्रविष्टियाँ हैं।
ये प्रविष्टियाँ लोडर (उस कोड को थोड़ा मेमोरी में लोड करती है) को वर्चुअल एड्रेस स्पेस में वास्तविक लोड पते के लिए समायोजित करने के लिए पूर्ण पते को फिर से लिखने की अनुमति देती है।
एक ऑपरेटिंग सिस्टम सभी साझा कार्यक्रमों के साथ मेमोरी में भरी हुई "साझा ऑब्जेक्ट लाइब्रेरी" की एक प्रतिलिपि को उसी साझा लाइब्रेरी लाइब्रेरी से जोड़ने का प्रयास करेगा।
चूंकि कोड एड्रेस स्पेस (डेटा स्पेस के वर्गों के विपरीत) को सन्निहित होने की आवश्यकता नहीं है, और क्योंकि अधिकांश प्रोग्राम जो किसी विशिष्ट लाइब्रेरी से लिंक होते हैं, उनमें काफी हद तक निश्चित लाइब्रेरी डिपेंडेंसी ट्री होता है, यह ज्यादातर समय सफल होता है। उन दुर्लभ मामलों में जहां विसंगति है, हां, एक साझा ऑब्जेक्ट लाइब्रेरी की दो या अधिक प्रतियां स्मृति में होना आवश्यक है।
जाहिर है, कार्यक्रमों और / या कार्यक्रम के उदाहरणों के बीच एक पुस्तकालय के लोड पते को यादृच्छिक करने के लिए कोई भी प्रयास (ताकि एक शोषक पैटर्न बनाने की संभावना को कम करने के लिए) ऐसे मामलों को सामान्य बना देगा, दुर्लभ नहीं, इसलिए जहां एक प्रणाली ने इस क्षमता को सक्षम किया है, सभी को सभी साझा वस्तु पुस्तकालयों को स्वतंत्र करने के लिए संकलित करने का हरसंभव प्रयास करना चाहिए।
चूंकि मुख्य कार्यक्रम के शरीर से इन पुस्तकालयों में कॉल को भी स्थानांतरित किया जाएगा, इससे यह बहुत कम संभावना है कि एक साझा पुस्तकालय को कॉपी करना होगा।