ไฟล์ปฏิบัติการแบบไบนารีประกอบขึ้นอย่างไร? มาสำรวจกัน!
- ไฟล์ปฏิบัติการไม่ใช่สิ่งที่เข้าใจไม่ได้ แต่เป็นรูปแบบไฟล์มาตรฐานชนิดหนึ่ง
- บทความนี้ว่าด้วยการจัดการไบนารี ELF บนลินุกซ์ โดยใช้ภาษา C แต่ก็ประยุกต์กับภาษาแบบคอมไพล์อื่น ๆ ได้เช่นกัน
- เรียนรู้เกี่ยวกับ สัญลักษณ์ (symbol), เซกชัน (section) และ เซกเมนต์ (segment)
- สัญลักษณ์เปรียบได้กับชื่อฟังก์ชัน ถูกจัดอยู่ในเซกชัน และเซกชันต่าง ๆ ก็ถูกรวมเป็นเซกเมนต์
- ใช้เครื่องมือ
readelfเพื่อสำรวจสิ่งเหล่านี้
ขั้นที่ 1: เปิดด้วยโปรแกรมแก้ไขข้อความ!
- เป็นวิธีที่ง่ายที่สุดในการดูไบนารี และจะเห็นข้อความอย่าง "Penguin!" และ "ELF"
ขั้นที่ 2: ใช้ readelf เพื่อดูตารางสัญลักษณ์
- ใช้
readelf --symbolsเพื่อดูสัญลักษณ์ได้ - สามารถเห็นสัญลักษณ์อย่าง
main,puts,_start - โปรแกรมไม่ได้เริ่มที่
mainแต่เริ่มที่_start
สัญลักษณ์
- เมื่อเขียนโปรแกรม จะมีการสร้างสัญลักษณ์สำหรับฟังก์ชันต่าง ๆ
- เมื่อต้องเรียกใช้ฟังก์ชันจากไลบรารี ก็จำเป็นต้องมีสัญลักษณ์เพื่อค้นหาโค้ดของฟังก์ชันนั้น
- การลิงก์เกิดขึ้นได้ทั้งแบบสแตติก (static linking) และไดนามิก (dynamic linking)
ขั้นที่ 3: ใช้ objdump เพื่อดูไบนารีและเรียนรู้เรื่องเซกชัน!
objdumpให้วิธีที่ดีกว่าในการดูไบนารี- สามารถดูเซกชันอย่าง
.text,.rodata,.interpได้ - เซกชันใช้ในช่วงลิงก์ ส่วนเซกเมนต์ใช้ในช่วงรันไทม์
ขั้นที่ 4: ดูแอสเซมบลี!
- เซกชัน
.textมีโค้ดแอสเซมบลีอยู่ - ใช้
objdump -dเพื่อดูโค้ดแอสเซมบลี
ขั้นที่ 5: ดูเซกเมนต์!
- โปรแกรมประกอบด้วยเซกเมนต์ หรือ program header
- ใช้
readelf --segmentsเพื่อดูเซกเมนต์ - เซกเมนต์เป็นตัวกำหนดว่าจะแยกส่วนต่าง ๆ ของโปรแกรมในหน่วยความจำอย่างไร
ไม่ใช่เวทมนตร์!
- ไฟล์ปฏิบัติการไม่ใช่เวทมนตร์ และ ELF ก็เหมือนกับรูปแบบไฟล์อื่น ๆ
- สามารถใช้
readelf,nm,objdumpเพื่อตรวจสอบไบนารีบนลินุกซ์ได้
ความคิดเห็นของ GN⁺
- บทความนี้มีประโยชน์มากสำหรับวิศวกรซอฟต์แวร์ระดับเริ่มต้นที่ต้องการเข้าใจโครงสร้างของไฟล์ปฏิบัติการแบบไบนารี
- ให้ข้อมูลเชิงปฏิบัติเกี่ยวกับแนวคิดของสัญลักษณ์ เซกชัน เซกเมนต์ และเครื่องมือสำหรับตรวจสอบสิ่งเหล่านี้ (
readelf,objdump) - ยังช่วยปูพื้นความเข้าใจว่าจริง ๆ แล้วโปรแกรมถูกโหลดเข้าหน่วยความจำและทำงานอย่างไร ซึ่งอาจจุดประกายความสนใจในด้าน system programming ได้
1 ความคิดเห็น
ความเห็นจาก Hacker News
ผู้ใช้คนหนึ่งแนะนำให้ลองเขียน ELF (Executable and Linkable Format) ด้วยตัวเอง โดยบอกว่านี่ช่วยให้เข้าใจส่วนพื้นฐานของไฟล์ปฏิบัติการได้มาก อีกทั้งบทความนี้ยังมีประโยชน์สำหรับคนที่ต้องการแนวทางแบบมองจากบนลงล่าง แทนที่จะเป็นวิธีแบบดั้งเดิมที่ไล่จากล่างขึ้นบน
ผู้ใช้อีกคนอธิบายว่าแม้อาจคิดว่าโปรแกรมเริ่มทำงานที่
mainแต่ในความเป็นจริงมันเริ่มที่_startโดย_startจะทำงานสำคัญหลายอย่างรวมถึงการเรียกmainและนี่ไม่ใช่สิ่งที่เฉพาะกับภาษา C แต่เป็นจุดเริ่มต้นของไบนารีที่ไม่ขึ้นกับภาษาผู้ใช้คนหนึ่งกล่าวว่าบทความของ Julia ยอดเยี่ยมเสมอ และบอกว่าตนได้ผลลัพธ์ที่ดีในการสอนผู้คนว่าโค้ดที่คอมไพล์แล้วไม่ได้ซ่อนความลับไว้ ด้วยการสาธิตคำสั่ง
stringsผู้ใช้คนหนึ่งเล่าว่าตนเริ่มศึกษาหัวข้อนี้ครั้งแรกตอนเปลี่ยนเส้นทางอาชีพทางวิชาการจากคณิตศาสตร์ไปสู่วิทยาการคอมพิวเตอร์ และไม่เคยเสียใจกับการลงลึกเช่นนี้ อีกทั้ง Julia เองก็มีพื้นฐานด้านคณิตศาสตร์ด้วย และเขาคิดว่าความต้องการในการให้เหตุผลแบบมองจากบนลงล่างนี้อาจเป็นสิ่งที่พานักคณิตศาสตร์ไปสู่การทดลองลักษณะนี้
ผู้ใช้คนหนึ่งสะท้อนว่าไฟล์ปฏิบัติการนั้นผูกกับแพลตฟอร์ม และแบ่งปันประสบการณ์ตอนที่พิสูจน์ได้ว่า “ไฟล์ปฏิบัติการที่พกพาได้จริง” สามารถรันได้บนหลายแพลตฟอร์ม ซึ่งหมายความว่าคำตอบของปัญหาข้ามแพลตฟอร์มที่เราเคยพยายามแก้ด้วยวิธีต่าง ๆ เช่น Java และไลบรารีข้ามแพลตฟอร์มนั้น อยู่ตรงหน้ามานานแล้ว
ผู้ใช้คนหนึ่งเล่าว่าช่วงต้นทศวรรษ 90 เขาหลงใหลในฟอร์แมตของไฟล์ปฏิบัติการมากจนเขียนโปรแกรมดูไฟล์ปฏิบัติการของ DOS และ Windows ด้วย Modula 2 โปรแกรมนี้ออกเป็นแชร์แวร์ในปี 1991 ภายใต้ชื่อ VEXE ได้รับความนิยมระดับหนึ่งในหมู่แคร็กเกอร์ และยังถูกกล่าวถึงในบทเรียนของ +ORC ด้วย
ผู้ใช้คนหนึ่งบอกว่าการพิมพ์ไฟล์ไบนารีออกสู่เทอร์มินัลเป็นต้นเหตุแห่งความเศร้า และตัวเขาเองชอบใช้
hexdump -Cมากกว่าผู้ใช้หลายคนกล่าวว่านี่เป็นเธรดที่ยอดเยี่ยมเกี่ยวกับหัวข้อนี้
ผู้ใช้คนหนึ่งแนะนำให้ผู้ที่สนใจหัวข้อนี้ลองอ่าน Cosmopolitan และ RedBean รวมถึง "αcτµαlly pδrταblε εxεcµταblε (2020)"