सेटअप 1: समर्पित जीसीसी के बिना अपने स्वयं के ग्लिब को संकलित करें और इसका उपयोग करें
चूंकि यह केवल प्रतीक संस्करण हैकिंग के साथ करना असंभव लगता है, आइए एक कदम आगे बढ़ें और खुद को glibc संकलित करें।
यह सेटअप काम कर सकता है और जल्दी है क्योंकि यह पूरे जीसीसी टूलकिन को फिर से नहीं करता है, बस ग्लिबक।
लेकिन यह विश्वसनीय के रूप में यह का उपयोग करता है मेजबान सी क्रम इस तरह की वस्तुओं के रूप में नहीं है crt1.o
, crti.o
और crtn.o
glibc द्वारा प्रदान की। यह उल्लेख किया गया है: 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
मैं करता हूँ:
इसलिए मैं चयन करता हूं:
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
को इंटिअल बिल्ड के लिए विकल्प में सेट करना होगा :
और फिर आप कोशिश कर सकते हैं:
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 ++ लाइब्रेरी लाइब्रेरी स्रोत को कैसे संपादित करें और फिर से बनाएं?