2010-07-18 7 views
33

के साथ निर्मित स्थैतिक पुस्तकालयों में छिपाने वाला प्रतीक मैं यह पता लगाने की कोशिश कर रहा हूं कि मैं एक स्थिर पुस्तकालय का निर्माण कर सकता हूं जो इंटरफ़ेस को निर्यात करना चाहते हैं, इसके अलावा, अपनी सभी आंतरिक वस्तुओं और कार्यों को छुपाता है। मैं एक्सकोड (जीसीसी 4.2) के साथ प्रयोग कर रहा हूँ।एक्सकोड/जीसीसी

मैंने प्रति सी ++ कक्षाओं पर __attribute__((visibility("hidden"))) विशेषता का उपयोग किया है। मैंने फ़ाइल-स्थानीय (स्थैतिक) आदि के रूप में छोटे सहायक सी कार्यों को भी परिभाषित किया है।

हालांकि, जब मैं strings परिणामस्वरूप .a लाइब्रेरी फ़ाइल पर चलाता हूं, तब भी रिलीज कॉन्फ़िगरेशन में संकलित होने पर भी, मुझे अभी भी नाम दिखाई देते हैं मेरे स्पष्ट रूप से छिपे हुए वर्गों के, उनके विधि नामों के साथ, यहां तक ​​कि फ़ाइल-स्थानीय कार्यों के नाम भी वहां के चारों ओर घूमते हैं।

मैंने -fvisibility=hidden और -fno-rtti को जीसीसी झंडे में जोड़ा है। हालांकि इससे कुछ तारों को कम कर दिया जाता है, कक्षा के नाम, विधि नाम, और स्थैतिक कार्य नाम अभी भी सादा या उलझन-लेकिन-पढ़ने योग्य रूप में मौजूद हैं।

क्या इस सामग्री को बाइनरी में उत्सर्जित सभी आंतरिक सामग्री के स्ट्रिंग नामों के बिना कंपाइलर प्राप्त करने का कोई विश्वसनीय तरीका है? किसी भी बाहरी क्लाइंट को जोड़ने के लिए यह आवश्यक नहीं होना चाहिए।

(स्पष्टीकरण के लिए: मैं आंतरिक नामकरण के लंबवत होने के बारे में पूछ रहा हूं, बनाम शाब्दिक निर्यात बाध्यकारी ज़रूरतों के विरुद्ध। मैं विघटित हूं कि सभी आंतरिक कार्य दिखाई दे रहे हैं strings कमांड के माध्यम से, भले ही इन प्रतीकों को औपचारिक रूप से निर्यात किया गया हो या नहीं।)

धन्यवाद।

+2

यदि आरटीटीआई सक्षम है, तो सभी प्रकार के नामों को एम्बेड किया जा रहा है, चाहे 'type_info :: name()' काम करने के लिए। आप '-फनो-आरटीआई' के साथ पुनः संयोजित करने का प्रयास कर सकते हैं और देख सकते हैं कि इससे कोई फर्क पड़ता है या नहीं। बेशक, यदि आप कहीं भी 'dynamic_cast' का उपयोग कर रहे हैं, तो यह काम नहीं करेगा। – Thomas

+0

संकेत के लिए धन्यवाद। कोशिश की, लेकिन सभी नाम अभी भी उलझन में हैं। –

+0

आपको वास्तव में उत्तर देने के बारे में सोचना चाहिए क्योंकि ब्लीटर द्वारा किसी को भी कोई चालबाजी की आवश्यकता नहीं है। न केवल मेरे अधिकांश नामों को हटा दिया, बल्कि यह पुस्तकालय के आकार को बहुत कम करता है जिसे मुझे साझा करने की आवश्यकता है। –

उत्तर

36

आंतरिक नामों छिपाई जा रही है कुछ सरल Xcode निर्माण सेटिंग की आवश्यकता है, और यह स्रोत को संशोधित करने या बनाया उत्पाद के प्रकार बदलने के लिए आवश्यक आम तौर पर नहीं है।

  1. एक एकल वस्तु prelink प्रदर्शन से मॉड्यूल के बीच आवश्यक किसी भी आंतरिक प्रतीकों हटा दें। हाँ (GENERATE_MASTER_OBJECT_FILE = YES) को "एकल-ऑब्जेक्ट प्रीलिंक करें" नामक एक्सकोड बिल्ड सेटिंग सेट करें। यह एलडी को "-r" ध्वज के साथ चलाने का कारण बनता है।
  2. सुनिश्चित करें कि सेटिंग "पट्टी शैली" के लिए "गैर वैश्विक प्रतीक" पर सेट है (STRIP_STYLE = गैर-वैश्विक), इस गुजरता ld करने के लिए "-x" बनाओ।
  3. स्ट्रिपिंग केवल वास्तव में स्थिर पुस्तकालयों पर किया जाता है, तो बाद के प्रसंस्करण सक्षम है (और यह डिफ़ॉल्ट नहीं है)। हां में एक्सकोड बिल्ड सेटिंग "परिनियोजन पोस्टप्रोसेसिंग" सेट करें। (DEPLOYMENT_POSTPROCESSING = हाँ)। यह भी सुनिश्चित करें कि "अलग स्ट्रिप का उपयोग करें" हां पर सेट है (हमेशा डिफ़ॉल्ट नहीं) (SEPARATE_STRIP = YES)।
  4. हैं, तो स्थानीय प्रतीकों के अलावा, आप वैश्विक प्रतीकों आप पट्टी आदेश को अतिरिक्त विकल्प की आपूर्ति कर सकते में से कुछ को हटाने के लिए, Xcode निर्माण "अतिरिक्त पट्टी झंडे" सेटिंग के तहत की आवश्यकता है। जैसे मैं सामान्य रूप से स्ट्रिप "-R somefile" विकल्प का उपयोग करता हूं ताकि फ़ाइल को प्रतीकों की एक अतिरिक्त सूची के साथ प्रदान किया जा सके जिसे मैं वैश्विक प्रतीक तालिका से हटा देना चाहता हूं।
+0

बढ़िया! मैंने बस एक्सकोड 5.1 बीटा के साथ सुझाव दिया था, और यह पूरी तरह से काम किया। मुझे जिस चीज की जरूरत थी। –

+6

मैं उपर्युक्त सूची में 5 जोड़ने का सुझाव दूंगा: हाँ में "प्रतीक हिडनबाइडफल्ट" सेट करें। (यह कोड जनरेशन अनुभाग में है)। यह -दृश्यता = छुपा के बराबर है। चरण 1..4 ने मुझे तारों को हटाने में मदद की लेकिन चरण 5 गैर सार्वजनिक विधियों, स्थैतिक चर और बफर को छुपाता है। – DanielHsH

+0

@DanielHsH ओपी के सवाल ने कहा कि वह पहले ही प्रतीक दृश्यता नियंत्रित कर चुका था, लेकिन हां, आपका सुझाव उन अन्य मामलों के लिए एक अच्छा विचार है जहां स्पष्ट नियंत्रण अभी तक नहीं रखा गया है। यह परीक्षण करने के लिए भुगतान करता है कि अंतिम उत्पाद सही ढंग से लिंक किया जा सकता है (एक गतिशील खंड या निष्पादन योग्य में) हालांकि, संभावना है कि कॉलर्स अनजाने में निजी प्रतीकों से जुड़ रहे हों। – bleater

12

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

एक बार जब आप सही ढंग से अपने लक्ष्य की स्थापना की है, तो निम्न चरणों में मदद मिलेगी प्रतीक सही छुपा मिलती है:

  1. सेट का निर्माण सेटिंग्स में हाँ करने के लिए विकल्प "डिफ़ॉल्ट रूप से छुपा प्रतीक"। यह सुनिश्चित करता है कि फ़ाइलों में संकलित सभी प्रतीकों को निजी के रूप में चिह्नित किया गया है।

  2. चूंकि यह एक पुस्तकालय है, तो आपको कुछ प्रतीकों को सार्वजनिक रखने की आवश्यकता है। आपको उन कार्यों के लिए कोड रखना चाहिए जिन्हें आप अलग-अलग फ़ाइलों में सार्वजनिक रूप से दिखाना चाहते हैं, और उन फ़ाइलों को -fvisibility=default ध्वज के साथ संकलित करें (आप इस ध्वज को अलग-अलग फ़ाइलों के लिए सेट कर सकते हैं "बिल्ड ध्वज> संकलन स्रोत> - एक्सकोड में कंपाइलर ध्वज")। वैकल्पिक रूप से, आप उस कार्य/वर्ग के नाम को उपसर्ग कर सकते हैं जिसे आप __attribute__((visibility("default"))) निर्देश के साथ दिखाना चाहते हैं।

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

  4. प्रतीकों को निजी रूप से चिह्नित करने के बाद भी वे अब भी .o फ़ाइल में दिखाई देते हैं।आपको निजी प्रतीकों से छुटकारा पाने के लिए अलग करने की आवश्यकता है। यह "स्ट्रिपेड लिंक्ड प्रोडक्ट" सेटिंग को बिल्ड सेटिंग्स में हां में सेट करके किया जा सकता है। इस विकल्प को सेट करने से ऑब्जेक्ट फ़ाइल पर strip -x कमांड चलाता है जो ऑब्जेक्ट फ़ाइल से निजी प्रतीकों को हटा देता है।

  5. डबल जाँच सभी आंतरिक प्रतीकों निर्माण प्रक्रिया द्वारा उत्पन्न अंतिम पुनर्निधारणीय वस्तु फ़ाइल पर एनएम आदेश चलाकर चले गए हैं।

उपर्युक्त चरण आपको एनएम कमांड से प्रतीक नामों से छुटकारा पाने में मदद करेंगे। यदि आप अपनी ऑब्जेक्ट फ़ाइल पर स्ट्रिंग कमांड चलाते हैं (कुछ तारों और ऑब्जेक्ट नाम अपवादों के माध्यम से संकलित किए जाने के कारण) आप अभी भी कुछ फ़ंक्शन नाम और फ़ाइल नाम देखेंगे। मेरे colleagues में से एक ऐसी स्क्रिप्ट है जो बाइनरी अनुभागों को देखकर और उन तारों का नाम बदलकर इन प्रतीकों में से कुछ का नाम बदलती है। मैंने इसे आपके लिए उपयोग करने के लिए यहां पोस्ट किया है: https://gist.github.com/varungulshan/6198167। आप इस स्क्रिप्ट को एक्सकोड में एक अतिरिक्त निर्माण चरण के रूप में जोड़ सकते हैं।

+0

उत्तर के लिए धन्यवाद, हमने इसे किया लेकिन अब हम इसे सिम्युलेटर पर नहीं चला सकते हैं, यह लिंक नहीं करता है। यह केवल डिवाइस पर काम करता है। हमें जो त्रुटि मिल रही है वह है: ld: दावा विफल: (atom-> fixupCount() == 1), फ़ंक्शन targetClassName, फ़ाइल/SourceCache/ld64/ld64-136/src/ld/parsers/macho_relocatable_file.cpp, पंक्ति 4973। क्लैंग: त्रुटि: लिंकर कमांड निकास कोड 1 के साथ विफल रहा (उपयोग -v आमंत्रण देखने के लिए)। क्या आपको इस मुद्दे का सामना करना पड़ा? धन्यवाद – Yoav

+0

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

+0

ठीक है, क्या आप इसे पोस्ट कर सकते हैं या इसे मेरे मेल पर भेज सकते हैं? हमें अभी भी इसके साथ समस्याएं हैं .... – Yoav

0

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

मान लीजिए कि आप इन दो ग फ़ाइलों करते हैं:

// f1.c 
const char *get_english_greeting(void) 
{ 
    return "hello"; 
} 

__attribute__((visibility("default"))) 
const char *get_greeting(void) 
{ 
    return get_english_greeting(); 
} 

और

// f2.c 
#include <stdio.h> 
const char *get_english_greeting(void); 

__attribute__((visibility("default"))) 
void print_greeting(void) 
{ 
    puts(get_english_greeting()); 
} 

आप एक स्थिर पुस्तकालय के निर्यात में इन दो फ़ाइलों कनवर्ट करना चाहते हैं दोनों get_greeting और print_greeting नहीं बल्कि get_english_greeting आप जो स्थिर बनाना नहीं चाहते हैं क्योंकि आप इसे अपनी लाइब्रेरी में उपयोग करना चाहते हैं।

यहाँ कि प्राप्त करने के लिए कदम हैं:

gcc -fvisibility=hidden -c f1.c f2.c 
ld -r f1.o f2.o -o libf.o 
objcopy --localize-hidden libf.o 
ar rcs libf.a libf.o 

अब इस काम करता है:

// gcc -L. main.c -lf 
void get_greeting(void); 
void print_greeting(void); 
int main(void) 
{ 
    get_greeting(); 
    print_greeting(); 
    return 0; 
} 

और यह नहीं करता है:

// gcc -L. main.c -lf 
const char *get_english_greeting(void); 
int main(void) 
{ 
    get_english_greeting(); 
    return 0; 
} 

बाद आप इस त्रुटि मिलती है के लिए :

/tmp/ccmfg54F.o: In function `main': 
main.c:(.text+0x8): undefined reference to `get_english_greeting' 
collect2: error: ld returned 1 exit status 

जो हम चाहते हैं वह है।

ध्यान दें कि छिपे हुए प्रतीक नाम स्थिर पुस्तकालय में अभी भी दिखाई दे रहे हैं लेकिन लिंकर स्थिर स्थिर पुस्तकालय के बाहर उनके साथ लिंक करने से इंकार कर देगा। प्रतीक नामों को पूरी तरह से निकालने के लिए आपको स्ट्रिप और obfuscate करने की आवश्यकता होगी।