मैं एक विशिष्ट ग्लिबैक संस्करण से कैसे लिंक कर सकता हूं?


110

जब मैं अपने Ubuntu Lucid 10.04 PC पर कुछ संकलित करता हूं तो यह glibc के खिलाफ लिंक हो जाता है। ल्यूसिड 2.11 ग्लिबक का उपयोग करता है। जब मैं इस बाइनरी को दूसरे पीसी पर एक पुराने ग्लिबक के साथ चलाता हूं, तो कमांड यह कहता है कि इसमें कोई ग्लिब 2.11 नहीं है ...

जहाँ तक मुझे पता है कि glibc प्रतीक संस्करण का उपयोग करता है। क्या मैं एक विशिष्ट प्रतीक संस्करण के खिलाफ लिंक करने के लिए जीसीसी को बाध्य कर सकता हूं?

अपने ठोस उपयोग में मैं एआरएम के लिए एक जीसीसी क्रॉस टूलचैन संकलित करने की कोशिश करता हूं।


58
अर्घ यह वास्तव में कष्टप्रद लिनक्स समस्याओं में से एक है, जहां समाधान हमेशा "आपको ऐसा नहीं करना चाहिए", जिसका अर्थ है कि "यह काम नहीं करता है और किसी ने अभी तक इसे तय नहीं किया है"।
टिम्मम्म

3
लोगों ने विंडोज पर DLL नरक के बारे में शिकायत की। मुझे याद है लिनक्स कुछ aficionados विंडोज दुनिया से एक विशेष रूप से भयानक उदाहरण के रूप में लाने की कोशिश कर रहा है। जब में मैं पहले खत्म हुआ यह सब मैंने किया था पहले एक दशक से अधिक कर लिनक्स विकास मेरे हाथ में मेरे चेहरे को दफनाने था।
0xC0000022L

जवाबों:


69

आप सही हैं कि glibc प्रतीक संस्करण का उपयोग करता है। यदि आप उत्सुक हैं, तो glibc 2.1 में शुरू किए गए प्रतीक संस्करण के कार्यान्वयन को यहां वर्णित किया गया है और यहां वर्णित सूर्य के प्रतीक संस्करण का विस्तार है

एक विकल्प यह है कि आप अपने बाइनरी को स्टेटिकली लिंक करें। यह शायद सबसे आसान विकल्प है।

आप अपने बाइनरी को चेरोट बिल्ड वातावरण में भी बना सकते हैं, या एक glibc- new => glibc- पुराने क्रॉस-कंपाइलर का उपयोग कर सकते हैं।

Http://www.trevorpounds.com ब्लॉग पोस्ट के अनुसार पुराने संस्करण वाले सिंबल (ग्लिब) को लिंक करना , किसी भी प्रतीक को एक पुराने के खिलाफ लिंक करने के लिए मजबूर करना संभव है, जब तक कि वह एक ही .symverछद्म का उपयोग करके वैध हो। -op कि पहली बार में संस्करण प्रतीकों को परिभाषित करने के लिए प्रयोग किया जाता है। निम्नलिखित उदाहरण ब्लॉग पोस्ट से लिया गया है ।

निम्न उदाहरण ग्लिबक के रियलपथ का उपयोग करता है, लेकिन यह सुनिश्चित करता है कि यह पुराने 2.2.5 संस्करण के खिलाफ जुड़ा हुआ है।

#include <limits.h>
#include <stdlib.h>
#include <stdio.h>

__asm__(".symver realpath,realpath@GLIBC_2.2.5");
int main()
{
    const char* unresolved = "/lib64";
    char resolved[PATH_MAX+1];

    if(!realpath(unresolved, resolved))
        { return 1; }

    printf("%s\n", resolved);

    return 0;
}

18
glibc स्थैतिक लिंकिंग का समर्थन नहीं करता है - सांख्यिकीय रूप से जुड़े glibc प्रोग्राम अलग-अलग libc संस्करणों के साथ सिस्टम पर काम नहीं करते हैं।
मोनिका

5
glibc का libc.aअस्तित्व बना रहता है, glibc कुछ मामलों में इसका समर्थन करता है , हालाँकि यह अनुशंसित नहीं है (Drepper) । आपको गैर-तुच्छ कार्यक्रमों, esp कुछ भी है जो NSS ( FAQ में वर्कअराउंड ) का उपयोग करता है, से परेशानी होगी ।
mr.spuratic

20

साथ लिंक स्थैतिक । जब आप -static के साथ लिंक करते हैं , तो लिंकर निष्पादन योग्य के अंदर लाइब्रेरी को एम्बेड करता है, इसलिए निष्पादन योग्य बड़ा होगा, लेकिन इसे सिस्टम पर glibc के पुराने संस्करण के साथ निष्पादित किया जा सकता है, क्योंकि प्रोग्राम सिस्टम के बजाय स्वयं लाइब्रेरी का उपयोग करेगा ।


55
अक्सर इसका कारण यह है कि आप ऐसा करना चाहते हैं क्योंकि आप एक बंद स्रोत एप्लिकेशन वितरित कर रहे हैं। इस मामले में अक्सर लाइसेंसिंग कारणों से ऐसा करने की अनुमति नहीं है (ऐसा करने से आपको अपने सभी स्रोत कोड जारी करने की आवश्यकता होगी), इसलिए आपको -स्टिक के साथ सावधान रहने की आवश्यकता है।
मालवीयस

3
इस बीच कम से कम एक व्यक्ति अक्सर musl-libc का सहारा ले सकता है, लेकिन C ++ प्रोग्राम के साथ चीजें अधिक जटिल हो सकती हैं, इसलिए एक प्रतीक संस्करण को निर्दिष्ट करना अभी भी आवश्यक हो सकता है।
0xC0000022L

16

सेटअप 1: समर्पित जीसीसी के बिना अपने स्वयं के ग्लिब को संकलित करें और इसका उपयोग करें

चूंकि यह केवल प्रतीक संस्करण हैकिंग के साथ करना असंभव लगता है, आइए एक कदम आगे बढ़ें और खुद को glibc संकलित करें।

यह सेटअप काम कर सकता है और जल्दी है क्योंकि यह पूरे जीसीसी टूलकिन को फिर से नहीं करता है, बस ग्लिबक।

लेकिन यह विश्वसनीय के रूप में यह का उपयोग करता है मेजबान सी क्रम इस तरह की वस्तुओं के रूप में नहीं है crt1.o, crti.oऔर crtn.oglibc द्वारा प्रदान की। यह उल्लेख किया गया है: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_cocation उन वस्तुओं को जल्दी सेटअप करते हैं जो ग्लिबक पर भरोसा करते हैं, इसलिए मुझे आश्चर्य होगा कि चीजें आश्चर्यजनक रूप से दुर्घटनाग्रस्त हो गईं। और भयानक सूक्ष्म तरीके।

अधिक विश्वसनीय सेटअप के लिए, नीचे सेटअप 2 देखें।

ग्लिबक बनाएँ और स्थानीय रूप से स्थापित करें:

export glibc_install="$(pwd)/glibc/build/install"

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`

सेटअप 1: बिल्ड को सत्यापित करें

test_glibc.c

#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>

atomic_int acnt;
int cnt;

int f(void* thr_data) {
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
    }
    return 0;
}

int main(int argc, char **argv) {
    /* Basic library version check. */
    printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());

    /* Exercise thrd_create from -pthread,
     * which is not present in glibc 2.27 in Ubuntu 18.04.
     * /programming/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

संकलित करें और चलाएं test_glibc.sh:

#!/usr/bin/env bash
set -eux
gcc \
  -L "${glibc_install}/lib" \
  -I "${glibc_install}/include" \
  -Wl,--rpath="${glibc_install}/lib" \
  -Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
  -std=c11 \
  -o test_glibc.out \
  -v \
  test_glibc.c \
  -pthread \
;
ldd ./test_glibc.out
./test_glibc.out

कार्यक्रम अपेक्षित परिणाम देता है:

gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674

कमांड https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_live से अनुकूलित किया गया, लेकिन --sysrootइसके साथ विफल रहा:

cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install

इसलिए मैंने इसे हटा दिया।

lddआउटपुट इस बात की पुष्टि करता है lddकि हमारे द्वारा अभी-अभी बनाए गए लाइब्रेरियों को वास्तव में अपेक्षित रूप से उपयोग किया जा रहा है:

+ ldd test_glibc.out
        linux-vdso.so.1 (0x00007ffe4bfd3000)
        libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
        libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
        /home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)

gccसंकलन डिबग आउटपुट शो है कि मेरे मेजबान क्रम वस्तुओं का उपयोग किया गया है, जो बुरा जैसा कि पहले उल्लेख है, लेकिन मैं यह कैसे हल करने के लिए पता नहीं है के रूप में है, जैसे यह शामिल हैं:

COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o

सेटअप 1: glibc संशोधित करें

अब आइए ग्लिबक को संशोधित करें:

diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */

+#include <stdio.h>
+
 #include "thrd_priv.h"

 int
 thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
 {
+  puts("hacked");
   _Static_assert (sizeof (thr) == sizeof (pthread_t),
                   "sizeof (thr) != sizeof (pthread_t)");

फिर recompile और फिर से स्थापित glibc, और recompile और हमारे प्रोग्राम को फिर से चलाएँ:

cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh

और हम hackedउम्मीद के मुताबिक कुछ समय मुद्रित करते हैं ।

यह आगे पुष्टि करता है कि हमने वास्तव में उस glibc का उपयोग किया था जिसे हमने संकलित किया था और मेजबान को नहीं।

उबंटू 18.04 पर परीक्षण किया गया।

सेटअप 2: क्रॉसस्टूल-एनजी प्राचीन सेटअप

इस सेटअप 1 के लिए एक विकल्प है, और यह सबसे सही सेटअप मैं अब तक हासिल कर लिया है है: सब कुछ जहाँ तक सही है के रूप में मैं भी शामिल सी क्रम जैसे वस्तुओं, का निरीक्षण कर सकते crt1.o, crti.o, और crtn.o

इस सेटअप में, हम एक पूर्ण समर्पित जीसीसी टूलकिन संकलित करेंगे जो कि हम चाहते हैं कि glibc का उपयोग करता है।

इस पद्धति का एकमात्र नकारात्मक पहलू यह है कि निर्माण में अधिक समय लगेगा। लेकिन मैं कुछ भी कम के साथ एक उत्पादन सेटअप जोखिम नहीं होगा।

crosstool-NG एक स्क्रिप्ट का एक सेट है जो GCC, glibc और bincils सहित हमारे लिए स्रोत से सब कुछ डाउनलोड और संकलित करता है।

हां जीसीसी निर्माण प्रणाली इतनी खराब है कि हमें इसके लिए एक अलग परियोजना की आवश्यकता है।

यह सेटअप केवल सही नहीं है क्योंकि क्रॉस्टूल-एनजी अतिरिक्त -Wlझंडे के बिना निष्पादन के निर्माण का समर्थन नहीं करता है , जो अजीब लगता है क्योंकि हमने स्वयं एनसीसी का निर्माण किया है। लेकिन सब कुछ काम करने लगता है, इसलिए यह केवल एक असुविधा है।

क्रॉसस्टूल-एनजी प्राप्त करें और इसे कॉन्फ़िगर करें:

git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig

एकमात्र अनिवार्य विकल्प जो मैं देख सकता हूं, यह सही कर्नेल हेडर का उपयोग करने के लिए आपके होस्ट कर्नेल संस्करण से मेल खा रहा है। इसके साथ अपना होस्ट कर्नेल संस्करण खोजें:

uname -a

जो मुझे दिखाता है:

4.15.0-34-generic

तो menuconfigमैं करता हूँ:

  • Operating System
    • Version of linux

इसलिए मैं चयन करता हूं:

4.14.71

जो पहला समान या पुराना संस्करण है। यह पुराने होने के बाद से कर्नेल पीछे संगत है।

अब आप के साथ निर्माण कर सकते हैं:

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

और अब संकलन के लिए लगभग तीस मिनट से दो घंटे तक प्रतीक्षा करें।

सेटअप 2: वैकल्पिक कॉन्फ़िगरेशन

इसके .configसाथ हमने जो उत्पन्न किया ./ct-ng x86_64-unknown-linux-gnuहै:

CT_GLIBC_V_2_27=y

यह करने के लिए, कि menuconfig:

  • C-library
  • Version of glibc

सहेजें .config, और बिल्ड के साथ जारी रखें।

या, यदि आप अपने स्वयं के ग्लिबक स्रोत का उपयोग करना चाहते हैं, उदाहरण के लिए नवीनतम गिट से ग्लिबक का उपयोग करना चाहते हैं, तो इस तरह से आगे बढ़ें :

  • Paths and misc options
    • Try features marked as EXPERIMENTAL: सच में सेट
  • C-library
    • Source of glibc
      • Custom location: हाँ बोलो
      • Custom location
        • Custom source location: अपने glibc स्रोत वाली निर्देशिका की ओर संकेत करें

जहां ग्लिब को क्लोन किया गया था:

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28

सेटअप 2: इसका परीक्षण करें

एक बार जब आप निर्माण कर लेते हैं, तो आप उसे चाहते हैं:

#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
PATH="${PATH}:${install_dir}/bin" \
  x86_64-unknown-linux-gnu-gcc \
  -Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
  -Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
  -v \
  -o test_glibc.out \
  test_glibc.c \
  -pthread \
;
ldd test_glibc.out
./test_glibc.out

सब कुछ सेटअप 1 के रूप में काम करने लगता है, सिवाय इसके कि अब सही रनटाइम ऑब्जेक्ट का उपयोग किया गया था:

COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o

सेटअप 2: विफल कुशल glibc recompilation प्रयास

यह नीचे बताए गए अनुसार क्रोसस्टूल-एनजी के साथ संभव नहीं है।

यदि आप बस फिर से निर्माण करते हैं;

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

तब कस्टम ग्लिबक स्रोत स्थान में आपके बदलावों को ध्यान में रखा जाता है, लेकिन यह खरोंच से सब कुछ बनाता है, जिससे पुनरावृत्ति विकास के लिए यह बेकार हो जाता है।

यदि हम करें तो:

./ct-ng list-steps

यह बिल्ड चरणों का एक अच्छा अवलोकन देता है:

Available build steps, in order:
  - companion_tools_for_build
  - companion_libs_for_build
  - binutils_for_build
  - companion_tools_for_host
  - companion_libs_for_host
  - binutils_for_host
  - cc_core_pass_1
  - kernel_headers
  - libc_start_files
  - cc_core_pass_2
  - libc
  - cc_for_build
  - cc_for_host
  - libc_post_cc
  - companion_libs_for_target
  - binutils_for_target
  - debug
  - test_suite
  - finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.

इसलिए, हम देखते हैं कि कई GCC चरणों के साथ interibined glibc चरण हैं, सबसे विशेष रूप libc_start_filesसे पहले आता है cc_core_pass_2, जो संभवतः एक साथ सबसे महंगा कदम है cc_core_pass_1

केवल एक कदम बनाने के लिए, आपको सबसे पहले "इंटरमीडिएट चरणों को सहेजें" .configको इंटिअल बिल्ड के लिए विकल्प में सेट करना होगा :

  • Paths and misc options
    • Debug crosstool-NG
      • Save intermediate steps

और फिर आप कोशिश कर सकते हैं:

env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`

लेकिन दुर्भाग्य से, +आवश्यक के रूप में उल्लेख किया गया: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

हालाँकि, ध्यान दें कि एक मध्यवर्ती चरण पर पुनरारंभ करने से उस चरण में उस राज्य में स्थापना निर्देशिका रीसेट हो जाती है। यानी, आपके पास एक पुनर्निर्माण लिबेक होगा - लेकिन इस परिवाद के साथ बनाया गया कोई अंतिम संकलक नहीं है (और इसलिए, कोई संकलक लाइब्रेरी जैसे libstdc ++ या तो नहीं)।

और मूल रूप से अभी भी पुनर्निर्माण को बहुत धीमी गति से विकास के लिए संभव बनाता है, और मैं यह नहीं देखता कि क्रॉस्टूल-एनजी को पैच किए बिना इसे कैसे पार किया जाए।

इसके अलावा, libcकदम से शुरू करने से स्रोत पर फिर से प्रतिलिपि नहीं लगती Custom source location, आगे इस पद्धति को अनुपयोगी बना दिया गया।

बोनस: stdlibc ++

एक बोनस यदि आप C ++ मानक पुस्तकालय में रुचि रखते हैं: GCC libstdc ++ C ++ लाइब्रेरी लाइब्रेरी स्रोत को कैसे संपादित करें और फिर से बनाएं?


musl-libcजहां तक ​​सी रनटाइम का संबंध है एक और विकल्प है।
0xC0000022L

0

मेरी राय में, सबसे आसान समाधान (विशेषकर यदि आप नवीनतम ब्लीडिंग एज C / C ++ फीचर्स पर भरोसा नहीं करते हैं, या लेटेस्ट कंपाइलर फीचर्स का उल्लेख नहीं किया गया है), तो यहाँ यह है:

बस उस सिस्टम पर निर्माण करें जिसमें आप सबसे पुराने GLIBC का समर्थन करना चाहते हैं।

यह वास्तव में आजकल चेरोट, या केवीएम / वर्चुअलबॉक्स, या डॉकटर जैसी प्रौद्योगिकियों के साथ करना बहुत आसान है, भले ही आप वास्तव में किसी भी पीसी पर इस तरह के पुराने डिस्ट्रो का उपयोग न करना चाहते हों। विस्तार से, आपके सॉफ़्टवेयर की अधिकतम पोर्टेबल बाइनरी बनाने के लिए मैं इन चरणों का पालन करने की सलाह देता हूं:

  1. बस सैंडबॉक्स / वर्चुअलाइजेशन / ... के अपने जहर को उठाओ, और इसका उपयोग अपने आप को एक आभासी पुराने उबंटू एलटीएस पाने के लिए करें और इसे डिफ़ॉल्ट रूप से इसमें मौजूद gcc / g ++ के साथ संकलित करें। यह आपके GLIBC को उस वातावरण में उपलब्ध स्वचालित रूप से सीमित कर देता है।

  2. फाउंडेशनल लोगों के बाहर बाहरी कामों पर निर्भर होने से बचें: जैसे, आपको गतिशील रूप से ग्राउंड-लेवल सिस्टम सामान जैसे ग्लिबेक, लिबेल्ग, लिबेंक्ब / एक्स 11 / वेलैंडलैंड, लिबासाउंड / लिबस्पल्सीडियो से लिंक करना चाहिए, संभवतः जीटीके / यदि आप इसका उपयोग करते हैं, लेकिन अन्यथा अधिमानतः स्टेटिक रूप से बाहरी रूप से लिंक करें यदि आप कर सकते हैं तो उनके साथ लिबास / जहाज। विशेष रूप से ज्यादातर छवि लोडर, मल्टीमीडिया डिकोडर, आदि जैसे स्वयं-निहित कामों के कारण अन्य डिस्ट्रोस पर कम टूटना हो सकता है (ब्रेक्जिट का कारण हो सकता है जैसे कि केवल एक अलग प्रमुख संस्करण में कहीं मौजूद हो) यदि आप सांख्यिकीय रूप से उन्हें जहाज करते हैं।

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

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