Kurulum 1: Özel GCC olmadan kendi glibc'nizi derleyin ve kullanın
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 konuda şu adresten bahsedilir: 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 yapıyor, bu yüzden işler harika bir şekilde çöktüyse şaşırmam ve müthiş ince yollar.
Daha güvenilir bir kurulum için aşağıdaki Kurulum 2'ye bakın.
Glibc oluşturun 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: Derlemeyi 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);
}
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ıyı 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 adresinden uyarlandı ancak --sysroot
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
output, yeni oluşturduğumuz ldd
ve kütüphanelerin gerçekte 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 aşağıdakilerle 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)");
Sonra glibc'i yeniden derleyin ve yeniden kurun ve programımızı yeniden derleyip 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ış kurulumu
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 bir özel GCC araç zinciri derleyeceğiz.
Bu yöntemin tek dezavantajı, yapının daha uzun sürecek olmasıdır. Ama daha az bir şeyle bir üretim kurulumu riske atmam.
crosstool-NG , GCC, glibc ve binutils dahil olmak üzere her şeyi kaynağından indirip derleyen bir dizi komut dosyasıdır .
Evet, GCC inşa sistemi o kadar kötü ki bunun için ayrı bir projeye ihtiyacımız var.
Bu kurulum sadece mükemmel değildir, çünkü crosstool-NG,-Wl
GCC'nin kendisini oluşturduğumuz için garip hisseden ekstra bayraklar olmadan yürütülebilir dosyalar oluşturmayı desteklemez . Ama her şey işe yarıyor gibi görünüyor, bu yüzden bu sadece bir rahatsızlık.
Crosstool-NG'yi alın, yapılandırın ve oluşturun:
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
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
Yapı yaklaşık otuz dakika ila iki saat sürer.
Görebildiğim tek zorunlu yapılandırma seçeneği, doğru çekirdek başlıklarını kullanmak için ana makine çekirdek sürümünüzle eşleşmesini sağlamaktır. Şununla ana makine çekirdek sürümünü bulun:
uname -a
bu bana gösteriyor:
4.15.0-34-generic
böylece menuconfig
yapmam:
bu yüzden seçiyorum:
4.14.71
ilk eşit veya eski sürüm. Çekirdek geriye dönük olarak uyumlu olduğundan daha eski olmalıdır.
Kurulum 2: İsteğe bağlı yapılandırmalar
Birlikte .config
ürettiğimiz ./ct-ng x86_64-unknown-linux-gnu
:
CT_GLIBC_V_2_27=y
Bunu değiştirmek menuconfig
için şunu yapın:
C-library
Version of glibc
kaydedin .config
ve derlemeye 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 ayarlandı
C-library
Source of glibc
Custom location
: Evet de
Custom location
Custom source location
: glibc kaynağınızı içeren bir dizinin üzerine gelin
burada 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:
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: Başarısız verimli glibc yeniden derleme girişimi
Aşağıda açıklandığı gibi crosstool-NG ile mümkün görünmemektedir.
Sadece yeniden inşa ederseniz;
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
özel glibc kaynak konumundaki değişiklikleriniz dikkate alınır, ancak her şeyi sıfırdan oluşturur ve 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, GCC adımlarıyla iç içe geçmiş, en önemlisi libc_start_files
daha önce gelen glibc adımlarının olduğunu görüyoruz cc_core_pass_2
, bu da muhtemelen en pahalı adımdır cc_core_pass_1
.
Yalnızca bir adım .config
oluşturmak için ilk olarak intial derlemede "Ara adımları kaydet" seçeneğini ayarlamanız gerekir :
ve sonra deneyebilirsiniz:
env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`
ancak maalesef +
şu adresten belirtildiği gibi gereklidir: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536
Ancak, bir ara adımda yeniden başlatmanın kurulum dizinini bu adım sırasındaki durumuna sıfırladığını unutmayın. Yani, yeniden oluşturulmuş bir libc'ye sahip olacaksınız - ancak bu libc ile inşa edilmiş son bir derleyici (ve dolayısıyla libstdc ++ gibi derleyici kütüphaneleri yok).
ve temel olarak, yeniden inşayı geliştirme için mümkün olmayacak kadar yavaş hale getiriyor ve crosstool-NG'yi yamalamadan bunun üstesinden nasıl geleceğini görmüyorum.
Dahası, adımdan başlayarak libc
kaynağın üzerinden tekrar kopyalanmadı Custom source location
ve bu yöntemi daha fazla kullanılamaz hale getirdi.
Bonus: stdlibc ++
C ++ standart kitaplığıyla da ilgileniyorsanız bir bonus: GCC libstdc ++ C ++ standart kitaplık kaynağı nasıl düzenlenir ve yeniden oluşturulur?