ฉันสามารถเปลี่ยน 'rpath' ในไบนารีที่คอมไพล์แล้วได้หรือไม่?


96

ฉันมีไฟล์ปฏิบัติการเก่าที่กำหนดไว้สำหรับกองเศษซาก แต่ยังไม่มี มันขึ้นอยู่กับ libs บางตัวที่ถูกลบออกจากสภาพแวดล้อมของฉัน แต่ฉันมี Stub libs บางที่ที่มันใช้งานได้ดี Id ต้องการชี้ไฟล์ปฏิบัติการนี้ไปยัง Stub libs เหล่านี้ ใช่ฉันสามารถตั้งค่า LD_LIBRARY_PATH ได้ แต่ไฟล์ปฏิบัติการนี้ถูกเรียกใช้จากหลายสคริปต์และผู้ใช้จำนวนมากและฉันต้องการแก้ไขในจุดเดียว

ฉันไม่มีแหล่งข้อมูลสำหรับสิ่งนี้และคงยากที่จะได้รับมัน ฉันคิดว่า - ฉันสามารถแก้ไขไฟล์นี้โดยใช้โปรแกรมแก้ไข ELF Awareness และเพิ่ม PATH แบบธรรมดาให้กับ rpath เพื่อให้มันเข้าสู่ libs ใหม่ได้หรือไม่ เป็นไปได้หรือไม่หรือเมื่อคุณสร้างไบนารี ELF คุณแก้ไขสิ่งต่าง ๆ ในสถานที่และไม่สามารถเคลื่อนย้ายได้?


3
รวมไว้ในเชลล์สคริปต์ที่ตั้งค่า LD_LIBRARY_PATH และเรียกไบนารี วางเชลล์สคริปต์ในตำแหน่งที่อยู่ในเส้นทางของผู้โทร
wildplasser

LD_LIBRARY_PATH สืบทอดโดยกระบวนการย่อย คุณอาจไม่ต้องการสิ่งนั้น
จะ

1
@ ใช่แล้วและฉันก็บอกไปแล้วว่าฉันไม่ต้องการทำอย่างนั้น :)
Rich Homolka

คำตอบ:


80

มีเครื่องมือที่เรียกว่าchrpathสามารถทำได้ซึ่งอาจมีอยู่ในแพ็คเกจการแจกจ่ายของคุณ


9
หมายเหตุสำหรับผู้ใช้ mac install_name_toolสามารถทำได้โดยใช้-rpathธง
Kevin Tonon

10
หากคุณได้รับข้อผิดพลาด: <binary>: no rpath or runpath tag found.คุณไม่สามารถใช้chrpathเพื่อแทนที่ได้ แต่คุณสามารถใช้patchelfในกรณีนี้:patchelf --set-rpath /path/to/libaries <binary>
phyatt

ฉันชอบ chrpath ถ้าเป็นไปได้ในขณะที่มันเป็นสากลมากกว่า แต่ patchelf ก็มีข้อผิดพลาดที่ยาวนานซึ่งทำให้ขนาดของไลบรารี / ไฟล์ปฏิบัติการของคุณสูงขึ้นอย่างมาก
taranaki

@taranaki: คุณกำลังพูดถึง patchelf รุ่นไหน?
hagello

1
chrpathมีข้อ จำกัด ที่รุนแรง: สามารถแทนที่ RPATH ได้ด้วยความยาวเท่ากันหรือสั้นกว่าเท่านั้น (หน้าคนของ rpath เวอร์ชัน 0.16)
hagello

165

มีเครื่องมือสากลมากขึ้นกว่าที่เป็นที่เรียกว่าchrpath patchelfเดิมถูกสร้างขึ้นเพื่อใช้ในการสร้างแพ็คเกจสำหรับ Nix และ NixOS (ระบบบรรจุภัณฑ์และการแจกจ่าย GNU / Linux)

ในกรณีที่ไม่มี rpath ในไบนารี (ที่นี่เรียกว่า rdsamp) chrpathล้มเหลว:

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

ในทางกลับกัน,

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

ประสบความสำเร็จได้ดี


10
โดยเฉพาะอย่างยิ่งpatchelfสามารถเพิ่ม rpath ให้กับไบนารีที่ไม่มี rpath chrpathแต่ดูเหมือนว่าจะสามารถแก้ไขรายการที่มีอยู่แล้วได้เท่านั้น
maxschlepzig

5
ขณะที่ทราบโดยทั่วไปจะมีค่าการทำความเข้าใจความแตกต่างระหว่างที่ลึกซึ้งและrpath runpathโดยทั่วไปเราสามารถลบล้างได้LD_LIBRARY_PATHและอีกอันไม่สามารถทำได้ ดูรายละเอียดได้ที่blog.tremily.us/posts/rpath
Stuart Berg

6
สิ่งที่น่ารำคาญคือทั้งสองchrpathและpatchelfเลอะเทอะกับคำศัพท์ของพวกเขา ตัวอย่างเช่นpatchelfคำสั่งที่แสดงด้านบนจะเปลี่ยนไปrunpathแต่rpathจะไม่เปลี่ยนแปลงเว้นแต่คุณจะระบุ--force-rpathตัวเลือกไว้ด้วย
Stuart Berg

10
@superbatfish ใช่ แต่ความแตกต่างมักไม่สำคัญ รายการจากการเปลี่ยนแปลงนี้patchelfอธิบายได้ " --set-rpath, --shrink-rpathและ--print-rpathตอนนี้ชอบ DT_RUNPATHมากกว่าDT_RPATHซึ่งเป็นล้าสมัยเมื่อปรับปรุงถ้าทั้งสองมีอยู่ทั้งมีการปรับปรุงถ้าเพียง แต่ DT_RPATH เป็นปัจจุบันจะถูกแปลงเป็น.. DT_RUNPATHเว้นแต่จะ--force-rpathระบุไว้หากไม่เป็นปัจจุบัน. DT_RUNPATHจะมีการเพิ่มa เว้นแต่--force-rpathจะระบุไว้ซึ่งในกรณีนี้DT_RPATHจะมีการเพิ่ม " ชื่อของตัวเลือกอาจไม่เปลี่ยนแปลงเนื่องจากเหตุผลด้านความเข้ากันได้
user7610

2
คำตอบที่ดีที่สุดควรเป็นคำตอบที่ยอมรับแทน!
Kenneth Hoste

16

เช่นเดียวกับที่ @ user7610 กล่าววิธีที่ถูกต้องคือpatchelfเครื่องมือ

แต่ฉันรู้สึกว่าสามารถให้คำตอบที่ครอบคลุมมากขึ้นครอบคลุมคำสั่งทั้งหมดที่ต้องทำอย่างนั้น

สำหรับบทความที่ครอบคลุมเกี่ยวกับเรื่องนี้คลิก ที่นี่

ก่อนอื่นนักพัฒนาหลายคนพูดถึง RPATHRUNPATHแต่พวกเขาจริงหมายถึง นี่คือส่วนไดนามิกที่เป็นทางเลือกสองส่วนที่แตกต่างกันและตัวโหลดจะจัดการพวกมันต่างกันมาก คุณสามารถอ่านเพิ่มเติมเกี่ยวกับความแตกต่างระหว่างพวกเขาได้ในลิงค์ที่ฉันพูดถึงก่อนหน้านี้

สำหรับตอนนี้โปรดจำไว้ว่า:

  • ถ้า RUNPATHตั้งค่าไว้RPATHจะถูกละเว้น
  • RPATH เลิกใช้แล้วและควรหลีกเลี่ยง
  • RUNPATH เป็นที่ต้องการเนื่องจากสามารถลบล้างได้โดย LD_LIBRARY_PATH

ดูเส้นทาง R [UN] ปัจจุบัน

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

ล้างเส้นทาง R [UN]

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

หมายเหตุ:

  • ลบทั้งสองRPATHและRUNPATH

เพิ่มค่าให้กับ R [UN] PATH

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

หมายเหตุ:

  • <desired-path> คือรายการไดเร็กทอรีที่คั่นด้วยเครื่องหมายจุลภาคเช่น: /my/libs:/my/other/libs
  • หากคุณระบุ--force-rpathชุดหรือชุดRPATHอื่น ๆRUNPATH

1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsชุดDT_RUNPATHและนั่นคือชุดที่คนส่วนใหญ่ควรใช้ RUNPATHสามารถแทนที่โดยเพื่อให้คนที่ไม่ควรใช้LD_LIBRARY_PATH --force-rpath
jww

@jww ฉันเห็นว่าฉันไม่ได้เพิ่มความคิดเห็นเกี่ยวกับการเลิกใช้งาน RPATH ดังนั้นฉันจึงเพิ่มเข้าไปในตอนนี้ ขอบคุณ!
Daniel Trugman

โปรดสังเกตว่าตัวอย่าง<desired-path>ใช้เครื่องหมายจุดคู่ มันควรจะเป็นเครื่องหมายจุลภาค (นั่นคือ: /my/libs,/my/other/libs)
Alan De Smet

@AlanDeSmet ฉันไม่รู้เกี่ยวกับเครื่องหมายจุลภาค แต่โคลอนใช้ได้กับฉัน
Daniel Trugman

RPATH อาจเลิกใช้งานแล้ว แต่การใช้ RUNPATH อาจทำให้เกิดกรณีมุมที่ "ไม่คาดคิด" ได้ ดูตัวอย่างเช่นqt.io/blog/2011/10/28/rpath-and-runpath
Rob

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.