Dapatkah saya mengubah 'rpath' dalam biner yang sudah dikompilasi?

93

Saya memiliki executable lama yang dijadwalkan untuk tumpukan memo, tetapi belum ada. Ini bergantung pada beberapa libs yang telah dihapus dari lingkungan saya, tetapi saya memiliki beberapa lib bertopik di suatu tempat yang berfungsi dengan baik. Saya ingin mengarahkan ini dapat dieksekusi ke perpustakaan rintisan ini. Ya, saya dapat menyetel LD_LIBRARY_PATH, tetapi file yang dapat dieksekusi ini dipanggil dari banyak skrip, dan banyak pengguna, dan saya ingin memperbaikinya di satu tempat.

Saya tidak punya sumber untuk ini, dan akan sulit mendapatkannya. Saya berpikir - dapatkah saya mengedit file ini, menggunakan editor yang sadar ELF, dan menambahkan PATH sederhana ke rpath agar dapat mencapai libs baru? Apakah ini mungkin, atau setelah Anda membuat biner ELF, Anda memperbaiki berbagai hal ke lokasi dan tidak dapat dipindahkan?

Homolka kaya
sumber
3
Bungkus ke dalam shellscript yang menetapkan LD_LIBRARY_PATH dan memanggil biner. Letakkan skrip shell di tempat yang ada di PATH pemanggil.
wildplasser
LD_LIBRARY_PATH diwarisi oleh proses anak. Anda mungkin tidak menginginkan itu.
Akankah
1
@ akan ya itu dan saya sudah mengatakan saya tidak ingin melakukan itu. :)
Rich Homolka

Jawaban:

79

Ada sebuah alat bernama chrpathyang dapat melakukan ini - itu mungkin tersedia di paket distribusi Anda.

TomH
sumber
9
Sekadar catatan untuk pengguna mac, install_name_tooldapat melakukan ini dengan -rpathbendera
Kevin Tonon
10
Jika Anda mendapatkan kesalahan <binary>: no rpath or runpath tag found.chrpathpatchelfpatchelf --set-rpath /path/to/libaries <binary>
:,
Saya lebih suka chrpath jika memungkinkan karena, meskipun lebih universal, patchelf memiliki beberapa bug lama yang secara dramatis memperbesar ukuran libraries / executable Anda.
taranaki
@taranaki: Versi patchelf mana yang kamu bicarakan?
hagello
1
chrpath memiliki batasan yang parah: ia hanya dapat mengganti RPATH dengan salah satu panjang yang sama atau lebih pendek (halaman manual rpath versi 0.16)
hagello
162

Ada alat yang lebih universal daripada yang chrpathdisebut patchelf. Awalnya dibuat untuk digunakan dalam pembuatan paket untuk Nix dan NixOS (sistem pengemasan dan distribusi GNU / Linux).

Jika tidak ada rpath dalam biner (di sini disebut rdsamp), chrpathgagal:

chrpath -r '$ORIGIN/../lib64' rdsamp 
rdsamp: no rpath or runpath tag found.

Di samping itu,

patchelf --set-rpath '$ORIGIN/../lib64' rdsamp

berhasil dengan baik.

pengguna7610
sumber
10
Terutama, patchelfdapat menambahkan rpath ke biner yang tidak berisi rpath, namun - di mana chrpathhanya tampak dapat memodifikasi entri yang sudah ada.
maxschlepzig
4
Sebagai catatan umum, ada baiknya memahami perbedaan halus antara rpathdan runpath. Pada dasarnya, yang satu bisa menimpa LD_LIBRARY_PATHdan yang lainnya tidak bisa. Untuk detailnya, lihat blog.tremily.us/posts/rpath
Stuart Berg
6
Hal yang mengganggu adalah bahwa kedua chrpathdan patchelfceroboh dengan terminologi mereka. Misalnya, patchelfperintah yang ditunjukkan di atas akan berubah runpathtetapi tidak rpathkecuali Anda juga memberikan --force-rpathopsi.
Stuart Berg
10
@superbatfish Ya, tetapi perbedaannya biasanya tidak masalah. Entri ini dari CHANGELOG dari patchelfmenjelaskannya: " --set-rpath, --shrink-rpathdan --print-rpathsekarang lebih memilih DT_RUNPATHdaripada DT_RPATH, yang sudah usang. Saat memperbarui, jika keduanya ada, keduanya diperbarui. Jika hanya DT_RPATH ada, itu akan diubah ke DT_RUNPATHkecuali --force-rpathditentukan. Jika tidak ada , a DT_RUNPATHditambahkan kecuali --force-rpathditentukan, dalam hal ini a DT_RPATHditambahkan. " Nama opsi mungkin tidak diubah karena alasan kompatibilitas.
pengguna7610
2
Sejauh ini jawaban terbaik, ini seharusnya menjadi jawaban yang diterima!
Kenneth Hoste
13

Seperti yang dikatakan @ user7610, cara yang tepat adalah menggunakan patchelfalat.

Tetapi, saya merasa bahwa saya dapat memberikan jawaban yang lebih komprehensif, mencakup semua perintah yang harus dilakukan oleh seseorang.

Untuk artikel komprehensif tentang subjek, klik di sini

Pertama-tama, banyak pengembang membicarakannya RPATH, tetapi sebenarnya mereka bermaksud jahat RUNPATH. Ini adalah dua bagian dinamis opsional yang berbeda, dan loader menanganinya dengan sangat berbeda. Anda dapat membaca lebih lanjut tentang perbedaan di antara mereka di tautan yang saya sebutkan sebelumnya.

Untuk saat ini, ingat saja:

  • Jika RUNPATHdisetel, RPATHdiabaikan
  • RPATH sudah usang dan harus dihindari
  • RUNPATH lebih disukai karena dapat diganti oleh LD_LIBRARY_PATH

Lihat R [UN] PATH saat ini

readelf -d <path-to-elf> | egrep "RPATH|RUNPATH"

Kosongkan R [UN] PATH

patchelf --remove-rpath <path-to-elf>

Catatan:

  • Menghapus keduanya RPATHdanRUNPATH

Tambahkan nilai ke R [UN] PATH

patchelf [--force-rpath] --set-rpath "<desired-rpath>" <path-to-elf>

Catatan:

  • <desired-path> adalah daftar direktori yang dipisahkan koma, misalnya: /my/libs:/my/other/libs
  • Jika Anda menentukan --force-rpath, menyetel RPATH, sebaliknya menyetelRUNPATH
Daniel Trugman
sumber
1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsset DT_RUNPATH, dan itulah yang harus digunakan kebanyakan orang. RUNPATHdapat diganti oleh LD_LIBRARY_PATH, jadi orang tidak boleh menggunakan --force-rpath.
jww
@jww Saya melihat bahwa saya tidak menambahkan komentar tentang penghentian RPATH, jadi saya baru saja menambahkan satu. Terima kasih!
Daniel Trugman
Perhatikan bahwa contoh <desired-path>menggunakan titik dua; itu harus berupa koma (yaitu:) /my/libs,/my/other/libs.
Alan De Smet
@AlanDeSmet, saya tidak tahu tentang koma, tetapi titik dua berfungsi untuk saya.
Daniel Trugman
RPATH mungkin tidak berlaku lagi, tetapi menggunakan RUNPATH dapat menyebabkan kasus sudut yang "tidak terduga". Lihat, misalnya, qt.io/blog/2011/10/28/rpath-and-runpath .
Merampok
0

Ini berhasil untuk saya, mengganti XORIGIN dengan $ ORIGIN.

chrpath -r '\$\ORIGIN/../lib64' httpd

vikram kedlaya
sumber