Pertanyaan ini sudah tua, jawaban lainnya sudah tua. Jawaban "Bahasa Rusia yang Dipekerjakan" sangat bagus dan informatif, tetapi hanya berfungsi jika Anda memiliki kode sumbernya. Jika tidak, alternatif saat itu sangat rumit. Untungnya saat ini kami memiliki solusi sederhana untuk masalah ini (seperti yang dikomentari di salah satu balasannya), menggunakan patchelf. Yang harus Anda lakukan adalah:
$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp
Dan setelah itu, Anda bisa mengeksekusi file Anda:
$ ./myapp
Tidak perlu chroot
atau edit binari secara manual, untungnya. Tapi ingat untuk mencadangkan biner Anda sebelum menambalnya, jika Anda tidak yakin dengan apa yang Anda lakukan, karena ini mengubah file biner Anda. Setelah Anda menambalnya, Anda tidak dapat mengembalikan jalur lama ke interpreter/rpath. Jika tidak berhasil, Anda harus terus menambalnya sampai Anda menemukan jalur yang benar-benar berfungsi... Yah, itu tidak harus menjadi proses trial-and-error. Misalnya, dalam contoh OP, dia membutuhkan GLIBC_2.3
, sehingga Anda dapat dengan mudah menemukan lib mana yang menyediakan versi tersebut menggunakan strings
:
$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3
Secara teori, grep pertama akan kosong karena libc sistem tidak memiliki versi yang dia inginkan, dan yang kedua harus menampilkan GLIBC_2.3 karena memiliki versi myapp
gunakan, jadi kita tahu kita bisa patchelf
biner kami menggunakan jalur itu. Jika Anda mengalami kesalahan segmentasi, baca catatan di bagian akhir.
Saat Anda mencoba menjalankan biner di linux, biner mencoba memuat linker, lalu perpustakaan, dan semuanya harus berada di jalur dan/atau di tempat yang tepat. Jika masalah Anda ada pada linker dan Anda ingin mengetahui jalur mana yang dicari biner Anda, Anda dapat mencari tahu dengan perintah ini:
$ readelf -l myapp | grep interpreter
[Requesting program interpreter: /lib/ld-linux.so.2]
Jika masalah Anda ada pada lib, perintah yang akan memberi Anda lib yang digunakan adalah:
$ readelf -d myapp | grep Shared
$ ldd myapp
Ini akan mencantumkan lib yang dibutuhkan biner Anda, tetapi Anda mungkin sudah mengetahui lib yang bermasalah, karena lib tersebut sudah menghasilkan kesalahan seperti dalam kasus OP.
"patchelf" berfungsi untuk banyak masalah berbeda yang mungkin Anda temui saat mencoba menjalankan program, terkait dengan 2 masalah ini. Misalnya, jika Anda mendapatkan:ELF file OS ABI invalid
, ini dapat diperbaiki dengan menyetel loader baru (kode --set-interpreter
bagian dari perintah) seperti yang saya jelaskan di sini. Contoh lain adalah untuk masalah mendapatkan No such file or directory
ketika Anda menjalankan file yang ada dan dapat dieksekusi, seperti yang dicontohkan di sini. Dalam kasus khusus itu, OP kehilangan tautan ke loader, tetapi mungkin dalam kasus Anda, Anda tidak memiliki akses root dan tidak dapat membuat tautan. Menetapkan juru bahasa baru akan menyelesaikan masalah Anda.
Terima kasih Employed Russian dan Michael Pankov atas wawasan dan solusinya!
Catatan untuk kesalahan segmentasi:Anda mungkin berada dalam kasus di mana myapp
menggunakan beberapa lib, dan sebagian besar baik-baik saja tetapi beberapa tidak; lalu Anda patchelf
ke dir baru, dan Anda mendapatkan kesalahan segmentasi. Saat Anda patchelf
biner Anda, Anda mengubah jalur beberapa lib, meskipun beberapa awalnya berada di jalur yang berbeda. Lihatlah contoh saya di bawah ini:
$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./myapp)
linux-vdso.so.1 => (0x00007fffb167c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)
Perhatikan bahwa sebagian besar lib ada di /lib/x86_64-linux-gnu/
tapi yang bermasalah (libstdc++.so.6
) ada di /usr/lib/x86_64-linux-gnu
. Setelah saya menambal myapp
untuk menunjuk ke /path/to/mylibs
, saya mendapat kesalahan segmentasi. Untuk beberapa alasan, lib tidak sepenuhnya kompatibel dengan biner. Sejak myapp
tidak mengeluh tentang lib asli, saya menyalinnya dari /lib/x86_64-linux-gnu/
ke /path/to/mylibs2
, dan saya juga menyalin libstdc++.so.6
dari /path/to/mylibs
di sana. Lalu saya menambalnya menjadi /path/to/mylibs2
, dan myapp
bekerja sekarang. Jika biner Anda menggunakan lib yang berbeda, dan Anda memiliki versi yang berbeda, mungkin Anda tidak dapat memperbaiki situasi Anda. :( Tapi jika memungkinkan, mencampur libs mungkin caranya. Itu tidak ideal, tapi mungkin itu akan berhasil. Semoga berhasil!
Gunakan LD_PRELOAD:letakkan pustaka Anda di luar direktori man lib dan jalankan:
LD_PRELOAD='mylibc.so anotherlib.so' program
Lihat:artikel Wikipedia
Pertama-tama, ketergantungan terpenting dari setiap program yang terhubung secara dinamis adalah linker. Semua perpustakaan harus cocok dengan versi penaut.
Mari kita ambil contoh sederhana:Saya memiliki sistem ubuntu newset tempat saya menjalankan beberapa program (dalam kasus saya ini adalah kompiler D - ldc2). Saya ingin menjalankannya di CentOS lama, tetapi karena perpustakaan glibc yang lebih lama, itu tidak mungkin. Saya dapat
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
Saya harus menyalin semua dependensi dari ubuntu ke centos. Metode yang tepat adalah sebagai berikut:
Pertama, mari kita periksa semua dependensi:
ldd ldc2-1.5.0-linux-x86_64/bin/ldc2
linux-vdso.so.1 => (0x00007ffebad3f000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)
linux-vdso.so.1 bukan perpustakaan sebenarnya dan kami tidak perlu memedulikannya.
/lib64/ld-linux-x86-64.so.2 adalah penaut, yang digunakan oleh linux untuk menautkan yang dapat dieksekusi dengan semua pustaka dinamis.
File lainnya adalah pustaka nyata dan semuanya bersama dengan tautan harus disalin di suatu tempat di centos.
Mari kita asumsikan semua perpustakaan dan linker ada di direktori "/mylibs".
ld-linux-x86-64.so.2 - seperti yang sudah saya katakan - adalah penghubungnya. Ini bukan perpustakaan dinamis tetapi dapat dieksekusi secara statis. Anda dapat menjalankannya dan melihat bahwa ia bahkan memiliki beberapa parameter, misalnya --library-path (saya akan kembali ke situ).
Di linux, program yang tertaut secara dinamis dapat diberi makan siang hanya dengan namanya, misalnya
/bin/ldc2
Linux memuat program semacam itu ke dalam RAM, dan memeriksa linker mana yang disetel untuk itu. Biasanya, pada sistem 64-bit, itu adalah /lib64/ld-linux-x86-64.so.2 (dalam sistem file Anda itu adalah tautan simbolis ke executable nyata). Kemudian linux menjalankan tautan dan memuat pustaka dinamis.
Anda juga dapat mengubah ini sedikit dan melakukan trik berikut:
/mylibs/ld-linux-x86-64.so.2 /bin/ldc2
Ini adalah metode untuk memaksa linux menggunakan linker tertentu.
Dan sekarang kita dapat kembali ke parameter yang disebutkan sebelumnya --library-path
/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2
Ini akan menjalankan ldc2 dan memuat pustaka dinamis dari /mylibs.
Ini adalah metode untuk memanggil yang dapat dieksekusi dengan pustaka yang dipilih (bukan default sistem).
Sangat mungkin untuk memiliki beberapa versi glibc pada sistem yang sama (kami melakukannya setiap hari).
Namun, Anda perlu tahu bahwa glibc terdiri dari banyak bagian (200+ shared library) yang semuanya harus cocok. Salah satunya adalah ld-linux.so.2, dan itu harus cocok dengan libc.so.6, atau Anda akan melihat kesalahan yang Anda lihat.
Jalur absolut ke ld-linux.so.2 di-hard-code menjadi executable pada waktu tautan, dan tidak dapat dengan mudah diubah setelah tautan selesai (Pembaruan:dapat dilakukan dengan patchelf; lihat jawaban ini di bawah).
Untuk membangun executable yang akan bekerja dengan glibc baru, lakukan ini:
g++ main.o -o myapp ... \
-Wl,--rpath=/path/to/newglibc \
-Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2
-rpath
opsi linker akan membuat runtime loader mencari pustaka di /path/to/newglibc
(jadi Anda tidak perlu menyetel LD_LIBRARY_PATH
sebelum menjalankannya), dan -dynamic-linker
opsi akan "memanggang" jalur untuk mengoreksi ld-linux.so.2
ke dalam aplikasi.
Jika Anda tidak dapat menautkan ulang myapp
aplikasi (misalnya karena ini adalah biner pihak ketiga), tidak semuanya hilang, tetapi semakin rumit. Salah satu solusinya adalah menyetel chroot
yang tepat lingkungan untuk itu. Kemungkinan lain adalah menggunakan rtldi dan editor biner. Perbarui:atau Anda dapat menggunakan patchelf.