Tôi có thể thay đổi 'rpath' trong một tệp nhị phân đã được biên dịch không?


92

Tôi có một tệp thực thi cũ được lên lịch cho đống phế liệu, nhưng nó vẫn chưa ở đó. Nó dựa trên một số lib đã bị xóa khỏi môi trường của tôi, nhưng tôi có một số libs sơ khai ở một số nơi mà nó hoạt động tốt. Tôi muốn trỏ tệp thực thi này đến các lib sơ khai này. Có, tôi có thể đặt LD_LIBRARY_PATH, nhưng tệp thực thi này được gọi từ nhiều tập lệnh và nhiều người dùng và tôi muốn sửa nó ở một chỗ.

Tôi không có nguồn cho việc này và sẽ rất khó để lấy nó. Tôi đang suy nghĩ - tôi có thể chỉnh sửa tệp này bằng cách sử dụng trình chỉnh sửa nhận biết ELF và thêm một PATH đơn giản vào rpath để nó đạt được các lib mới không? Điều này có thể thực hiện được không, hay một khi bạn tạo một bản nhị phân ELF, bạn cố định mọi thứ vào các vị trí và chúng không thể di chuyển được?


3
Gói nó vào một shellcript đặt LD_LIBRARY_PATH và gọi nhị phân. Đặt tập lệnh shell vào một nơi nằm trong PATH của người gọi.
wildplasser

LD_LIBRARY_PATH được kế thừa bởi các quy trình con. Bạn có thể không muốn điều đó.
Will

1
@will yeah và tôi đã nói rằng tôi không muốn làm điều đó. :)
Rich Homolka

Câu trả lời:


78

Có một công cụ được gọi là chrpathcó thể làm điều này - nó có thể có sẵn trong các gói của phân phối của bạn.


9
Chỉ cần một lưu ý cho người dùng mac, install_name_toolcó thể làm điều này với -rpathcờ
Kevin Tonon

10
Nếu bạn nhận được lỗi: <binary>: no rpath or runpath tag found., bạn không thể sử dụng chrpathđể thay thế nó, nhưng bạn có thể sử dụng patchelftrong trường hợp này:patchelf --set-rpath /path/to/libaries <binary>
phyatt

Tôi thích chrpath hơn nếu có thể vì nó phổ biến hơn, patchelf có một số lỗi lâu đời làm tăng đáng kể kích thước của các thư viện / tệp thực thi của bạn.
taranaki

157

Có một công cụ phổ quát hơn chrpathđược gọi là patchelf. Ban đầu nó được tạo ra để sử dụng trong việc tạo các gói cho Nix và NixOS (hệ thống đóng gói và bản phân phối GNU / Linux).

Trong trường hợp không có rpath trong tệp nhị phân (ở đây được gọi là rdsamp), chrpathkhông thành công:

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

Mặt khác,

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

thành công tốt.


9
Đặc biệt, patchelfcó thể thêm một rpath vào một tệp nhị phân chưa chứa rpath - nơi chrpathdường như chỉ có thể sửa đổi một mục đã có sẵn.
maxschlepzig

4
Như một lưu ý chung, cần hiểu sự phân biệt tinh vi giữa rpathrunpath. Về cơ bản, một cái có thể ghi đè LD_LIBRARY_PATHvà cái kia không thể. Để biết chi tiết, hãy xem blog.tremily.us/posts/rpath
Stuart Berg,

6
Điều khó chịu là cả hai chrpathpatchelfđều cẩu thả với thuật ngữ của họ. Ví dụ: patchelflệnh hiển thị ở trên sẽ thay đổi runpathnhưng không thay đổi rpathtrừ khi bạn cũng cung cấp --force-rpathtùy chọn.
Stuart Berg

10
@superbatfish Có, nhưng sự khác biệt thường không quan trọng. Mục nhập này từ CHANGELOG patchelfgiải thích nó: " --set-rpath, --shrink-rpath--print-rpathbây giờ thích DT_RUNPATHhơn DT_RPATH, đã lỗi thời. Khi cập nhật, nếu cả hai đều có mặt, cả hai đều được cập nhật. Nếu chỉ có DT_RPATH, nó sẽ được chuyển đổi thành DT_RUNPATHtrừ khi --force-rpathđược chỉ định. Nếu không có , a DT_RUNPATHđược thêm vào trừ khi --force-rpathđược chỉ định, trong trường hợp đó a DT_RPATHđược thêm vào. " Tên của tùy chọn có thể được giữ nguyên vì lý do tương thích.
user7610,

2
Cho đến nay câu trả lời tốt nhất, đây phải là câu trả lời được chấp nhận thay thế!
Kenneth Hoste

12

Giống như @ user7610 đã nói, con đường đúng đắn để đi là patchelfcông cụ.

Nhưng, tôi cảm thấy rằng tôi có thể đưa ra một câu trả lời toàn diện hơn, bao gồm tất cả các lệnh người ta cần để thực hiện chính xác điều đó.

Để có một bài báo toàn diện về chủ đề này, hãy nhấp vào đây

Trước hết, nhiều nhà phát triển nói về RPATH, nhưng họ thực sự có ý nghĩa RUNPATH. Đây là hai phần động tùy chọn khác nhau và trình tải xử lý chúng rất khác nhau. Bạn có thể đọc thêm về sự khác biệt giữa chúng trong liên kết mà tôi đã đề cập trước đây.

Hiện tại, chỉ cần nhớ:

  • Nếu RUNPATHđược đặt, RPATHsẽ bị bỏ qua
  • RPATH không được dùng nữa và nên tránh
  • RUNPATH được ưa thích vì nó có thể bị ghi đè bởi LD_LIBRARY_PATH

Xem R [UN] PATH hiện tại

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

Xóa R [UN] PATH

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

Ghi chú:

  • Loại bỏ cả hai RPATHRUNPATH

Thêm giá trị vào R [UN] PATH

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

Ghi chú:

  • <desired-path> là danh sách thư mục được phân tách bằng dấu phẩy, ví dụ: /my/libs:/my/other/libs
  • Nếu bạn chỉ định --force-rpath, hãy đặt RPATH, nếu không thì đặtRUNPATH

1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsbộ DT_RUNPATH, và đó là một trong hầu hết mọi người nên sử dụng. RUNPATHcó thể bị ghi đè bởi LD_LIBRARY_PATH, vì vậy mọi người không nên sử dụng --force-rpath.
jww

@jww Tôi thấy rằng tôi đã không thêm nhận xét về việc ngừng sử dụng RPATH, vì vậy tôi đã thêm một nhận xét ngay bây giờ. Cảm ơn!
Daniel Trugman

Lưu ý rằng ví dụ <desired-path>sử dụng dấu hai chấm; nó phải là một dấu phẩy (nghĩa là:/my/libs,/my/other/libs :).
Alan De Smet

@AlanDeSmet, tôi không biết về dấu phẩy, nhưng dấu hai chấm phù hợp với tôi.
Daniel Trugman

0

Điều này phù hợp với tôi, thay thế XORIGIN bằng $ ORIGIN.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.