चूंकि यह लिनक्स है, तो आप देख सकते हैं कि यह कर्नेल द्वारा कैसे कार्यान्वित किया जाता है।
रजिस्ट्रार पर load_elf_binary
के अंत में कॉल द्वारा सेट किए जाने लगते हैं (यदि आप आधुनिक लिनक्स सिस्टम का उपयोग कर रहे हैं, तो यह लगभग हमेशा ईएलएफ प्रारूप का उपयोग करेगा)। एआरएम के लिए, रजिस्ट्रार निम्नानुसार सेट किए गए प्रतीत होते हैं:
r0 = first word in the stack
r1 = second word in the stack
r2 = third word in the stack
sp = address of the stack
pc = binary entry point
cpsr = endianess, thumb mode, and address limit set as needed
स्पष्ट रूप से आपके पास एक वैध स्टैक है।मुझे लगता है कि r0
के मूल्य - r2
जंक हैं, और आपको स्टैक से सबकुछ पढ़ना चाहिए (आप देखेंगे कि मैं इसे बाद में क्यों सोचता हूं)। अब, चलो देखते हैं कि ढेर पर क्या है। स्टैक से आप जो पढ़ेंगे, वह create_elf_tables
से भरा हुआ है।
यहां ध्यान देने योग्य एक दिलचस्प बात यह है कि यह कार्य वास्तुकला-स्वतंत्र है, इसलिए वही चीजें (ज्यादातर) प्रत्येक ईएलएफ-आधारित लिनक्स आर्किटेक्चर पर ढेर पर रखी जाएंगी। निम्नलिखित ढेर पर है, क्रम में आप इसे लिखा होगा:
- पैरामीटर की संख्या (इस
main()
में argc
है)। प्रत्येक पैरामीटर एक शून्य द्वारा पीछा के लिए एक सी स्ट्रिंग के लिए
- एक सूचक (इस
main()
में argv
की सामग्री है, argv
इन संकेत के पहले को इंगित करेंगे)।
- प्रत्येक पर्यावरण चर के लिए एक सी स्ट्रिंग के लिए एक सूचक, शून्य के बाद (यह शायद ही कभी देखा गया
envp
main()
का तीसरा पैरामीटर; envp
इन पॉइंटर्स में से पहला इंगित करेगा)।
- "सहायक वेक्टर", जो जोड़े के अनुक्रम (एक मान के बाद एक प्रकार) है, जो पहले तत्व में शून्य (
AT_NULL
) के साथ एक जोड़ी द्वारा समाप्त किया गया है। इस सहायक वेक्टर में कुछ रोचक और उपयोगी जानकारी है, जिसे आप LD_SHOW_AUXV
पर्यावरण चर सेट 1
(उदाहरण के लिए LD_SHOW_AUXV=1 /bin/true
) पर किसी गतिशील रूप से जुड़े प्रोग्राम को चलाकर (यदि आप ग्लिब का उपयोग कर रहे हैं) देख सकते हैं। यह भी है जहां वास्तुकला के आधार पर चीजें थोड़ा भिन्न हो सकती हैं।
इस संरचना के बाद से, हर वास्तुकला के लिए एक ही है आप SYSV 386 ABI के पेज 54 पर ड्राइंग पर उदाहरण के लिए देखने के लिए कैसे चीजें एक साथ फिट (ध्यान दें, तथापि का एक बेहतर विचार प्राप्त करने के लिए कर सकते हैं, कि सहायक वेक्टर प्रकार उस दस्तावेज़ पर स्थिरांक लिनक्स का उपयोग करने से अलग हैं, इसलिए आपको उनके लिए लिनक्स हेडर देखना चाहिए)।
अब आप देख सकते हैं कि r0
- r2
की सामग्री कचरा क्यों है। स्टैक में पहला शब्द argc
है, दूसरा प्रोग्राम नाम (argv[0]
) के लिए एक सूचक है, और तीसरा शायद आपके लिए शून्य था क्योंकि आपने प्रोग्राम को कोई तर्क नहीं दिया था (यह argv[1]
होगा)। मुझे लगता है कि वे बड़े a.out
द्विपदीय प्रारूप के लिए इस तरह से, जैसा कि आप देख सकते हैं जो create_aout_tables
argc
, argv
, और envp
डालता है पर ढेर में (ताकि वे r0
में समाप्त होता है स्थापित कर रहे हैं - r2
के लिए एक कॉल के लिए उम्मीद के क्रम में main()
)।
अंत में, r0
शून्य के बजाय आपके लिए शून्य क्यों था (argc
एक होना चाहिए यदि आपने प्रोग्राम को कोई तर्क नहीं दिया है)? मैं syscall मशीनरी में गहरी कुछ अनुमान लगा रहा हूं, इसे सिस्टम कॉल के रिटर्न वैल्यू के साथ ओवरराइट करें (जो निष्पादित होने के बाद शून्य होगा)। आप kernel_execve
में देख सकते हैं (जो syscall मशीनरी का उपयोग नहीं करता है, क्योंकि यह कर्नेल कॉल करता है जब कर्नेल मोड से निष्पादित करना चाहता है) कि यह के वापसी मूल्य के साथ जानबूझकर r0
को ओवरराइट करता है।
धन्यवाद। क्या यह सेटअप कहीं भी दस्तावेज है जिसे आप जानते हैं? –
मुझे यकीन है कि यह होना चाहिए, लेकिन मुझे यह मानना है कि मैंने इसे जीडीबी का उपयोग करके समझ लिया है। –