การเรียกระบบใดที่ใช้เพื่อโหลดไลบรารีใน Linux


23

ในstraceเอาต์พุตพา ธ ไปยังไลบรารีที่เรียกใช้งานการเรียกใช้อยู่ในการเรียกopen()ใช้ นี่เป็นการเรียกระบบที่ใช้โดยโปรแกรมที่เชื่อมโยงแบบไดนามิกหรือไม่? เกี่ยวกับdlopen()อะไร open()ไม่ใช่สายที่ฉันเดาได้ว่าจะมีบทบาทในการทำงานของโปรแกรม

คำตอบ:


33

dlopenไม่ได้เป็นสายระบบมันเป็นฟังก์ชั่นห้องสมุดในห้องสมุด libdl straceเฉพาะสายระบบแสดงขึ้นใน

บน Linux และบนแพลตฟอร์มอื่น ๆ (โดยเฉพาะอย่างยิ่งที่ใช้รูปแบบ ELF สำหรับ executables) dlopenจะถูกนำไปใช้โดยการเปิดไลopen()บรารี่เป้าหมายด้วยการแมปมันเข้ากับหน่วยความจำด้วย มันเป็นส่วนสำคัญอย่างยิ่งที่นี่มันคือสิ่งที่รวมไลบรารีไว้ในพื้นที่ที่อยู่ของกระบวนการดังนั้น CPU จึงสามารถเรียกใช้งานโค้ดได้ แต่คุณต้องไปที่ไฟล์ก่อนที่จะทำได้!mmap()mmap()open()mmap()


2
"mmap () เป็นส่วนที่สำคัญอย่างยิ่ง": จากนั้นตัวเชื่อมโยงแบบไดนามิกจะต้องทำการเปลี่ยนตำแหน่งการเริ่มต้นและอื่น ๆ (แต่นี่จะไม่เห็นในระดับการเรียกของระบบ)
ysdx

1
เนื่องจากการโหลดไลบรารี่นั้นทำโดยฟังก์ชั่นไลบรารี่ฉันคิดว่ามันมีความเกี่ยวข้องที่จะเพิ่มมันเองและld-linuxถูกแมปโดยเคอร์เนลเป็นส่วนหนึ่งของการexecveเรียกระบบ
kasperd

mmap ตามคำตอบนี้ โปรดทราบว่าหลังจากที่ "เปิด" การดำเนินการแต่ละไลบรารีบางส่วน (832) ไบต์จะถูกอ่านก่อนการเรียก mmap ฉันเชื่อว่าจะตรวจสอบว่าไลบรารีนั้นถูกต้อง
Johan

@kasperd ดังนั้นเคอร์เนล Linux จึงทราบถึงตัวโหลดแบบไดนามิกหรือไม่ มันเรียกมันว่าเมื่อมีการใช้งานแอพลิเคชัน? หรือแอปพลิเคชันเองทำเช่นนั้น? หากหลังไฟล์ที่ถูกเรียกใช้งานอื่นจะเข้าถึงหน่วยความจำของแอปพลิเคชันได้อย่างไร
Melab

@Melab ใช่เคอร์เนลตระหนักถึง dynamic linker เคอร์เนลจะอ่านเส้นทางไปยังตัวเชื่อมโยงแบบไดนามิกจากส่วนหัวของปฏิบัติการ และเคอร์เนลจะแมปทั้งในหน่วยความจำ ฉันไม่ทราบว่าจุดเข้าใช้งานซึ่งเคอร์เนลควบคุมการถ่ายโอนไปยังตอนแรกนั้นอยู่ในตัวเชื่อมโยงหรือปฏิบัติการได้หรือไม่ ถ้าฉันใช้มันฉันอาจจะมีการควบคุมการถ่ายโอนเคอร์เนลไปยังจุดเข้าใช้งานใน linker ที่มีที่อยู่ผู้ส่งคืนบนสแต็กที่ชี้ไปยังจุดเข้าใช้งานของปฏิบัติการ
kasperd

5

dlopen ไม่มีส่วนเกี่ยวข้องกับไลบรารีที่แบ่งใช้อย่างที่คุณคิด มีสองวิธีในการโหลดวัตถุที่แชร์:

  1. คุณบอกตัวรวบรวมเวลารวบรวม (ld แต่โดยปกติจะเรียกผ่านตัวรวบรวม) ที่คุณต้องการใช้ฟังก์ชั่นจากไลบรารีที่ใช้ร่วมกันโดยเฉพาะ ด้วยวิธีการนี้คุณจะต้องรู้ว่าชื่อของห้องสมุดจะอยู่ที่ใดเมื่อตัวรวบรวมเวลาทำงาน แต่คุณสามารถเรียกใช้ฟังก์ชันของไลบรารีราวกับว่าพวกเขาเชื่อมโยงกับโปรแกรมของคุณแบบคงที่ เมื่อเรียกใช้แอปพลิเคชันตัวเชื่อมโยงรันไทม์ (ld.so) แบบไดนามิกจะถูกเรียกใช้ก่อนmainหน้าที่จะเรียกใช้และตั้งค่าพื้นที่กระบวนการของแอปพลิเคชันเพื่อให้แอปพลิเคชันค้นหาฟังก์ชันของไลบรารี วิธีนี้เกี่ยวข้องกับopen()การซ้อนกันและจากนั้นmmap()ตามด้วยการตั้งค่าตารางการค้นหา
  2. คุณบอกตัวรวบรวมเวลารวบรวมที่คุณต้องการเชื่อมโยงด้วยlibdlจากนั้นคุณ (โดยใช้วิธีแรก) สามารถโทรdlopen()และdlsym()ฟังก์ชั่น. ด้วย dlopen คุณจะได้รับการจัดการไปยังห้องสมุดซึ่งคุณสามารถใช้กับ dlsym เพื่อรับฟังก์ชั่นตัวชี้ไปยังฟังก์ชั่นเฉพาะ วิธีนี้มีความซับซ้อนมากกว่าสำหรับโปรแกรมเมอร์มากกว่าวิธีแรก (เนื่องจากคุณต้องทำการตั้งค่าด้วยตนเองแทนที่จะให้ตัวเชื่อมโยงทำมันให้คุณโดยอัตโนมัติ) และมันก็ค่อนข้างบอบบางกว่า (เนื่องจากคุณไม่ได้รับการคอมไพล์ - ตรวจสอบเวลาว่าคุณกำลังเรียกใช้ฟังก์ชันด้วยประเภทอาร์กิวเมนต์ที่ถูกต้องตามที่คุณได้รับในวิธีแรก) แต่ข้อดีคือคุณสามารถเลือกวัตถุที่ใช้ร่วมกันที่จะโหลดในขณะทำงาน (หรือแม้กระทั่งว่าจะโหลดเลย) นี่เป็นอินเทอร์เฟซสำหรับการใช้งานประเภทปลั๊กอิน ในที่สุดอินเทอร์เฟซ dlopen ยังพกพาได้น้อยกว่าวิธีอื่นเนื่องจากกลไกของมันขึ้นอยู่กับการใช้งานตัวเชื่อมโยงแบบไดนามิกที่แน่นอน (ดังนั้น libtool'slibltdlซึ่งพยายามแยกความแตกต่างเหล่านี้ออกจากกัน)

ที่น่าสนใจ; ดังนั้นไลบรารีที่โหลดแบบไดนามิกจะดีกว่าเรียกว่าไลบรารีที่ลิงก์แบบไดนามิกเนื่องจากการโหลดไฟล์ไบนารีลงในหน่วยความจำไม่ใช่ส่วนที่ยากทำให้การใช้ที่อยู่ในนั้นสมเหตุสมผล เมื่อฉันขอให้โหลดไลบรารีแบบไดนามิกฉันขอให้เชื่อมโยง (หรือยกเลิกการเชื่อมโยง) ห้องสมุดลงใน (หรือออกจาก) พื้นที่ที่อยู่ของฉัน
Dmitry

4

วันนี้ระบบปฏิบัติการส่วนใหญ่ใช้วิธีการสำหรับไลบรารีที่ใช้ร่วมกันซึ่งเปิดตัวในปลายปี 1987 โดย SunOS-4.0 วิธีนี้ขึ้นอยู่กับการแม็พหน่วยความจำผ่าน mmap ()

จากข้อเท็จจริงที่ว่าในต้นปี 1990 Sun ได้บริจาครหัส a.out เก่า (Solaris ในเวลานั้นเป็น ELF based) แก่ผู้ใช้ FreeBSD และรหัสนี้ในภายหลังได้มอบให้กับระบบอื่น ๆ (รวมถึง Linux) คุณอาจเข้าใจว่าทำไมไม่มีความแตกต่างใหญ่ระหว่างแพลตฟอร์ม


3

ltrace -Sการวิเคราะห์ตัวอย่างที่น้อยที่สุดแสดงให้เห็นว่าmmapใช้ใน glibc 2.23

ใน glibc 2.23, Ubuntu 16.04, รันlatrace -Sบนโปรแกรมขนาดเล็กที่สุดที่ใช้dlopenกับ:

ltrace -S ./dlopen.out

แสดงให้เห็นว่า:

dlopen("libcirosantilli_ab.so", 1 <unfinished ...>
SYS_open("./x86_64/libcirosantilli_ab.so", 524288, 06267650550)      = -2
SYS_open("./libcirosantilli_ab.so", 524288, 06267650550)             = 3
SYS_read(3, "\177ELF\002\001\001", 832)                              = 832
SYS_brk(0)                                                           = 0x244c000
SYS_brk(0x246d000)                                                   = 0x246d000
SYS_fstat(3, 0x7fff42f9ce30)                                         = 0
SYS_getcwd("/home/ciro/bak/git/cpp-cheat"..., 128)                   = 54
SYS_mmap(0, 0x201028, 5, 2050)                                       = 0x7f1c323fe000
SYS_mprotect(0x7f1c323ff000, 2093056, 0)                             = 0
SYS_mmap(0x7f1c325fe000, 8192, 3, 2066)                              = 0x7f1c325fe000
SYS_close(3)                                                         = 0
SYS_mprotect(0x7f1c325fe000, 4096, 1)                                = 0

ดังนั้นเราจะเห็นได้ทันทีว่าdlopenโทร+openmmap

น่ากลัวltraceเครื่องมือร่องรอยทั้งสายห้องสมุดและระบบโทรศัพท์และดังนั้นจึงเหมาะที่จะตรวจสอบสิ่งที่เกิดขึ้นในกรณีนี้

การวิเคราะห์อย่างใกล้ชิดแสดงให้เห็นว่าopenส่งกลับไฟล์ descriptor 3(อันถัดไปฟรีหลังจาก stdin, out และ err)

readแล้วใช้ที่บ่งแฟ้ม แต่สิ่งที่ต้องทำทำไมmmapข้อโต้แย้ง 's จะถูก จำกัด ให้สี่และเราไม่สามารถดูที่ FD ถูกนำมาใช้มีตั้งแต่ที่เป็นอาร์กิวเมนต์ที่ straceยืนยันอย่างที่คาดหวังนั่น3คือสิ่งนั้นและลำดับของจักรวาลได้รับการฟื้นฟู

วิญญาณผู้กล้าหาญยังสามารถเปลี่ยนเป็น glibc code ได้ แต่ฉันไม่สามารถหาmmapgrep ที่รวดเร็วและขี้เกียจได้

ทดสอบกับนี้ตัวอย่างน้อยที่สุดกับการสร้างต้นแบบบน GitHub


2

straceรายงานการเรียกใช้ระบบ (เช่นฟังก์ชั่นที่ใช้งานโดยตรงจากเคอร์เนล) ไลบรารีแบบไดนามิกไม่ใช่ฟังก์ชันเคอร์เนล dlopenเป็นส่วนหนึ่งของไลบรารี C ไม่ใช่เคอร์เนล การดำเนินการของdlopenwill call open(ซึ่งเป็นการเรียกระบบ) เพื่อเปิดไฟล์ไลบรารีเพื่อให้สามารถอ่านได้


5
ltraceสามารถโทรออกห้องสมุดจะเห็นได้โดยใช้
kasperd

@kasperd ltrace -Sสมบูรณ์แบบในการวิเคราะห์สิ่งนี้เนื่องจากมันยังแสดง syscalls: unix.stackexchange.com/a/462710/32558
Ciro Santilli 新疆改造改造中心法轮功六四事件
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.