Kurulum 1: adanmış GCC olmadan kendi glibc'nizi derleyin ve kullanın
Sadece sembol versiyonlama hack'leriyle yapmak imkansız göründüğü için, bir adım daha ileri gidelim ve glibc'yi kendimiz derleyelim.
Bu kurulum işe yarayabilir ve tüm GCC araç zincirini yeniden derlemediği için hızlıdır, sadece glibc.
Bu gibi konakçı C çalışma zamanı gibi nesneleri kullanmaktadır Ancak güvenilir değildir crt1.o
, crti.o
ve crtn.o
glibc'nin sağladığı. Bu, şu adreste belirtilmiştir: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Bu nesneler, glibc'nin dayandığı erken kurulum yapar, bu yüzden işler harika bir şekilde çökerse şaşırmam ve müthiş incelikli yollar.
Daha güvenilir bir kurulum için aşağıdaki Kurulum 2'ye bakın.
Glibc'yi derleyin ve yerel olarak yükleyin:
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`
Kurulum 1: yapıyı doğrulayın
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);
}
Aşağıdakilerle derleyin ve çalıştırın 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
Program beklenen çıktıları verir:
gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674
Komut, https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location'dan uyarlandı, ancak --sysroot
şunlarla başarısız oldu:
cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install
bu yüzden kaldırdım.
ldd
çıktı, az önce oluşturduğumuz ldd
ve kitaplıklarının aslında beklendiği gibi kullanıldığını doğrular :
+ 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
Daha önce belirtildiği, ama bunu geçici bir çözüm için nasıl bilmiyorum kadar kötü benim ev sahibi çalışma zamanı nesneler kullanıldığını derleme ayıklama çıkışı gösterileri, örneğin içerdiği:
COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o
Kurulum 1: glibc'yi değiştirin
Şimdi glibc'yi şununla değiştirelim:
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)");
Ardından glibc'yi yeniden derleyin ve yeniden kurun ve programımızı yeniden derleyin ve yeniden çalıştırın:
cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh
ve hacked
beklendiği gibi birkaç kez basıldığını görüyoruz .
Bu ayrıca, ana bilgisayarı değil, derlediğimiz glibc'yi kullandığımızı doğrular.
Ubuntu 18.04'te test edildi.
Kurulum 2: crosstool-NG bozulmamış kurulum
Bu kurulum 1'e alternatif olduğunu ve ben kadar elde ettik en doğru kurgusunda: herşey C çalışma zamanı gibi nesneleri de dahil olmak üzere, gözlemlemek kadarıyla doğru olduğunu crt1.o
, crti.o
ve crtn.o
.
Bu kurulumda, istediğimiz glibc'yi kullanan tam adanmış bir GCC araç zinciri derleyeceğiz.
Bu yöntemin tek dezavantajı, yapımın daha uzun sürmesidir. Ama daha azıyla bir üretim kurulumunu riske atmam.
crosstool-NG , GCC, glibc ve binutils dahil her şeyi bizim için kaynaktan indiren ve derleyen bir dizi .
Evet, GCC inşa sistemi o kadar kötü ki bunun için ayrı bir projeye ihtiyacımız var.
Bu kurulum yalnızca mükemmel değildir çünkü crosstool-NG, ekstra -Wl
bayraklar olmadan çalıştırılabilir dosyaların oluşturulmasını desteklemez. , bu da GCC'yi kendimiz oluşturduğumuz için garip geliyor. Ancak her şey çalışıyor gibi görünüyor, bu yüzden bu sadece bir rahatsızlık.
Crosstool-NG'yi alın ve yapılandırın:
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
Görebildiğim tek zorunlu seçenek, doğru çekirdek başlıklarını kullanmak için ana bilgisayar çekirdek sürümünüzle eşleşmesini sağlamaktır. Ana bilgisayar çekirdek sürümünüzü şu şekilde bulun:
uname -a
bana gösteriyor:
4.15.0-34-generic
böylece menuconfig
yapmam:
bu yüzden seçiyorum:
4.14.71
ilk eşit veya daha eski sürüm olan. Çekirdek geriye dönük olarak uyumlu olduğu için daha eski olması gerekir.
Şimdi şununla inşa edebilirsiniz:
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
ve şimdi derleme için yaklaşık otuz dakika ila iki saat bekleyin.
Kurulum 2: isteğe bağlı yapılandırmalar
.config
Birlikte oluşturduğunu ./ct-ng x86_64-unknown-linux-gnu
vardır:
CT_GLIBC_V_2_27=y
Bunu değiştirmek menuconfig
için şunları yapın:
C-library
Version of glibc
kaydedin .config
ve oluşturmaya devam edin.
En son git den glibc kullanmak örneğin kendi glibc kaynağı kullanmak istiyorsanız Veya, devam böyle :
Paths and misc options
Try features marked as EXPERIMENTAL
: true olarak ayarla
C-library
Source of glibc
Custom location
: Evet de
Custom location
Custom source location
: glibc kaynağınızı içeren bir dizine işaret edin
glibc şu şekilde klonlandı:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
Kurulum 2: test edin
İstediğiniz araç zincirini oluşturduktan sonra, aşağıdakilerle test edin:
#!/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
Artık doğru çalışma zamanı nesnelerinin kullanılması dışında her şey Kurulum 1'deki gibi çalışıyor gibi görünüyor:
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
Kurulum 2: verimli glibc yeniden derleme girişimi başarısız oldu
Crosstool-NG ile aşağıda açıklandığı gibi mümkün görünmemektedir.
Sadece yeniden inşa ederseniz;
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
daha sonra özel glibc kaynak konumunda yaptığınız değişiklikler hesaba katılır, ancak her şeyi sıfırdan oluşturarak onu yinelemeli geliştirme için kullanılamaz hale getirir.
Eğer yaparsak:
./ct-ng list-steps
derleme adımlarına güzel bir genel bakış sunar:
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.
bu nedenle, birçok GCC adımıyla iç içe geçmiş glibc adımları olduğunu görüyoruz, en önemlisi libc_start_files
daha önce gelir cc_core_pass_2
ve bu muhtemelen birlikte en pahalı adımdır cc_core_pass_1
.
Yalnızca bir adım oluşturmak için, ilk derlemede "Ara adımları kaydet" .config
seçeneğini ayarlamanız gerekir :
ve sonra deneyebilirsiniz:
env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`
ancak maalesef +
şu adreste belirtildiği gibi gereklidir: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536
Ancak, ara bir adımda yeniden başlatmanın, kurulum dizinini o adımdaki durumuna sıfırlayacağını unutmayın. Yani, yeniden oluşturulmuş bir libc'ye sahip olacaksınız - ancak bu libc ile derlenmiş son derleyiciniz olmayacak (ve dolayısıyla libstdc ++ gibi derleyici kitaplıkları da yok).
ve temelde, yeniden inşayı geliştirme için mümkün olamayacak kadar yavaşlatıyor ve crosstool-NG'yi yamamadan bunun üstesinden nasıl geleceğimi bilmiyorum.
Dahası, adımdan başlayarak libc
kaynağın üzerine tekrar kopyalanmadı Custom source location
, bu da bu yöntemi kullanılamaz hale getirdi.
Bonus: stdlibc ++
C ++ standart kitaplığıyla da ilgileniyorsanız bir avantaj: GCC libstdc ++ C ++ standart kitaplık kaynağı nasıl düzenlenir ve yeniden oluşturulur?