जीसीसी और एलडी के साथ अप्रयुक्त सी / सी ++ प्रतीकों को कैसे निकालना है?


110

मुझे अपने निष्पादन योग्य आकार ( ARMविकास) के आकार को अनुकूलित करने की आवश्यकता है और मैंने देखा कि मेरी वर्तमान बिल्ड स्कीम ( gcc+ ld) में अप्रयुक्त प्रतीकों को छीना नहीं जा रहा है।

arm-strip --strip-unneededपरिणामी निष्पादकों / पुस्तकालयों के लिए उपयोग निष्पादन योग्य का आउटपुट आकार नहीं बदलता (मुझे पता नहीं क्यों, शायद यह आपको पसंद नहीं है)

मेरी बिल्डिंग पाइपलाइन को संशोधित करने का तरीका (यदि यह मौजूद है) क्या होगा , ताकि अप्रयुक्त प्रतीकों को परिणामस्वरूप फ़ाइल से छीन लिया जाए?


मैं इसके बारे में सोच भी नहीं सकता, लेकिन मेरा मौजूदा एम्बेडेड वातावरण बहुत "शक्तिशाली" नहीं है और बहुत अच्छे लोडिंग प्रदर्शन को बढ़ावा देने में परिणाम से 500Kबाहर भी बचा रहा है 2M

अपडेट करें:

दुर्भाग्य से वर्तमान gccसंस्करण मैं उपयोग नहीं है -dead-stripविकल्प और -ffunction-sections... + --gc-sectionsके लिए ldजिसके परिणामस्वरूप उत्पादन के लिए किसी भी महत्वपूर्ण अंतर नहीं देता है।

मैं हैरान हूं कि यह भी एक समस्या बन गई, क्योंकि मुझे यकीन था कि gcc + ldअप्रयुक्त प्रतीकों को स्वचालित रूप से पट्टी करना चाहिए (उन्हें भी क्यों रखना है?)।


आप कैसे जानते हैं कि प्रतीकों का उपयोग नहीं किया जाता है?
ज़्वारबा

कहीं भी संदर्भित नहीं => अंतिम आवेदन में उपयोग नहीं किया जा रहा है। मुझे लगता है कि कॉमप्लिंग / लिंकिंग के दौरान बिल्डिंग कॉल ग्राफ बहुत कठिन नहीं होना चाहिए।
यिप्पी-की-यूल

1
क्या आप मृत प्रतीकों को हटाकर .o फ़ाइल के आकार को कम करने की कोशिश कर रहे हैं, या आप निष्पादन योग्य मेमोरी में लोड होने के बाद वास्तविक कोड पदचिह्न के आकार को कम करने की कोशिश कर रहे हैं? तथ्य यह है कि आप कहते हैं "एम्बेडेड" बाद में संकेत देता है; आपके द्वारा पूछा गया प्रश्न पूर्व पर केंद्रित है।
इरा बैक्सटर

@ यदि मैं आउटपुट निष्पादन योग्य आकार को कम करने की कोशिश कर रहा हूं, क्योंकि (उदाहरण के रूप में) अगर मैं कुछ मौजूदा अनुप्रयोगों को पोर्ट करने का प्रयास करता हूं, जो boostपुस्तकालयों का उपयोग करते हैं, तो परिणामस्वरूप .exeफ़ाइल में कई अप्रयुक्त ऑब्जेक्ट फाइलें होती हैं और मेरे वर्तमान एम्बेडेड रनटाइम के विनिर्देशों के कारण। , किसी 10mbएप्लिकेशन को शुरू करना , उदाहरण के लिए, किसी 500kएप्लिकेशन को शुरू करने में अधिक समय लेता है ।
यिप्पी-की-यूल

8
@ यिप्पी: आप लोड समय को कम करने के लिए कोड से छुटकारा चाहते हैं; आप जिस कोड से छुटकारा पाना चाहते हैं, वह अप्रयुक्त तरीके हैं / आदि। पुस्तकालयों से। हां, आपको ऐसा करने के लिए कॉल ग्राफ़ बनाने की आवश्यकता है। यह इतना आसान नहीं है; यह एक वैश्विक कॉल ग्राफ़ होना चाहिए, इसे रूढ़िवादी होना चाहिए (कुछ ऐसी चीज़ों को हटा नहीं सकता है जो इसका उपयोग हो सकता है) और सटीक होना चाहिए (इसलिए आपके पास एक आदर्श कॉल ग्राफ़ के करीब है, इसलिए आप वास्तव में जानते हैं कि क्या नहीं है उपयोग किया गया)। बड़ी समस्या एक वैश्विक, सटीक कॉल ग्राफ है। ऐसा करने वाले कई कंपाइलरों के बारे में नहीं जानते हैं, अकेले ही लिंकर्स को दें।
इरा बैक्सटर

जवाबों:


131

जीसीसी के लिए, यह दो चरणों में पूरा किया जाता है:

पहले डेटा को संकलित करें लेकिन संकलक को अनुवाद इकाई के भीतर कोड को अलग-अलग वर्गों में विभाजित करने के लिए कहें। यह निम्नलिखित दो संकलक झंडे का उपयोग करके कार्यों, कक्षाओं और बाहरी चर के लिए किया जाएगा:

-fdata-sections -ffunction-sections

लिंकर ऑप्टिमाइज़ेशन फ़्लैग का उपयोग करके अनुवाद इकाइयों को एक साथ लिंक करें (इससे लिंकर अप्रतिबंधित वर्गों को छोड़ देता है)

-Wl,--gc-sections

इसलिए यदि आपके पास test.cpp नामक एक फ़ाइल थी, जिसमें दो फ़ंक्शन घोषित किए गए थे, लेकिन उनमें से एक अप्रयुक्त था, तो आप अप्रयुक्त एक को निम्नलिखित कमांड के साथ gcc (g ++) में छोड़ सकते हैं:

gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections

(ध्यान दें कि -O एक अतिरिक्त संकलक ध्वज है जो GCC को आकार के लिए अनुकूलित करने के लिए कहता है)


3
कृपया ध्यान दें कि यह जीसीसी के विकल्प विवरण (मैंने परीक्षण किया) के अनुसार निष्पादन योग्य को धीमा कर देगा।
मेटामोर्फोसिस

1
इसके साथ mingwस्टेटिक रूप से libstdc ++ को लिंक करते समय और ध्वज के साथ libgcc के साथ काम नहीं करता है -static। लिंकर विकल्प -strip-allकाफी हद तक मदद करता है, लेकिन फिर भी उत्पन्न निष्पादन योग्य (या dll) दृश्य स्टूडियो की तुलना में लगभग 4 तरह बड़ा होगा। बिंदु है, मेरा कोई नियंत्रण नहीं libstdc++था कि कैसे संकलित किया गया था। एक ldही विकल्प होना चाहिए ।
Fabio

34

यदि इस सूत्र पर विश्वास किया जाना है, तो आपको अपने स्वयं के अनुभाग में प्रत्येक फ़ंक्शन और डेटा ऑब्जेक्ट को डालने के लिए -ffunction-sectionsऔर-fdata-sections gcc को आपूर्ति करने की आवश्यकता है । तब आप --gc-sectionsअप्रयुक्त खंडों को हटाने के लिए और GNU ld को देते हैं।


6
@MSalters: यह डिफ़ॉल्ट नहीं है, क्योंकि यह C और C ++ मानकों का उल्लंघन करता है। अचानक वैश्विक आरंभ नहीं होता है, जिसके परिणामस्वरूप कुछ बहुत आश्चर्यचकित करने वाले प्रोग्रामर होते हैं।
बेन वोइगट जूल

1
@MSalters: केवल अगर आप गैर-मानक व्यवहार-ब्रेकिंग विकल्प पास करते हैं, जिसे आपने डिफ़ॉल्ट व्यवहार बनाने के लिए प्रस्तावित किया था।
बेन वोइगट

1
@MSalters: यदि आप एक पैच बना सकते हैं जो स्टेटिक इनिशियलाइज़र चलाता है अगर और केवल अगर प्रोग्राम के सही संचालन के लिए साइड इफेक्ट्स आवश्यक हैं, तो यह बहुत बढ़िया होगा। दुर्भाग्य से मुझे लगता है कि इसे पूरी तरह से करना अक्सर हल करने की समस्या को हल करने की आवश्यकता होती है, इसलिए आपको कई बार कुछ अतिरिक्त प्रतीकों को शामिल करने की आवश्यकता होगी। जो मूल रूप से इरा अपनी टिप्पणी के सवाल में कहता है। (BTW: "कार्यक्रम के सही संचालन के लिए आवश्यक नहीं" "अप्रयुक्त" की एक अलग परिभाषा है कि मानकों में इस शब्द का उपयोग कैसे किया जाता है)
बेन वोइग्ट

2
C में @BenVoigt, वैश्विक आरंभ के साइड-इफेक्ट्स नहीं हो सकते हैं (शुरुआती चरणों में लगातार अभिव्यक्ति होनी चाहिए)
MM

2
@ मैट: लेकिन यह सी ++ में सच नहीं है ... और वे एक ही लिंकर साझा करते हैं।
बेन वोइगट

25

आप gcc और ld के अपने संस्करण के लिए अपने डॉक्स देखना चाहेंगे:

हालाँकि मेरे लिए (OS X gcc 4.0.1) मुझे ये ld के लिए लगता है

-dead_strip

फ़ंक्शन और डेटा निकालें जो प्रविष्टि बिंदु या निर्यात किए गए प्रतीकों द्वारा पहुंच से बाहर हैं।

-dead_strip_dylibs

प्रवेश बिंदु या निर्यात किए गए प्रतीकों द्वारा पहुंच से बाहर होने वाली dylibs को हटा दें। यही है, dylibs के लिए लोड कमांड कमांड की पीढ़ी को दबा देता है जो लिंक के दौरान कोई प्रतीक नहीं देता है। इस विकल्प का उपयोग तब नहीं किया जाना चाहिए जब किसी dylib के खिलाफ लिंक किया जा रहा हो, जो कि कुछ अप्रत्यक्ष कारण जैसे कि dylib में एक महत्वपूर्ण इनिशलाइज़र हो।

और यह मददगार विकल्प

-why_live symbol_name

प्रतीकों_name के संदर्भों की एक श्रृंखला लॉग करता है। के साथ ही लागू है -dead_strip। यह डिबग करने में मदद कर सकता है कि क्यों आपको लगता है कि मृत पट्टी को हटा दिया जाना चाहिए नहीं।

Gcc / g ++ आदमी में एक नोट यह भी है कि कुछ प्रकार के डेड कोड एलिमिनेशन केवल तभी किए जाते हैं यदि कंपाइलिंग के दौरान ऑप्टिमाइज़ेशन सक्षम हो।

हालांकि ये विकल्प / शर्तें आपके संकलक के लिए नहीं हो सकते हैं, मेरा सुझाव है कि आप अपने डॉक्स में कुछ इसी तरह की तलाश करें।


यह कुछ भी नहीं करने के लिए लगता है mingw
फाबियो

-dead_stripएक gccविकल्प नहीं है ।
ar2015 4:23

20

प्रोग्रामिंग की आदतें भी मदद कर सकती हैं; उदाहरण के लिए staticउन फ़ंक्शंस में जोड़ें जिन्हें किसी विशिष्ट फ़ाइल के बाहर एक्सेस नहीं किया जाता है; प्रतीकों के लिए छोटे नामों का उपयोग करें (थोड़ा मदद कर सकते हैं, संभवतः बहुत अधिक नहीं); const char x[]जहां संभव हो उपयोग करें ; ... यह पेपर , हालांकि यह गतिशील साझा वस्तुओं के बारे में बात करता है, इसमें ऐसे सुझाव शामिल हो सकते हैं, जिनका अनुसरण करने पर, आपके अंतिम बाइनरी आउटपुट आकार को छोटा करने में मदद मिल सकती है (यदि आपका लक्ष्य ईएलएफ है)।


4
प्रतीकों के लिए छोटे नामों को चुनने में कैसे मदद मिलती है?
फ़ूज

1
अगर प्रतीकों को छीन नहीं लिया जाता है, ça va sans dire- लेकिन ऐसा लगता है कि इसे अभी कहा जाना चाहिए।
शिनटेकजेउ

@fuz पेपर गतिशील साझा वस्तुओं (जैसे .soलिनक्स पर) के बारे में बात कर रहा है , इसलिए प्रतीक नामों को बनाए रखना होगा ताकि पायथन के ctypesएफएफआई मॉड्यूल जैसे एपीआई उन्हें रनटाइम पर नाम से प्रतीक देखने के लिए उपयोग कर सकें।
ssokolow

18

जवाब है -flto। आपको इसे अपने संकलन और लिंक चरणों दोनों को पास करना होगा, अन्यथा यह कुछ भी नहीं करता है।

यह वास्तव में बहुत अच्छी तरह से काम करता है - एक माइक्रोकंट्रोलर कार्यक्रम के आकार को कम कर देता है जिसे मैंने अपने पिछले आकार के 50% से कम लिखा था!

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


1
"-Wl, - जीसी-सेक्शन" मेरे लिए मिनगॉव-डब्ल्यू 64 पर काम नहीं करता है, "-फ्लो" काम करता है। धन्यवाद
rhbc73

आउटपुट असेंबली बहुत अजीब है क्योंकि -fltoमुझे यह समझ में नहीं आता है कि यह दृश्य के पीछे क्या करता है।
ar2015

मेरा मानना ​​है कि -fltoयह प्रत्येक फ़ाइल को विधानसभा में संकलित नहीं करता है, यह उन्हें LLVM IR के लिए संकलित करता है, और फिर अंतिम लिंक उन्हें संकलित करता है जैसे कि वे सभी एक संकलन इकाई में थे। इसका मतलब है कि यह अप्रयुक्त कार्यों को समाप्त कर सकता है और गैर-इनलाइन static, और शायद अन्य चीजें भी। देखें llvm.org/docs/LinkTimeOptimization.html
टिमम्पी

13

जबकि प्रतीकों के बारे में सख्ती से नहीं, अगर आकार के लिए जा रहा है - हमेशा के साथ संकलित करें -Osऔर -sझंडे। -Osन्यूनतम निष्पादन योग्य आकार के लिए परिणामी कोड का अनुकूलन करता है और निष्पादन -sतालिका से प्रतीक तालिका और स्थानांतरण जानकारी को हटाता है।

कभी-कभी - यदि छोटे आकार की इच्छा होती है - विभिन्न अनुकूलन झंडे के साथ चारों ओर खेलना - या महत्व हो सकता है। उदाहरण के लिए टॉगल करना -ffast-mathऔर / या -fomit-frame-pointerकई बार आपको दर्जनों बाइट भी बचा सकता है।


जब तक आप भाषा मानक का अनुपालन करते हैं, तब तक अधिकांश अनुकूलन ट्विक सही कोड प्राप्त करेंगे, लेकिन मैंने -ffast-mathपूरी तरह से मानक-अनुरूप C ++ कोड में कहर बरपाया है, इसलिए मैं इसकी सिफारिश कभी नहीं करूंगा।
Raptor007

11

यह मुझे लगता है कि निमो द्वारा प्रदान किया गया उत्तर सही है। यदि वे निर्देश काम नहीं करते हैं, तो समस्या आपके द्वारा उपयोग किए जा रहे gcc / ld के संस्करण से संबंधित हो सकती है, एक अभ्यास के रूप में मैंने यहां विस्तृत निर्देशों का उपयोग करके एक उदाहरण कार्यक्रम संकलित किया है

#include <stdio.h>
void deadcode() { printf("This is d dead codez\n"); }
int main(void) { printf("This is main\n"); return 0 ; }

फिर मैंने उत्तरोत्तर अधिक आक्रामक डेड-कोड हटाने के स्विच का उपयोग करके कोड संकलित किया:

gcc -Os test.c -o test.elf
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections -Wl,--strip-all

ये संकलन और लिंकिंग पैरामीटर क्रमशः 8457, 8164 और 6160 बाइट्स के निष्पादन योग्य आकार का उत्पादन करते हैं, जो 'स्ट्रिप-ऑल' घोषणा से आने वाला सबसे महत्वपूर्ण योगदान है। यदि आप अपने प्लेटफ़ॉर्म पर समान कटौती नहीं कर सकते हैं, तो हो सकता है कि gcc का आपका संस्करण इस कार्यक्षमता का समर्थन न करे। मैं लिनक्स टकसाल 2.6.38-8-जेनेरिक x86_64 पर gcc (4.5.2-8ubuntu4), ld (2.21.0.20110327) का उपयोग कर रहा हूं


8

strip --strip-unneededकेवल आपके निष्पादन योग्य के प्रतीक तालिका पर कार्य करता है। यह वास्तव में किसी भी निष्पादन योग्य कोड को नहीं हटाता है।

मानक लायब्रेरी आपके द्वारा अपने सभी फ़ंक्शंस को अलग-अलग ऑब्जेक्ट फ़ाइलों में विभाजित करने के बाद प्राप्त होने वाले परिणाम को प्राप्त करती हैं, जिनका उपयोग करके संयुक्त किया जाता है ar। यदि आप परिणामी आर्काइव को लाइब्रेरी के रूप में लिंक करते हैं (यानी विकल्प दें-l your_library ld ) तो ld में केवल ऑब्जेक्ट फाइल्स शामिल होंगी, और इसलिए प्रतीकों, जो वास्तव में उपयोग किए जाते हैं।

उपयोग के इस समान प्रश्न पर आपको कुछ प्रतिक्रियाएं भी मिल सकती हैं।


2
स्थैतिक लिंक करते समय पुस्तकालय में अलग-अलग ऑब्जेक्ट फ़ाइलें केवल प्रासंगिक होती हैं। साझा पुस्तकालयों के साथ, पूरी लाइब्रेरी भरी हुई है, लेकिन निष्पादन योग्य में शामिल नहीं है, बिल्कुल।
जोनाथन लेफलर

4

मुझे नहीं पता कि क्या यह आपके वर्तमान पूर्वानुमान के साथ मदद करेगा क्योंकि यह एक हालिया विशेषता है, लेकिन आप वैश्विक रूप से प्रतीकों की दृश्यता को निर्दिष्ट कर सकते हैं। -fvisibility=hidden -fvisibility-inlines-hiddenसंकलन पर पासिंग लिंकर को बाद में अनावश्यक प्रतीकों से छुटकारा पाने में मदद कर सकता है। यदि आप एक निष्पादन योग्य (एक साझा पुस्तकालय के विपरीत) उत्पादन कर रहे हैं, तो ऐसा करने के लिए अधिक कुछ नहीं है।

अधिक जानकारी (और उदाहरण के पुस्तकालयों के लिए एक ठीक-ठाक दृष्टिकोण) जीसीसी विकि पर उपलब्ध है ।


4

जीसीसी 4.2.1 मैनुअल से, अनुभाग -fwhole-program:

मान लें कि वर्तमान संकलन इकाई पूरे कार्यक्रम को संकलित किए जाने का प्रतिनिधित्व करती है। सभी सार्वजनिक फ़ंक्शंस और चर इसके अपवाद के साथ होते हैं mainऔर जिन्हें विशेषता द्वारा मर्ज किया जाता है externally_visibleवे स्टैटिक फ़ंक्शंस बन जाते हैं और एक प्रभाव में अंतरप्रांतीय ऑप्टिमाइज़र द्वारा अधिक आक्रामक रूप से अनुकूलित हो जाते हैं। हालांकि यह विकल्प staticएकल फ़ाइल वाले कार्यक्रमों के लिए कीवर्ड के उचित उपयोग के बराबर है , विकल्प के साथ संयोजन में --combineइस ध्वज का उपयोग अधिकांश छोटे पैमाने के C कार्यक्रमों को संकलित करने के लिए किया जा सकता है क्योंकि फ़ंक्शन और चर पूरे संयुक्त संकलन इकाई के लिए स्थानीय हो जाते हैं, के लिए नहीं एकल स्रोत फ़ाइल ही।


हाँ, लेकिन संभवतः किसी भी तरह के वृद्धिशील संकलन के साथ काम नहीं करता है और शायद थोड़ा धीमा होने वाला है।
टिम्मम

@ टिमम: मुझे संदेह है कि आप सोच रहे हैं -flto
बेन वोइगट

हाँ! मैंने बाद में पाया कि (इसका कोई जवाब क्यों नहीं है?)। दुर्भाग्य से यह थोड़ा छोटा लग रहा था, इसलिए मैं केवल इसे अंतिम निर्माण के लिए सुझाऊंगा और फिर परीक्षण करूंगा कि बहुत निर्माण करें!
टिम्मम

-1

आप ऑब्जेक्ट फ़ाइल (उदाहरण के लिए निष्पादन योग्य) पर स्ट्रिप बाइनरी का उपयोग कर सकते हैं, जिससे सभी प्रतीकों को हटा दिया जा सके।

नोट: यह फ़ाइल को स्वयं बदलता है और प्रतिलिपि नहीं बनाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.