2010-12-15 15 views
10

मेरे प्रश्नों में से एक पर टिप्पणियों के बाद मुझे यह जानने के लिए उत्सुकता है कि जब कोई निष्पादन योग्य को ओवरराइट करता है तो क्या होता है। मुझे इस मामले पर मेरी समझ की जांच करनी है।क्या होता है जब आप मेमोरी-मैप किए गए निष्पादन योग्य को ओवरराइट करते हैं?

कहें कि मेरे पास /usr/bin/myprog है। मैं इसे चलाता हूं और इसलिए ओएस /usr/bin/myprog लोड करता है, शायद http://en.wikipedia.org/wiki/Memory-mapped_file#Common_uses के माध्यम से।

किसी भी कारण से यह प्रक्रिया स्मृति में बनी हुई है और मैं वास्तव में फैसला करता हूं कि मैंने एक बग तय कर लिया है और मैं /usr/bin/myprog को ओवरराइट करता हूं।

तो, जहाँ तक मैं यह समझ के रूप में:

  • myprog का एक उदाहरण पहले से ही भरी हुई है और मैं फ़ाइल जहाँ से myprog पहले से ही लोड किया गया था की जगह, myprog के कहने असंशोधित है।
  • यदि मैं myprog का नया उदाहरण चलाता हूं तो यह नया कोड उपयोग करेगा।

क्या मैं सही हूँ?

हालांकि, स्मृति-मैप की गई फ़ाइलों पर आलेख के अनुसार, ऐसी तकनीक एक डेवलपर को फ़ाइल के हिस्सों का इलाज करने की अनुमति देती है जैसे कि वे भौतिक स्मृति हैं।

तो मुझे चीजों को समझने में एक विरोधाभास दिखाई देता है। यदि पेज वास्तव में केवल मांग पर लोड होते हैं, तो myprog मानते हैं कि 100% पेजेड नहीं है, तो यह विकिपीडिया लेख का तात्पर्य है कि नए पेज डिस्क पर फ़ाइल से लोड होंगे, जो मूल छवि लोड होने के बाद बदल गई है।

हालांकि, मुझे पूरा यकीन है कि मेरी दो संकलित छवियां समान नहीं होंगी और प्रत्येक फ़ाइल के लिए प्रासंगिक पता ऑफ़सेट समान नहीं हैं। तो, यह मानते हुए, निर्देश सूचक बहुत खोने जा रहा है ... मुझे पूरा यकीन है कि एक ऑपरेटिंग सिस्टम एक ही प्रक्रिया के हिस्से के रूप में स्मृति में दो अलग-अलग छवियों के हिस्सों को लोड नहीं करता है।

तो प्रोग्राम के निष्पादन के लिए मेमोरी-मैपिंग/मांग-पेजिंग का संयोजन कैसे काम करता है? क्या उस फ़ाइल को ओवरराइट करना प्रत्येक निष्पादन योग्य पृष्ठों पर पेज गलती को ट्रिगर करेगा ताकि यह सुनिश्चित किया जा सके कि यह वर्तमान में चल रही प्रक्रिया के लिए लोड हो गया है?

#include <stdio.h> 
#include <unistd.h> 

int main(int argc, char** argv) 
{ 
    printf("Program resident..."); 
    while(1) 
    { 
     printf("??? Just notifying you I'm still here...\n"); 
     usleep(1000000); 
    } 

    return 0; 
} 

और यकीन है कि पर्याप्त मैं कर सकता है क) इस निष्पादन की जगह, जबकि यह चल रहा था और ख) इसके उत्पादन नहीं बदला गया है:

मैं इस के साथ त्वरित प्रयोग किया था।

तो क्या चल रहा है? मैं विशेष रूप से क्या करता हूं यह देखने के लिए मैं क्या कर सकता हूं (लिनक्स या विंडोज) के लिए किसी भी सुझाव की सराहना करता हूं।

धन्यवाद सब कुछ।

संपादित करें: इस सवाल का जो मैं बात कर रहे थे कि इस प्रश्न छिड़: Upgrades without reboot - what kinds of problems happen in practice?

इसके अलावा, मुझे पता है यह विशेष रूप से प्रोग्रामिंग से संबंधित नहीं है, लेकिन एक निष्पादन को अद्यतन करने के परिणाम। मुझे अभी भी दिलचस्पी है, और मैं इसे पूछने के लिए बेहतर जगह नहीं सोच सकता।

उत्तर

8

लिनक्स के तहत, यदि आप चल रहे समय निष्पादन योग्य को प्रतिस्थापित करते हैं, तो परिणाम अप्रत्याशित होते हैं और यह क्रैश हो सकता है। जिन पृष्ठों को संशोधित किया गया है (उदा। "बीएसएस" प्रारंभिक डेटा) प्रभावित नहीं होंगे, लेकिन जिन पृष्ठों को संशोधित नहीं किया गया है (उदा। अधिकांश कोड)।

मेरा अनुमान है कि आपके मामले में, स्ट्रिंग एक ऐसे हिस्से में थी जो एक संशोधित (प्रतिलिपि) पृष्ठ था, इसलिए प्रभावित नहीं हुआ था।

हालांकि, यह केवल तब होता है जब आप वास्तव में उसी फ़ाइल को ओवरराइट करते हैं।

अधिकांश समय, जब आप निष्पादन योग्य को प्रतिस्थापित करते हैं, तो आप निर्देशिका प्रविष्टि को अलग फ़ाइल के साथ बदल देंगे। यह आम तौर पर मौजूदा पर एक अस्थायी फ़ाइल (उसी निर्देशिका में) का नाम बदलकर किया जाता है। यह वही है (उदाहरण के लिए) पैकेज प्रबंधक करते हैं।

प्रतिस्थापन-निर्देशिका-प्रविष्टि मामले में, पिछली निष्पादन योग्य फ़ाइल पूरी तरह से अलग (अभी भी निष्पादित) फ़ाइल के रूप में मौजूद है, और पिछले निष्पादन योग्य के बिना किसी पृष्ठ के अपने पृष्ठों को त्याग दिया और पुनः लोड किया जा सकता है - यह अभी भी पुराना देखता है फ़ाइल।

लिंकर इसके आउटपुट के साथ क्या करता है, मुझे नहीं पता। लेकिन/usr/bin/install एक नई फ़ाइल बनाता है। मुझे उम्मीद है कि यह व्यवहार काफी जानबूझकर है।

+0

मैं देखता हूं। तो वास्तव में पैकेज प्रबंधक जानबूझकर प्रक्रिया के बारे में जानते हैं ... दिलचस्प। कुंआ। मुझे लगता है कि इसका जवाब टेड के जवाब के साथ संयुक्त है, अब मैं वास्तव में क्या होता है इसके बारे में बहुत कुछ जानता हूं। –

+0

इसके लिए यह क्या है इसके लिए ओएस एक्स (और सामान्य रूप से बीएसडी) पर भी लागू होता है और पॉज़िक्स में अच्छी तरह से परिभाषित किया गया है, 'अनलिंक (2) 'देखें। – elslooo

10
  1. क्या होता है या नहीं, आप rm /usr/bin/myprog और उसके बाद एक नया बना पर सब से पहले निर्भर करता है, या कि क्या आप open() और write() मौजूदा /usr/bin/myprog करने के लिए।

  2. आप पुराने /usr/bin/myprog फ़ाइल rm और उसके बाद ही नाम के साथ एक नया बना है, तो गिरी/फ़ाइल सिस्टम ड्राइवर नया संस्करण एक नया नोड देता है, और वर्ष inode तक /proc फाइल सिस्टम में चारों ओर झूठ बोल रही है रहता है जिस प्रक्रिया ने इसे खोला है उसे बंद कर देता है। आपकी मौजूदा प्रक्रिया /usr/bin/myprog में फ़ाइल का अपना निजी संस्करण, अनमोडिफाइड है, जब तक यह close() फ़ाइल डिस्क्रिप्टर नहीं है।

  3. सभी ऑपरेटिंग सिस्टम (विंडोज, लिनक्स, शायद ओएस एक्स) का उपयोग मांग-पृष्ठांकित स्मृति मानचित्रण (mmap() POSIX के लिए, मैं विंडोज के लिए बराबर याद नहीं कर सकते? - VirtualAlloc()) प्रक्रिया लोड करने के लिए। इस तरह निष्पादन योग्य के किसी भी वर्ग को स्पर्श नहीं किया जाता है, कभी स्मृति में लोड नहीं होता है।

  4. यदि यह एक पारंपरिक mmap() 'd फ़ाइल थे, और दो प्रक्रियाओं दोनों खोला/यह मैप किया गया है, और उनमें से कोई भी निर्दिष्ट MAP_PRIVATE (यानी प्रति-ऑन-राइट) mmap() करने के लिए कॉल, में तो दो प्रक्रियाओं होगा अनिवार्य रूप से एक ही भौतिक स्मृति पृष्ठ को देख रहे हैं और, दोनों को mmap()PROT_READ के साथ बुलाया गया है। PROT_WRITE, वे एक दूसरे के संशोधन देखेंगे।

  5. यदि यह एक पारंपरिक mmap() 'd फ़ाइल थे, और इस प्रक्रिया 1 खोला था/मैप किया गया यह, और फिर प्रक्रिया 2 हार्ड ड्राइव पर ही फाइल के साथ बेला के आसपास शुरू कर दिया write() कॉल (मेरी mmap नहीं ing) के माध्यम से , प्रक्रिया 1 वास्तव में इन परिवर्तनों को देखता है। मुझे लगता है कि कर्नल नोटिस करता है कि फ़ाइल को संशोधित किया जा रहा है और प्रभावित पृष्ठों को फिर से लोड किया जा रहा है।

  6. मुझे नहीं पता कि निष्पादन योग्य छवियों के लिए कोई विशेष mmap() व्यवहार है या नहीं? अगर मैंने अपने कार्यों में से किसी एक को पॉइंटर हैक किया है और कोड संशोधित किया है, तो क्या यह पृष्ठ को गंदे के रूप में चिह्नित करेगा? क्या गंदा पृष्ठ /usr/bin/myprog पर वापस लिखा जाएगा? जब मैं इसे आज़माता हूं, तो यह segfaults, तो मुझे लगता है कि जबकि _TEXT पृष्ठों को MAP_SHARED के साथ मैप किया गया है, तो उन्हें शायद PROT_WRITE नहीं मिलता है और इसलिए जब लिखा जाता है तो segfault। _DATA अनुभाग भी स्मृति में लोड हो जाते हैं, और निश्चित रूप से उनको संशोधित करने की आवश्यकता है, लेकिन उन्हें MAP_PRIVATE (कॉपी-ऑन-राइट) चिह्नित किया जा सकता है - इसलिए वे शायद /usr/bin/myprog फ़ाइल से अपना कनेक्शन नहीं रख पाएंगे।

  7. प्वाइंट 6 निष्पादन योग्य को सीधे संशोधित करने से संबंधित है। प्वाइंट 5 mmap() डी फ़ाइल को write() स्तर पर मनमाने ढंग से संशोधित करने के लिए संबंधित है। जब मैं एक निष्पादन योग्य (जो mmap() 'डी) को write() के साथ किसी अन्य प्रक्रिया में संशोधित करने का प्रयास करता है, तो मुझे 5 के समान परिणाम नहीं मिलते हैं। मैं write() कॉल के साथ निष्पादन योग्य में सभी प्रकार के भयानक परिवर्तन कर सकता हूं, और कुछ नहीं हुआ। फिर, जब मैं प्रक्रिया से बाहर निकलता हूं और इसे फिर से चलाने की कोशिश करता हूं, तो यह दुर्घटनाग्रस्त हो जाता है (बेशक - सबकुछ के बाद मैं निष्पादन योग्य फ़ाइल में कर रहा हूं)। यह मुझे भ्रमित करता है। मैं पैरामीटर को mmap() पर इस तरह से व्यवहार करने के लिए अनुमति नहीं दे सकता - कॉपी-ऑन-राइट नहीं, लेकिन मैप किए गए फ़ाइल में परिवर्तनों से प्रभावित नहीं हूं।

  8. ठीक है, मैं वापस बाइबल (स्टीवंस) पर गया और बड़ी समस्या MAP_PRIVATE बनाम MAP_SHARED है।MAP_PRIVATE कॉपी-ऑन-राइट है और MAP_SHARED नहीं है। जैसे ही आप इसमें संशोधन करते हैं, MAP_PRIVATE मैप किए गए पृष्ठ की एक प्रति बना देगा। यह अनिर्धारित है कि मूल फ़ाइल में संशोधन मैप किए गए MAP_PRIVATE पृष्ठों पर प्रचारित होगा, लेकिन ओएस एक्स के साथ वे नहीं करते हैं। MAP_SHARED मूल फ़ाइल से कनेक्शन को बनाए रखता है, जिससे फ़ाइल को अपडेट को स्मृति पृष्ठों और इसके विपरीत प्रसारित करने की अनुमति मिलती है। यदि एक मेमोरी ब्लॉक MAP_PRIVATE मैप किया गया है, तो आपके द्वारा किए गए कोई भी संशोधन डिस्क पर कभी भी लिखा नहीं जाएगा। MAP_SHARED ओटीओएच मैप किए गए पृष्ठों को लिखने के माध्यम से फ़ाइल में संशोधन की अनुमति देता है।

  9. छवि लोडर मानचित्र निष्पादन योग्य फ़ाइलों को MAP_PRIVATE के रूप में मानचित्र करता है। यह बिंदु 6 में व्यवहार को बताता है - किसी फ़ंक्शन के कोड में पॉइंटर को हैक करना और उसके बाद इसे संशोधित करना, भले ही आपको ऐसा करने की अनुमति हो, फिर भी डेटा को डिस्क पर वापस नहीं लिखा जाएगा। सैद्धांतिक रूप से ओएस छवि लोडर mmap() के बाद निष्पादन योग्य /usr/bin/myprog को बदलना संभव होना चाहिए, लेकिन जब भी मैं vmmap के साथ बहुत बड़े निष्पादन योग्य देखता हूं, तो उनका टेक्स्ट अनुभाग हमेशा पूरी तरह से निवासी लगता है। मुझे नहीं पता कि ऐसा इसलिए है क्योंकि ओएस एक्स का इमेज लोडर यह सुनिश्चित करने के लिए सभी पृष्ठों को छूता है कि वे कॉपी हो जाएं, या ओएस एक्स का पेज मैनेजर पेज निवासी (यह है) बनाने के बारे में बहुत आक्रामक है, लेकिन मेरे पास नहीं है ओएस एक्स में निष्पादन योग्य बनाने में सक्षम है जिसका टेक्स्ट अनुभाग पूरी तरह निवासी नहीं था जैसे ही main() शुरू हुआ।

  10. ओएस एक्स छवि लोडर मैप किए गए पृष्ठों को लोड करने के बारे में बहुत आक्रामक है। मैंने देखा है कि जब mmap() फ़ाइल में है, तो ओएस एक्स किसी भी निवासी को छोड़ने का फैसला करने से पहले इसे बहुत बड़ा होना चाहिए। एक 1 जीबी फ़ाइल पूरी तरह से लोड हो जाती है, लेकिन केवल 3 जीबी फाइल के लगभग 1.7 जीबी निवासी बन जाती है। यह 8 जीबी भौतिक रैम वाली मशीन पर है और 64-बिट ओएस एक्स कर्नेल चला रहा है। निष्पादन के केवल बाइनरी फ़ाइल भंडार एक छवि:

+0

+1। +2 अगर मैं इसे दे सकता हूं। मैं भी उलझन में हूँ; मैं अभी तक एक सभ्य स्पष्टीकरण नहीं पा रहा हूं कि क्या हो रहा है। मैं वही चीजों की अपेक्षा करता हूं - मुझे पता है कि मैं recompile/usr/bin/myprog कर सकता हूं और जो कुछ भी मैं करता हूं वह जो भी चल रहा है उसमें परिलक्षित नहीं होता है, फिर भी सबकुछ लोड-ऑन-डिमांड का सुझाव देता है। मैं लिनक्स पेड़ को देख रहा हूं यह देखने के लिए कि क्या मुझे पता चल सकता है कि क्या होता है (यदि एक प्रतिलिपि बनाई गई है)। –

0

आप आम तौर पर सही हैं। किसी भी विशिष्ट पल में स्मृति में वास्तव में संग्रहीत किया जाता है एक प्रति है।

लेकिन, इन छवियों में आमतौर पर कई अनुभाग होते हैं - या सेगमेंट। उनमें से एक वास्तविक मशीन निर्देशों को संग्रहीत करता है, आपके प्रोग्राम का संकलित कोड - और यह हमेशा पूरी तरह से लोड होता है। अन्य वर्गों में स्थिर डेटा हो सकता है - विभिन्न स्थिरांक (विशेष रूप से तार), जिसे आपने शायद अपने पूरे कोड में उपयोग किया था। इन वर्गों को ओएस ऑन-डिमांड द्वारा लोड किया जा सकता है।

1

मैक ओएस एक्स पर, जब मैं चल रहे किसी भी एप्लिकेशन को अपग्रेड कर रहा हूं, तो अपग्रेड प्रोग्राम से अनुरोध है कि एप्लिकेशन को आगे बढ़ने के लिए पूरी तरह से बंद कर दिया जाए, कुछ मामलों में, यह बढ़ता है लेकिन अपग्रेड तब तक प्रभावी नहीं होते हैं आवेदन पुनरारंभ करें। यह कभी-कभी पुस्तकालयों के उपयोग के नामों को सूचीबद्ध करता है जो ब्लॉक में अपग्रेड कर रहे हैं। मैं यह इसलिए कहता हूं, क्योंकि एप्लिकेशन पुस्तकालयों को लॉक करता है जिस पर यह निर्भर करता है और अपग्रेड प्रोग्राम उन्हें उपयोग करने के लिए नहीं जानता है अगर वे उपयोग में हैं। इस प्रकार, किसी भी भाग या पूरे चल रहे आवेदन को लिखने पर नहीं।

उदाहरण के लिए, Google क्रोम अपग्रेड के लिए पुनरारंभ करने के लिए पुन: प्रारंभ करने के लिए कहता है और विंडोज, लिनक्स और मैक ओएस एक्स पर प्रभाव डालता है। मुझे आशा है कि आपको यह कहने के लिए एक संकेत मिलेगा कि कहां देखना शुरू करना है।

2

मुझे यह लिंक एक और अधिक संक्षिप्त स्पष्टीकरण मिला। "अपडेट" के तहत भाग को देखें जहां लेखक ने अपनी मूल पोस्ट अपडेट की थी।

http://it.toolbox.com/blogs/locutus/why-linux-can-be-updated-without-rebooting-12826

पूरी फ़ाइल मेमोरी में लोड नहीं है, वे समूहों में बफ़र्स में पढ़ रहे हैं (जो एक तकनीकी शब्द है, यह आमतौर पर 4k है, लेकिन आप यह निर्धारित कर सकते हैं जब आपके फ़ाइल सिस्टम की स्थापना)।

जब आप कोई फ़ाइल खोलते हैं, तो कर्नेल लिंक का पालन करता है, और इनोड को फ़ाइल डिस्क्रिप्टर (एक संख्या जो आंतरिक रूप से ट्रैक रखता है) असाइन करता है। जब आप फ़ाइल को हटाते हैं, तो आप इनोड को "अनलिंक" कर रहे हैं; फाइल डिस्क्रिप्टर अभी भी इसे इंगित करता है। आप इसे हटाने के बाद पुरानी फ़ाइल के समान नाम के साथ एक नई फ़ाइल बना सकते हैं, प्रभावी रूप से इसे "प्रतिस्थापित" कर सकते हैं, लेकिन यह एक अलग इनोड को इंगित करेगा। कोई प्रोग्राम जो अभी भी पुरानी फ़ाइल खोलता है, अभी भी फ़ाइल डिस्क्रिप्टर के माध्यम से पुरानी फ़ाइल तक पहुंच सकता है, लेकिन आपने प्रोग्राम को प्रभावी ढंग से अपग्रेड कर दिया है। जैसे ही प्रोग्राम समाप्त हो जाता है (या फ़ाइल को बंद करता है), और शुरू होता है (या इसे फिर से एक्सेस करने का प्रयास करता है), यह नई फ़ाइल तक पहुंचता है, और वहां आपके पास फ़ाइल की एक पूरी तरह से जगह प्रतिस्थापन है!

तो, लिनक्स में, अपने निष्पादन योग्य केवल पेज से मांग पर, पढ़ा जा सकता है के रूप में आप ने कहा, लेकिन यह मूल खुला filehandle के माध्यम से पढ़ सकते हैं और नहीं कर रहा है नई फ़ाइल है कि आपके चल निष्पादन कार्यक्रम की जगह का अद्यतन inode । मुझे लगता है कि मेरे प्रयास के लिए

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