เมื่อคอมไพล์ไลบรารีที่แบ่งใช้ใน gcc อ็อพชัน -fPIC จะคอมไพล์โค้ดโดยไม่ขึ้นกับตำแหน่ง มีเหตุผลใดบ้าง (ประสิทธิภาพหรืออย่างอื่น) ทำไมคุณถึงไม่รวบรวมตำแหน่งโค้ดทั้งหมดโดยไม่ขึ้นกับใคร?
เมื่อคอมไพล์ไลบรารีที่แบ่งใช้ใน gcc อ็อพชัน -fPIC จะคอมไพล์โค้ดโดยไม่ขึ้นกับตำแหน่ง มีเหตุผลใดบ้าง (ประสิทธิภาพหรืออย่างอื่น) ทำไมคุณถึงไม่รวบรวมตำแหน่งโค้ดทั้งหมดโดยไม่ขึ้นกับใคร?
คำตอบ:
มันเพิ่มทิศทาง ด้วยรหัสอิสระตำแหน่งคุณต้องโหลดที่อยู่ของฟังก์ชันของคุณแล้วข้ามไปที่มัน โดยปกติจะมีที่อยู่ของฟังก์ชันอยู่แล้วในสตรีมคำสั่ง
บทความนี้จะอธิบายถึงวิธีการทำงานของ PIC และเปรียบเทียบกับทางเลือก - การย้ายเวลาในการโหลด ฉันคิดว่ามันเกี่ยวข้องกับคำถามของคุณ
ใช่มีเหตุผลด้านประสิทธิภาพ การเข้าถึงบางอย่างอยู่ภายใต้การกำหนดทิศทางอีกชั้นหนึ่งอย่างมีประสิทธิภาพเพื่อให้ได้ตำแหน่งที่แน่นอนในหน่วยความจำ
นอกจากนี้ยังมี GOT (Global offset table) ซึ่งเก็บค่าชดเชยของตัวแปรส่วนกลาง สำหรับฉันนี่ดูเหมือนตารางฟิกซ์อัพของ IAT ซึ่งจัดเป็นตำแหน่งที่ขึ้นอยู่กับวิกิพีเดียและแหล่งข้อมูลอื่น ๆ
นอกเหนือจากคำตอบที่ได้รับการยอมรับ สิ่งหนึ่งที่ส่งผลเสียต่อประสิทธิภาพของรหัส PIC เป็นอย่างมากคือการไม่มี "ที่อยู่ IP สัมพัทธ์" บน x86 ด้วย "ที่อยู่แบบสัมพัทธ์ IP" คุณสามารถขอข้อมูลที่มีขนาด X ไบต์จากตัวชี้คำสั่งปัจจุบัน สิ่งนี้จะทำให้รหัส PIC ง่ายขึ้นมาก
การกระโดดและการโทรมักจะสัมพันธ์กับ EIP ดังนั้นสิ่งเหล่านี้จึงไม่ก่อให้เกิดปัญหา อย่างไรก็ตามการเข้าถึงข้อมูลจะต้องใช้กลอุบายเพิ่มเติมเล็กน้อย บางครั้งรีจิสเตอร์จะถูกสงวนไว้ชั่วคราวเป็น "ตัวชี้ฐาน" สำหรับข้อมูลที่โค้ดต้องการ ตัวอย่างเช่นเทคนิคทั่วไปคือการใช้วิธีการโทรบน x86 ในทางที่ผิด:
call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp ; now ebp holds the address of the first dataword
; this works because the call pushes the **next**
; instructions address
; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way
เทคนิคนี้และเทคนิคอื่น ๆ จะเพิ่มชั้นของทิศทางในการเข้าถึงข้อมูล ตัวอย่างเช่น GOT (Global offset table) ที่ใช้โดยคอมไพเลอร์ gcc
x86-64 เพิ่มโหมด "RIP ญาติ" ซึ่งจะทำให้สิ่งที่มากง่าย
เนื่องจากการติดตั้งโค้ดที่เป็นอิสระจากตำแหน่งอย่างสมบูรณ์จะเพิ่มข้อ จำกัด ให้กับตัวสร้างโค้ดซึ่งสามารถป้องกันการใช้งานที่เร็วขึ้นหรือเพิ่มขั้นตอนพิเศษเพื่อรักษาข้อ จำกัด นั้น
นี่อาจเป็นการแลกเปลี่ยนที่ยอมรับได้ในการรับการประมวลผลหลายขั้นตอนโดยไม่มีระบบหน่วยความจำเสมือนโดยที่คุณไว้วางใจให้กระบวนการไม่บุกรุกหน่วยความจำของกันและกันและอาจต้องโหลดแอปพลิเคชันเฉพาะที่ที่อยู่ฐานใด ๆ
ในระบบสมัยใหม่จำนวนมากการแลกเปลี่ยนประสิทธิภาพจะแตกต่างกันและตัวโหลดการย้ายตำแหน่งมักจะมีราคาไม่แพง (มีค่าใช้จ่ายทุกครั้งที่โหลดรหัสครั้งแรก) มากกว่าเครื่องมือเพิ่มประสิทธิภาพที่ดีที่สุดสามารถทำได้หากมีการครองราชย์ฟรี นอกจากนี้ความพร้อมใช้งานของช่องว่างที่อยู่เสมือนยังซ่อนแรงจูงใจส่วนใหญ่สำหรับความเป็นอิสระของตำแหน่งตั้งแต่แรก
นอกจากนี้ฮาร์ดแวร์หน่วยความจำเสมือนในโปรเซสเซอร์สมัยใหม่ส่วนใหญ่ (ใช้โดยระบบปฏิบัติการที่ทันสมัยที่สุด) หมายความว่าโค้ดจำนวนมาก (แอปพื้นที่ผู้ใช้ทั้งหมดยกเว้นการใช้ mmap หรือสิ่งที่คล้ายกัน) ไม่จำเป็นต้องเป็นตำแหน่งที่ไม่ขึ้นกับตำแหน่ง ทุกโปรแกรมมีพื้นที่แอดเดรสของตัวเองซึ่งคิดว่าเริ่มต้นที่ศูนย์
position-independent code
มีค่าใช้จ่ายด้านประสิทธิภาพในสถาปัตยกรรมส่วนใหญ่เนื่องจากต้องมีการลงทะเบียนเพิ่มเติม
ดังนั้นนี่คือจุดประสงค์ด้านประสิทธิภาพ
ปัจจุบันระบบปฏิบัติการและคอมไพเลอร์โดยค่าเริ่มต้นทำให้รหัสทั้งหมดเป็นรหัสอิสระของตำแหน่ง ลองคอมไพล์โดยไม่มีแฟล็ก -fPIC โค้ดจะคอมไพล์ได้ดี แต่คุณจะได้รับคำเตือนเท่านั้น OS เหมือน windows ใช้เทคนิคที่เรียกว่า memory mapping เพื่อให้ได้สิ่งนี้
คำถามเกิดขึ้นในปี 2009 สิบปีผ่านไปและตอนนี้รหัสทั้งหมดเป็นตำแหน่งที่เป็นอิสระ ซึ่งตอนนี้บังคับใช้โดยระบบปฏิบัติการและคอมไพเลอร์ ไม่มีวิธีใดที่จะเลือกไม่ใช้ โค้ดทั้งหมดถูกบังคับด้วย PIE และแฟล็ก -no-pic / -no-pie จะถูกละเว้นซึ่งเป็นส่วนหนึ่งของข้ออ้าง ASLR นี้ เหตุผลก็คือการชะลอตัวแอพที่เร็วก่อนหน้านี้และขายฮาร์ดแวร์รุ่นใหม่ภายใต้หน้ากากของความปลอดภัยที่เพิ่มขึ้น นั่นเป็นเรื่องที่ไร้เหตุผลอย่างสิ้นเชิงเพราะตอนนี้หน่วยความจำขนาดใหญ่ทำให้เราสามารถกำจัดนรกของการเชื่อมโยงแบบไดนามิกได้เลยโดยรวบรวมแอปทั้งหมดแบบคงที่
เกิดขึ้นก่อนหน้านี้เมื่อผู้คนยอมรับโหมดจริงอย่างเงียบ ๆ และเสรีภาพอื่น ๆ กำลังถูกพรากไป และฉันคิดว่าคุณ MMU มีการชะลอตัวอย่างหนักเนื่องจากสวิตช์บริบทและเวลาในการตอบสนองของการแปลที่อยู่ คุณจะไม่พบ MMU ในระบบที่สำคัญต่อประสิทธิภาพเช่นเดียวกับที่นักวิทยาศาสตร์ใช้ในการทดลองทางฟิสิกส์
คุณไม่บ่นเพราะคุณไม่รู้ด้วยซ้ำว่ารหัสของคุณถูกทำให้พิการโดยวงล้อฝึกเหล่านี้ ฉันจะว่าอย่างไรได้? เพลิดเพลินกับซอฟต์แวร์ที่ช้าลง 2 เท่าด้วย PIC ของพวกเขาตอนนี้! ยิ่งไปกว่านั้นด้วยการถือกำเนิดของ LLVM ในไม่ช้าจะมีการบังคับใช้ JIT (รหัสที่มีการจัดการ) โดยไม่มีการเข้าถึง x86 inline assembly ซึ่งจะทำให้โค้ด C / C ++ ช้าลง "ผู้ที่สละเสรีภาพเพื่อความมั่นคงก็ไม่สมควรได้รับเช่นกัน"