ในstraceเอาต์พุตพา ธ ไปยังไลบรารีที่เรียกใช้งานการเรียกใช้อยู่ในการเรียกopen()ใช้ นี่เป็นการเรียกระบบที่ใช้โดยโปรแกรมที่เชื่อมโยงแบบไดนามิกหรือไม่? เกี่ยวกับdlopen()อะไร open()ไม่ใช่สายที่ฉันเดาได้ว่าจะมีบทบาทในการทำงานของโปรแกรม
ในstraceเอาต์พุตพา ธ ไปยังไลบรารีที่เรียกใช้งานการเรียกใช้อยู่ในการเรียกopen()ใช้ นี่เป็นการเรียกระบบที่ใช้โดยโปรแกรมที่เชื่อมโยงแบบไดนามิกหรือไม่? เกี่ยวกับdlopen()อะไร open()ไม่ใช่สายที่ฉันเดาได้ว่าจะมีบทบาทในการทำงานของโปรแกรม
คำตอบ:
dlopenไม่ได้เป็นสายระบบมันเป็นฟังก์ชั่นห้องสมุดในห้องสมุด libdl straceเฉพาะสายระบบแสดงขึ้นใน
บน Linux และบนแพลตฟอร์มอื่น ๆ (โดยเฉพาะอย่างยิ่งที่ใช้รูปแบบ ELF สำหรับ executables) dlopenจะถูกนำไปใช้โดยการเปิดไลopen()บรารี่เป้าหมายด้วยการแมปมันเข้ากับหน่วยความจำด้วย มันเป็นส่วนสำคัญอย่างยิ่งที่นี่มันคือสิ่งที่รวมไลบรารีไว้ในพื้นที่ที่อยู่ของกระบวนการดังนั้น CPU จึงสามารถเรียกใช้งานโค้ดได้ แต่คุณต้องไปที่ไฟล์ก่อนที่จะทำได้!mmap()mmap()open()mmap()
ld-linuxถูกแมปโดยเคอร์เนลเป็นส่วนหนึ่งของการexecveเรียกระบบ
dlopen ไม่มีส่วนเกี่ยวข้องกับไลบรารีที่แบ่งใช้อย่างที่คุณคิด มีสองวิธีในการโหลดวัตถุที่แชร์:
mainหน้าที่จะเรียกใช้และตั้งค่าพื้นที่กระบวนการของแอปพลิเคชันเพื่อให้แอปพลิเคชันค้นหาฟังก์ชันของไลบรารี วิธีนี้เกี่ยวข้องกับopen()การซ้อนกันและจากนั้นmmap()ตามด้วยการตั้งค่าตารางการค้นหาlibdlจากนั้นคุณ (โดยใช้วิธีแรก) สามารถโทรdlopen()และdlsym()ฟังก์ชั่น. ด้วย dlopen คุณจะได้รับการจัดการไปยังห้องสมุดซึ่งคุณสามารถใช้กับ dlsym เพื่อรับฟังก์ชั่นตัวชี้ไปยังฟังก์ชั่นเฉพาะ วิธีนี้มีความซับซ้อนมากกว่าสำหรับโปรแกรมเมอร์มากกว่าวิธีแรก (เนื่องจากคุณต้องทำการตั้งค่าด้วยตนเองแทนที่จะให้ตัวเชื่อมโยงทำมันให้คุณโดยอัตโนมัติ) และมันก็ค่อนข้างบอบบางกว่า (เนื่องจากคุณไม่ได้รับการคอมไพล์ - ตรวจสอบเวลาว่าคุณกำลังเรียกใช้ฟังก์ชันด้วยประเภทอาร์กิวเมนต์ที่ถูกต้องตามที่คุณได้รับในวิธีแรก) แต่ข้อดีคือคุณสามารถเลือกวัตถุที่ใช้ร่วมกันที่จะโหลดในขณะทำงาน (หรือแม้กระทั่งว่าจะโหลดเลย) นี่เป็นอินเทอร์เฟซสำหรับการใช้งานประเภทปลั๊กอิน ในที่สุดอินเทอร์เฟซ dlopen ยังพกพาได้น้อยกว่าวิธีอื่นเนื่องจากกลไกของมันขึ้นอยู่กับการใช้งานตัวเชื่อมโยงแบบไดนามิกที่แน่นอน (ดังนั้น libtool'slibltdlซึ่งพยายามแยกความแตกต่างเหล่านี้ออกจากกัน)วันนี้ระบบปฏิบัติการส่วนใหญ่ใช้วิธีการสำหรับไลบรารีที่ใช้ร่วมกันซึ่งเปิดตัวในปลายปี 1987 โดย SunOS-4.0 วิธีนี้ขึ้นอยู่กับการแม็พหน่วยความจำผ่าน mmap ()
จากข้อเท็จจริงที่ว่าในต้นปี 1990 Sun ได้บริจาครหัส a.out เก่า (Solaris ในเวลานั้นเป็น ELF based) แก่ผู้ใช้ FreeBSD และรหัสนี้ในภายหลังได้มอบให้กับระบบอื่น ๆ (รวมถึง Linux) คุณอาจเข้าใจว่าทำไมไม่มีความแตกต่างใหญ่ระหว่างแพลตฟอร์ม
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
straceรายงานการเรียกใช้ระบบ (เช่นฟังก์ชั่นที่ใช้งานโดยตรงจากเคอร์เนล) ไลบรารีแบบไดนามิกไม่ใช่ฟังก์ชันเคอร์เนล dlopenเป็นส่วนหนึ่งของไลบรารี C ไม่ใช่เคอร์เนล การดำเนินการของdlopenwill call open(ซึ่งเป็นการเรียกระบบ) เพื่อเปิดไฟล์ไลบรารีเพื่อให้สามารถอ่านได้
ltraceสามารถโทรออกห้องสมุดจะเห็นได้โดยใช้
ltrace -Sสมบูรณ์แบบในการวิเคราะห์สิ่งนี้เนื่องจากมันยังแสดง syscalls: unix.stackexchange.com/a/462710/32558