GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana saya bisa menautkan ke versi glibc tertentu?

Anda benar bahwa glibc menggunakan versi simbol. Jika Anda penasaran, implementasi pembuatan versi simbol yang diperkenalkan di glibc 2.1 dijelaskan di sini dan merupakan perpanjangan dari skema pembuatan versi simbol Sun yang dijelaskan di sini.

Salah satu opsinya adalah menautkan biner Anda secara statis. Ini mungkin opsi termudah.

Anda juga dapat membangun biner Anda di lingkungan build chroot, atau menggunakan glibc-baru => glibc-lama lintas-kompiler.

Menurut entri blog http://www.trevorpounds.com Menautkan ke Simbol Versi Lama (glibc) , Anda dapat memaksa simbol apa pun untuk ditautkan dengan simbol lama asalkan valid dengan menggunakan .symver yang sama pseudo-op yang digunakan untuk mendefinisikan simbol berversi di tempat pertama. Contoh berikut dikutip dari entri blog.

Contoh berikut memanfaatkan realpath glibc, tetapi memastikannya tertaut dengan versi 2.2.5 yang lebih lama.

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

__asm__(".symver realpath,[email protected]_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;
}

Penyiapan 1:kompilasi glibc Anda sendiri tanpa GCC khusus dan gunakanlah

Karena tampaknya tidak mungkin dilakukan hanya dengan peretasan versi simbol, mari melangkah lebih jauh dan kompilasi sendiri glibc.

Penyiapan ini mungkin berhasil dan cepat karena tidak mengkompilasi ulang keseluruhan rantai alat GCC, hanya glibc.

Tapi itu tidak dapat diandalkan karena menggunakan objek runtime host C seperti crt1.o , crti.o , dan crtn.o disediakan oleh glibc. Ini disebutkan di:https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Objek-objek itu melakukan pengaturan awal yang diandalkan glibc, jadi saya tidak akan terkejut jika semuanya macet dengan luar biasa dan cara yang sangat halus.

Untuk penyiapan yang lebih andal, lihat Penyiapan 2 di bawah.

Bangun glibc dan instal secara lokal:

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`

Penyiapan 1:verifikasi build

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.
     * https://stackoverflow.com/questions/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);
}

Kompilasi dan jalankan dengan 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 menampilkan yang diharapkan:

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

Perintah diadaptasi dari https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location tetapi --sysroot membuatnya gagal dengan:

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

jadi saya menghapusnya.

ldd output mengonfirmasi bahwa ldd dan pustaka yang baru saja kita buat benar-benar digunakan seperti yang diharapkan:

+ 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 output debug kompilasi menunjukkan bahwa objek runtime host saya digunakan, yang buruk seperti yang disebutkan sebelumnya, tetapi saya tidak tahu cara mengatasinya, mis. itu berisi:

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

Penyiapan 1:ubah glibc

Sekarang mari kita ubah glibc dengan:

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)");

Kemudian kompilasi ulang dan instal ulang glibc, lalu kompilasi ulang dan jalankan kembali program kami:

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

dan kita melihat hacked dicetak beberapa kali seperti yang diharapkan.

Ini semakin menegaskan bahwa kami benar-benar menggunakan glibc yang kami kompilasi dan bukan host.

Diuji pada Ubuntu 18.04.

Penyiapan 2:penyiapan murni crosstool-NG

Ini adalah alternatif untuk penyiapan 1, dan ini adalah penyiapan paling benar yang telah saya capai sejauh ini:semuanya sudah benar sejauh yang dapat saya amati, termasuk objek runtime C seperti crt1.o , crti.o , dan crtn.o .

Dalam penyiapan ini, kita akan mengompilasi toolchain GCC khusus lengkap yang menggunakan glibc yang kita inginkan.

Satu-satunya downside ke metode ini adalah pembangunan akan memakan waktu lebih lama. Tapi saya tidak akan mengambil risiko penyiapan produksi dengan sesuatu yang kurang dari itu.

crosstool-NG adalah kumpulan skrip yang mengunduh dan mengompilasi semuanya dari sumber untuk kami, termasuk GCC, glibc, dan binutils.

Ya, sistem build GCC sangat buruk sehingga kami memerlukan project terpisah untuk itu.

Penyiapan ini tidak sempurna karena crosstool-NG tidak mendukung pembangunan executable tanpa tambahan -Wl flags, yang terasa aneh karena kami membuat GCC sendiri. Namun semuanya tampak berfungsi, jadi ini hanyalah ketidaknyamanan.

Dapatkan crosstool-NG dan konfigurasikan:

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

Satu-satunya opsi wajib yang dapat saya lihat adalah membuatnya cocok dengan versi kernel host Anda untuk menggunakan header kernel yang benar. Temukan versi kernel host Anda dengan:

uname -a

yang menunjukkan kepada saya:

4.15.0-34-generic

jadi di menuconfig Saya lakukan:

  • Operating System
    • Version of linux

jadi saya pilih:

4.14.71

yang merupakan versi pertama yang sama atau lebih tua. Itu harus lebih tua karena kernel kompatibel ke belakang.

Sekarang Anda dapat membangun dengan:

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

dan sekarang tunggu sekitar tiga puluh menit hingga dua jam untuk kompilasi.

Penyiapan 2:konfigurasi opsional

.config yang kami hasilkan dengan ./ct-ng x86_64-unknown-linux-gnu memiliki:

CT_GLIBC_V_2_27=y

Untuk mengubahnya, di menuconfig lakukan:

  • C-library
  • Version of glibc

simpan .config , dan lanjutkan dengan pembuatan.

Atau, jika Anda ingin menggunakan sumber glibc Anda sendiri, mis. untuk menggunakan glibc dari git terbaru, lanjutkan seperti ini:

  • Paths and misc options
    • Try features marked as EXPERIMENTAL :disetel ke true
  • C-library
    • Source of glibc
      • Custom location :katakan ya
      • Custom location
        • Custom source location :arahkan ke direktori yang berisi sumber glibc Anda

di mana glibc dikloning sebagai:

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

Penyiapan 2:uji coba

Setelah Anda membuat rantai alat yang Anda inginkan, ujilah dengan:

#!/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

Segalanya tampak berfungsi seperti pada Penyiapan 1, kecuali bahwa sekarang objek runtime yang benar telah digunakan:

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

Penyiapan 2:upaya kompilasi ulang glibc yang gagal

Sepertinya tidak mungkin dengan crosstool-NG, seperti yang dijelaskan di bawah.

Jika Anda baru saja membangun kembali;

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

maka perubahan Anda pada lokasi sumber glibc khusus akan diperhitungkan, tetapi itu membangun semuanya dari awal, sehingga tidak dapat digunakan untuk pengembangan berulang.

Jika kita melakukannya:

./ct-ng list-steps

ini memberikan ikhtisar yang bagus tentang langkah-langkah pembuatan:

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.

oleh karena itu, kami melihat bahwa ada langkah-langkah glibc yang terkait dengan beberapa langkah GCC, terutama libc_start_files datang sebelum cc_core_pass_2 , yang mungkin merupakan langkah termahal bersama dengan cc_core_pass_1 .

Untuk membuat satu langkah saja, Anda harus menyetel terlebih dahulu "Simpan langkah perantara" di .config opsi untuk build awal:

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

lalu Anda dapat mencoba:

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

tapi sayangnya, + diperlukan sebagaimana disebutkan di:https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

Namun perlu dicatat bahwa memulai ulang pada langkah menengah akan menyetel ulang direktori instalasi ke status yang dimilikinya selama langkah tersebut. Yaitu, Anda akan memiliki libc yang dibangun kembali - tetapi tidak ada kompiler final yang dibuat dengan libc ini (dan karenanya, tidak ada pustaka kompiler seperti libstdc++ juga).

dan pada dasarnya masih membuat pembangunan kembali terlalu lambat untuk dapat dikembangkan, dan saya tidak melihat cara mengatasinya tanpa menambal crosstool-NG.

Selanjutnya mulai dari libc step sepertinya tidak menyalin sumber lagi dari Custom source location , selanjutnya membuat metode ini tidak dapat digunakan.

Bonus:stdlibc++

Bonus jika Anda juga tertarik dengan pustaka standar C++:Bagaimana cara mengedit dan membuat ulang sumber pustaka standar GCC libstdc++ C++?


Linux
  1. Bagaimana saya bisa menghitung alamat IP pada Rentang Subnet CDIR Tertentu?

  2. Bagaimana saya bisa mencopot atau memutakhirkan versi node.js lama saya?

  3. Bagaimana saya bisa menghapus aturan khusus dari iptables?

  1. Bagaimana saya bisa menautkan ke versi lama dari perpustakaan bersama

  2. Bagaimana saya bisa mengubah versi php-cli di Ubuntu 14.04?

  3. Bagaimana cara mengetahui versi Linux yang saya gunakan?

  1. Cara Beralih Versi PHP

  2. Bagaimana cara menggunakan yum untuk menginstal versi Paket tertentu?

  3. Bagaimana Cara Mendeteksi Bash>=4.0?