2009-11-26 12 views
5

पर स्टैक मैं वर्तमान में लिनक्स पर एआरएम असेंबली के साथ सीखने के अभ्यास के रूप में खेल रहा हूं। मैं 'बेयर' असेंबली का उपयोग कर रहा हूं, यानी कोई libcrt या libgcc नहीं। क्या कोई मुझे पहले निर्देश से पहले कार्यक्रम की शुरुआत में स्टैक-पॉइंटर और अन्य रजिस्ट्रारों के बारे में जानकारी के बारे में जानकारी दे सकता है? स्पष्ट रूप से _start पर पीसी/आर 15 अंक, और शेष दो अपवादों के साथ 0 पर शुरू किया गया प्रतीत होता है; एसपी/आर 13 अंक मेरे कार्यक्रम के बाहर एक पते पर, और आर 1 अंक थोड़ा अधिक पते पर।प्रोग्राम रजिस्टरों की प्रारंभिक स्थिति और लिनक्स एआरएम

कुछ ठोस सवाल तो:

  • r1 में मूल्य क्या है?
  • क्या एसपी में मूल्य कर्नेल द्वारा आवंटित वैध स्टैक है?
  • यदि नहीं, तो स्टैक आवंटित करने की पसंदीदा विधि क्या है; ब्रैक का उपयोग या एक स्थिर .bs अनुभाग आवंटित?

किसी भी संकेत दिए गए सराहना की जाएगी।

उत्तर

2

यहाँ मैं एक लिनक्स/एआरएम कार्यक्रम मेरी संकलक के साथ आरंभ करने के लिए उपयोग करें: पर

/** The initial entry point. 
*/ 
asm(
"  .text\n" 
"  .globl _start\n" 
"  .align 2\n" 
"_start:\n" 
"  sub  lr, lr, lr\n"   // Clear the link register. 
"  ldr  r0, [sp]\n"    // Get argc... 
"  add  r1, sp, #4\n"   // ... and argv ... 
"  add  r2, r1, r0, LSL #2\n" // ... and compute environ. 
"  bl  _estart\n"    // Let's go! 
"  b  .\n"     // Never gets here. 
"  .size _start, .-_start\n" 
); 

आप देख सकते हैं, मैं सिर्फ argc, argv मिलता है, और ढेर से वातावरण सामान [एसपी] ।

एक छोटी सी स्पष्टीकरण: प्रक्रिया 'स्मृति में एक वैध क्षेत्र के लिए ढेर सूचक अंक। आर 0, आर 1, आर 2, और आर 3 फ़ंक्शन के पहले तीन पैरामीटर हैं जिन्हें कॉल किया जा रहा है। मैं उन्हें क्रमशः argc, argv, और वातावरण के साथ populate।

+0

धन्यवाद। क्या यह सेटअप कहीं भी दस्तावेज है जिसे आप जानते हैं? –

+0

मुझे यकीन है कि यह होना चाहिए, लेकिन मुझे यह मानना ​​है कि मैंने इसे जीडीबी का उपयोग करके समझ लिया है। –

0

मैं एआरएम लिनक्स उपयोग नहीं किया है, लेकिन मैं सुझाव है कि आप या तो libcrt के लिए स्रोत को देखो और देखें कि वे क्या करते हैं, या उपयोग gdb एक मौजूदा निष्पादन में कदम करने के लिए। आपको असेंबली कोड के माध्यम से बस सोर्स कोड की आवश्यकता नहीं होनी चाहिए।

सब कुछ आप पता लगाने के लिए बहुत पहले कोड किसी भी बाइनरी निष्पादन द्वारा निष्पादित के भीतर हो जाना चाहिए की जरूरत है।

उम्मीद है कि इससे मदद मिलती है।

टोनी

3

यहाँ uClibc crt है। ऐसा लगता है कि सभी रजिस्ट्रार r0 को छोड़कर अपरिभाषित हैं (जिसमें atexit() के साथ पंजीकृत होने वाला फ़ंक्शन पॉइंटर शामिल है) और sp जिसमें वैध स्टैक पता है।

तो, मूल्य आप r1 में देखते हैं शायद कुछ आप पर भरोसा कर सकते नहीं है।

कुछ डेटा आप के लिए ढेर पर रखा जाता है।

+0

उपयोगी लिंक, धन्यवाद। –

5

चूंकि यह लिनक्स है, तो आप देख सकते हैं कि यह कर्नेल द्वारा कैसे कार्यान्वित किया जाता है।

रजिस्ट्रार पर 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 इन संकेत के पहले को इंगित करेंगे)।
  • प्रत्येक पर्यावरण चर के लिए एक सी स्ट्रिंग के लिए एक सूचक, शून्य के बाद (यह शायद ही कभी देखा गया envpmain() का तीसरा पैरामीटर; 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_tablesargc, argv, और envp डालता है पर ढेर में (ताकि वे r0 में समाप्त होता है स्थापित कर रहे हैं - r2 के लिए एक कॉल के लिए उम्मीद के क्रम में main())।

अंत में, r0 शून्य के बजाय आपके लिए शून्य क्यों था (argc एक होना चाहिए यदि आपने प्रोग्राम को कोई तर्क नहीं दिया है)? मैं syscall मशीनरी में गहरी कुछ अनुमान लगा रहा हूं, इसे सिस्टम कॉल के रिटर्न वैल्यू के साथ ओवरराइट करें (जो निष्पादित होने के बाद शून्य होगा)। आप kernel_execve में देख सकते हैं (जो syscall मशीनरी का उपयोग नहीं करता है, क्योंकि यह कर्नेल कॉल करता है जब कर्नेल मोड से निष्पादित करना चाहता है) कि यह के वापसी मूल्य के साथ जानबूझकर r0 को ओवरराइट करता है।

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