क्या मैं पहले से संकलित बाइनरी में 'rpath' को बदल सकता हूं?


92

मेरे पास एक पुराना निष्पादन योग्य है जो स्क्रैप हीप के लिए निर्धारित है, लेकिन यह अभी तक वहां नहीं है। यह मेरे पर्यावरण से हटाए गए कुछ कामों पर निर्भर करता है, लेकिन मेरे पास कुछ ऐसे स्थान हैं जहां यह ठीक काम करता है। आईडी इस स्टेबल लिबास के लिए इस निष्पादन योग्य को इंगित करना पसंद करता है। हां, मैं LD_LIBRARY_PATH सेट कर सकता हूं, लेकिन यह निष्पादन योग्य कई स्क्रिप्ट्स, और कई उपयोगकर्ताओं से कॉल किया जाता है और मैं इसे एक स्थान पर ठीक करना पसंद करूंगा।

मेरे पास इसके लिए कोई स्रोत नहीं है, और इसे प्राप्त करना कठिन होगा। मैं सोच रहा था - क्या मैं इस फाइल को संपादित कर सकता हूं, एक ईएलएफ जागरूक संपादक का उपयोग कर सकता हूं, और इसे जोड़ने के लिए एक साधारण PATH को rpath में डालकर नए परिवादों को मारा है? क्या यह संभव है, या एक बार ईएलएफ बाइनरी बनाने के बाद, आप चीजों को स्थानों पर ठीक कर देते हैं और उन्हें स्थानांतरित नहीं किया जा सकता है?


3
इसे गोले में लपेटें जो LD_LIBRARY_PATH सेट करता है और बाइनरी को कॉल करता है। शेल स्क्रिप्ट को एक जगह पर रखें जो कॉलर्स के पैट में है।
Wildplasser 18

LD_LIBRARY_PATH को बाल प्रक्रियाओं द्वारा विरासत में मिला है। आप शायद ऐसा न चाहें।
विल

1
@ तो हाँ और मैंने पहले ही कहा कि मैं ऐसा नहीं करना चाहता। :)
रिच होमोलका

जवाबों:


78

एक उपकरण है, chrpathजो ऐसा कर सकता है - यह संभवतः आपके वितरण के पैकेज में उपलब्ध है।


9
मैक उपयोगकर्ताओं के लिए सिर्फ एक नोट, ध्वज के install_name_toolसाथ ऐसा कर सकते हैं-rpath
केविन टोनन

10
आप त्रुटि मिलती है: <binary>: no rpath or runpath tag found., आप उपयोग नहीं कर सकते chrpathइसे बदलना है, लेकिन आप उपयोग कर सकते हैं patchelfइस मामले में:patchelf --set-rpath /path/to/libaries <binary>
phyatt

मुझे लगता है कि जब से संभव हो तो chrpath पसंद करते हैं, जबकि यह अधिक सार्वभौमिक है, patchelf में कुछ लंबे समय तक चलने वाला बग है जो नाटकीय रूप से आपके पुस्तकालयों / निष्पादकों के आकार को बढ़ाता है।
तरणकी

156

chrpathकहा जाता है की तुलना में अधिक सार्वभौमिक उपकरण है patchelf। यह मूल रूप से निक्स और निक्स (पैकेजिंग सिस्टम और एक जीएनयू / लिनक्स वितरण) के लिए पैकेज बनाने में उपयोग के लिए बनाया गया था।

यदि बाइनरी में कोई रैपाथ नहीं होता है (जिसे रैंपैम्प कहा जाता है), chrpathविफल रहता है:

chrpath -r '$ORIGIN/../lib64' rdsamp 
rdsamp: no rpath or runpath tag found.

दूसरी ओर,

patchelf --set-rpath '$ORIGIN/../lib64' rdsamp

सफल ठीक है।


9
विशेष रूप से, patchelfएक बाइनरी में एक rpath जोड़ने में सक्षम है जिसमें एक rpath शामिल नहीं है, फिर भी - जहां chrpathकेवल पहले से मौजूद प्रविष्टि को संशोधित करने में सक्षम होना प्रतीत होता है।
12

4
एक सामान्य नोट के रूप में, यह rpathऔर के बीच के सूक्ष्म अंतर को समझने के लायक है runpath। असल में, एक ओवरराइड कर सकता है LD_LIBRARY_PATHऔर दूसरा नहीं कर सकता। जानकारी के लिए, ब्लॉग
स्टुअर्ट बर्ग

6
कष्टप्रद बात यह है कि दोनों chrpathऔर patchelfउनके शब्दावली के साथ खराब कर रहे हैं। उदाहरण के लिए, patchelfऊपर दिखाई गई कमांड बदल जाएगी runpathलेकिन rpathतब तक नहीं जब तक आप --force-rpathविकल्प प्रदान नहीं करते ।
स्टुअर्ट बर्ग

10
@superbatfish हाँ, लेकिन अंतर आमतौर पर मायने नहीं रखता। CHANGELOG की यह प्रविष्टि patchelfइसे समझाती है: " --set-rpath, --shrink-rpathऔर --print-rpathअब DT_RUNPATHअधिक पसंद करते हैं DT_RPATH, जो अप्रचलित है। अपडेट करते समय, यदि दोनों मौजूद हैं, तो दोनों अपडेट किए जाते हैं। यदि केवल DT_RPATH मौजूद है, तो इसे DT_RUNPATHतब तक परिवर्तित किया जाता है जब तक कि --force-rpathयह निर्दिष्ट न हो। , DT_RUNPATHजोड़ा जाता है जब तक --force-rpathकि निर्दिष्ट नहीं किया जाता है, जिस स्थिति में एक DT_RPATHजोड़ा जाता है। " विकल्प का नाम संभवतः संगतता कारणों के लिए अपरिवर्तित रखा गया था।
user7610

2
अब तक का सबसे अच्छा उत्तर, यह इसके बजाय स्वीकृत उत्तर होना चाहिए!
केनेथ होस्टे

12

जैसे @ user7610 ने कहा, जाने का सही तरीका patchelfउपकरण है।

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

विषय पर एक व्यापक लेख के लिए, यहां क्लिक करें

सबसे पहले, कई डेवलपर्स के बारे में बात करते हैं RPATH, लेकिन वे वास्तव में मतलब रखते हैं RUNPATH। ये दो अलग-अलग वैकल्पिक गतिशील अनुभाग हैं, और लोडर उन्हें बहुत अलग तरीके से संभालता है। आप मेरे द्वारा पहले बताए गए लिंक में उनके बीच अंतर के बारे में अधिक पढ़ सकते हैं।

अभी के लिए, बस याद रखें:

  • अगर RUNPATH सेट किया जाता है, RPATHतो अनदेखा कर दिया जाता है
  • RPATH वंचित है और इससे बचा जाना चाहिए
  • RUNPATH को प्राथमिकता दी जाती है क्योंकि इसे ओवरराइड किया जा सकता है LD_LIBRARY_PATH

वर्तमान R [UN] PATH देखें

readelf -d <path-to-elf> | egrep "RPATH|RUNPATH"

R [UN] को साफ़ करें

patchelf --remove-rpath <path-to-elf>

टिप्पणियाँ:

  • दोनों को निकालता है RPATHऔरRUNPATH

R [UN] PATH में मान जोड़ें

patchelf [--force-rpath] --set-rpath "<desired-rpath>" <path-to-elf>

टिप्पणियाँ:

  • <desired-path> अल्पविराम से अलग निर्देशिका सूची है, जैसे: /my/libs:/my/other/libs
  • यदि आप निर्दिष्ट करते हैं --force-rpath, सेट करते हैं RPATH, अन्यथा सेट करता हैRUNPATH

1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsसेट DT_RUNPATH, और वह है जिसे सबसे अधिक लोगों को उपयोग करना चाहिए। RUNPATHद्वारा ओवरराइड किया जा सकता है LD_LIBRARY_PATH, इसलिए लोगों को उपयोग नहीं करना चाहिए --force-rpath
jww

@jww मैं देख रहा हूं कि मैंने RPATH के पदावनति के बारे में कोई टिप्पणी नहीं की है, इसलिए मैंने अभी एक जोड़ा है। धन्यवाद!
डेनियल ट्रुगमैन

ध्यान दें कि उदाहरण <desired-path>एक कोलन का उपयोग करता है; यह एक अल्पविराम होना चाहिए (जो है:) /my/libs,/my/other/libs
एलन डे स्मेट

@AlanDeSmet, मैं अल्पविराम के बारे में नहीं जानता, लेकिन बृहदान्त्र मेरे लिए काम करता है।
डैनियल ट्रुगमैन

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