2011-08-24 5 views
17

मैं इस प्रक्रिया और लिंकर स्क्रिप्ट जोड़ने गहरी समझने के लिए मैं एक साधारण लिंकर स्क्रिप्ट कार्यान्वयन है कि मैं कुछ आदेश जोड़कर में सुधार किया है पाया कोशिश कर रहा हूँ ... binutils दस्तावेज़ को देख:एक साधारण लिंकर स्क्रिप्ट का सही तरीके से उपयोग कैसे करें? जब चलाने के निष्पादन SIGKILL हो जाता है

OUTPUT_FORMAT("elf32-i386", "elf32-i386", 
      "elf32-i386") 
OUTPUT_ARCH(i386) 

ENTRY(mymain) 

SECTIONS 
{ 
    . = 0x10000; 
    .text : { *(.text) } 
    . = 0x8000000; 
    .data : { *(.data) } 
    .bss : { *(.bss) } 
} 

void mymain(void) 
{ 
    int a; 
    a++; 
} 

अब मैं एक निष्पादन का निर्माण करने की कोशिश की: मेरे कार्यक्रम एक बहुत ही सरल कार्यक्रम है

gcc -c main.c 
ld -o prog -T my_script.lds main.o 

लेकिन अगर मैं करने की कोशिश रन prog इसे स्टार्टअप के दौरान SIGKILL प्राप्त करता है। मुझे पता है कि जब एक प्रोग्राम संकलित और आदेश के साथ जुड़ा हुआ है:

gcc prog.c -o prog 

अंतिम निष्पादन crt1.o, crti.o और crtn.o लेकिन मेरे मामले के बारे में क्या जैसे अन्य वस्तु फ़ाइलों की भी उत्पाद है? इस लिंकर स्क्रिप्ट का उपयोग करने का सही तरीका कौन सा है?

उत्तर

20

मुझे लगता है कि अपने कोड ठीक चल रहा है, और अंत में मुसीबत में हो रही: क्या आप a++ के बाद होने की उम्मीद करते हैं?

mymain() केवल एक सामान्य सी फ़ंक्शन है, जो इसके कॉलर पर वापस आने का प्रयास करेगा।

लेकिन आपने इसे ईएलएफ एंट्री पॉइंट के रूप में सेट किया है, जो ईएलएफ लोडर को सही जगह पर प्रोग्राम सेगमेंट लोड करने के बाद इसे कूदने के लिए कहता है - और यह आपको वापस आने की उम्मीद नहीं करता है।

उन "अन्य ऑब्जेक्ट फ़ाइलें जैसे crt1.o, crti.o और crtn.o" आमतौर पर सी प्रोग्राम के लिए इस सामग्री को संभालते हैं। एक सी प्रोग्राम के लिए ईएलएफ एंट्री पॉइंट main() नहीं है - इसके बजाए, यह एक रैपर है जो main() (उदाहरण के लिए argc और argv प्लेटफॉर्म के आधार पर स्टैक या रजिस्टरों पर तर्क) को सेट करने के लिए उचित वातावरण स्थापित करता है, main() पर कॉल करता है (उम्मीद है कि यह वापस आ सकता है), और उसके बाद exit सिस्टम कॉल (main() से वापसी कोड के साथ) को आमंत्रित करता है।


[अपडेट निम्नलिखित टिप्पणियां:]

जब मैं gdb के साथ अपने उदाहरण का प्रयास करें, मुझे लगता है कि यह वास्तव में mymain() से लौटने पर विफल करता है: mymain पर एक ब्रेकपाइंट सेट करने के बाद, और फिर के माध्यम से कदम निर्देश, मुझे लगता है कि यह वेतन वृद्धि करता है, तो समारोह उपसंहार में मुसीबत में हो जाता है:

$ gcc -g -c main.c 
$ ld -o prog -T my_script.lds main.o 
$ gdb ./prog 
... 
(gdb) b mymain 
Breakpoint 1 at 0x10006: file main.c, line 4. 
(gdb) r 
Starting program: /tmp/prog 

Breakpoint 1, mymain() at main.c:4 
4   a++; 
(gdb) display/i $pc 
1: x/i $pc 
0x10006 <mymain+6>:  addl $0x1,-0x4(%ebp) 
(gdb) si 
5  } 
1: x/i $pc 
0x1000a <mymain+10>: leave 
(gdb) si 
Cannot access memory at address 0x4 
(gdb) si 
0x00000001 in ??() 
1: x/i $pc 
Disabling display 1 to avoid infinite recursion. 
0x1: Cannot access memory at address 0x1 
(gdb) q 

कम से कम i386 के लिए, ईएलएफ लोडर लोड कोड दर्ज करने से पहले एक समझदार ढेर सेट करता है, इसलिए आप ई सीएफ प्रविष्टि बिंदु को सी फ़ंक्शन पर सेट कर सकते हैं और उचित व्यवहार प्राप्त कर सकते हैं; हालांकि, जैसा कि मैंने उपरोक्त उल्लेख किया है, आपको एक स्वच्छ प्रक्रिया को स्वयं से बाहर निकलना होगा। और यदि आप सी रनटाइम का उपयोग नहीं कर रहे हैं, तो आप बेहतर ढंग से सी रनटाइम पर निर्भर किसी भी पुस्तकालय का उपयोग नहीं करेंगे।

तो यहाँ इस बात का एक उदाहरण है, अपने मूल लिंकर स्क्रिप्ट का उपयोग कर - के रूप में a के अंतिम मूल्य के साथ लेकिन सी कोड ज्ञात मान को a आरंभ, और एक exit सिस्टम कॉल आह्वान करने के लिए संशोधित साथ (इनलाइन विधानसभा का प्रयोग करके) निकास कोड। (नोट: मुझे अभी एहसास हुआ है कि आपने बिल्कुल नहीं कहा है कि आप किस प्लेटफॉर्म का उपयोग कर रहे हैं; मैं यहां लिनक्स मान रहा हूं।)

$ cat main2.c 
void mymain(void) 
{ 
    int a = 42; 
    a++; 
    asm volatile("mov $1,%%eax; mov %0,%%ebx; int $0x80" : : "r"(a) : "%eax"); 
} 
$ gcc -c main2.c 
$ ld -o prog2 -T my_script.lds main2.o 
$ ./prog2 ; echo $? 
43 
$ 
+0

धन्यवाद यूथर्स के लिए मैथ्यू। मैं कहता हूं कि प्रोग्राम स्टार्टअप पर दुर्घटनाग्रस्त हो जाता है क्योंकि gdb यह कहता है ... मुझे पता है कि 'मुख्य' से पहले अन्य फ़ंक्शन कहा जाता है, उदाहरण के लिए ctors मुझे लगता है। लेकिन अगर मैं 'मुख्य' के लिए दूसरा नाम कहूं तो मुझे इसे निर्दिष्ट करना चाहिए? और, यदि मैं अपने प्रोग्राम को 'ld' के साथ स्पष्ट रूप से लिंक करता हूं तो क्या मुझे सी रनटाइम ऑब्जेक्ट फ़ाइलों को भी पास करना होगा? – MirkoBanchi

+0

आप क्या हासिल करने की कोशिश कर रहे हैं? क्या आप सामान्य सी रनटाइम और पुस्तकालयों का उपयोग करना चाहते हैं? यदि ऐसा है, तो आपके मुख्य फ़ंक्शन को 'मुख्य' कहा जाना चाहिए: सी रनटाइम कॉल यही है। (यह ईएलएफ एंट्री पॉइंट जैसा ही नहीं है, जो आमतौर पर 'crt1.o' में '_start' है।) यदि आप सीधे' ld' का आह्वान कर रहे हैं, तो हाँ, आपको विभिन्न सी रनटाइम फ़ाइलों को स्वयं लिंक करना होगा। यदि आप 'gcc' का उपयोग कर रहे हैं, तो यह आपके लिए ऐसा करेगा। आप देख सकते हैं कि यह 'gcc -v' के साथ क्या करता है, लेकिन आपको यह जानना होगा कि यह एक रैपर के माध्यम से 'ld' को आमंत्रित करता है,' collect2' (देखें [यहां] (http://gcc.gnu.org/onlinedocs/gcc -4.6.1/gccint/Collect2.html))। –

+0

मुझे पता होगा कि संभव है कि एक निष्पादन योग्य (ईएलएफ प्रारूप) बनाएं जो सी रनटाइम ऑब्जेक्ट फ़ाइलों को लिंक किए बिना सही ढंग से चलता है। – MirkoBanchi

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