1 คะแนน โดย GN⁺ 2024-07-11 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

สิ่งแปลก ๆ ที่ได้เรียนรู้ระหว่างเขียน x86 emulator

  • อธิบายเกร็ดความรู้และเรื่องแปลก ๆ หลายอย่างที่ได้เรียนรู้ระหว่างเขียน x86 และ amd64 emulator
  • ใน Time Travel Debugging(TTD) มีการใช้ CPU emulator เพื่อบันทึกการทำงานของโปรเซสในระดับคำสั่ง
  • TTD เวอร์ชันแรกเรียกว่า iDNA เขียนด้วย assembly code จึงเร็ว แต่ดูแลรักษายาก
  • เวอร์ชันที่สองเขียนด้วย C++ ทำให้การบำรุงรักษาดีขึ้น

เกร็ดความรู้ x86 encoding ที่แทบไม่ค่อยมีประโยชน์

  • โครงสร้างการเข้ารหัสของ x86 สามารถเข้ารหัสคำสั่งเดียวกันได้หลายวิธี
  • คำสั่ง int 3 สามารถเข้ารหัสได้เป็น CD 03 หรือ CC
  • รีจิสเตอร์ EAX ถูกเรียกว่า "accumulator register" และมีความแตกต่างจริงในด้าน encoding
  • prefix REX ช่วยให้เข้าถึงช่วงรีจิสเตอร์ที่กว้างขึ้นได้ในโค้ด 64 บิต
  • คำสั่งหนึ่งคำสั่งมีความยาวได้สูงสุด 15 ไบต์ และหากเกินกว่านั้นจะเกิด exception
  • address override prefix ช่วยให้อ้างอิงที่อยู่แบบ 32 บิตได้ในโหมด 64 บิต

คุณสมบัติของ flag ที่แปลก ๆ

  • คำสั่ง INC จะไม่อัปเดต carry flag ต่างจากคำสั่ง ADD
  • คำสั่ง CMPXCHG8B/CMPXCHG16B จะเปลี่ยนเฉพาะ zero flag
  • คำสั่ง shift และ rotate จะปล่อยให้ overflow flag อยู่ในสถานะไม่กำหนดเมื่อปริมาณการ shift มากกว่า 1

ความน่าประหลาดใจเพิ่มเติมของคำสั่ง shift

  • shr ax, 10h จะ shift รีจิสเตอร์ ax 16 บิตจนกลายเป็น 0
  • shr eax, 20h จะ shift รีจิสเตอร์ eax 32 บิต แต่ค่าจะไม่เปลี่ยน
  • ปริมาณการ shift จะถูก mask ด้วย 1FH

segment override

  • segment ยังคงถูกใช้ในโค้ด 32 บิตและ 64 บิต โดยหลักแล้วใช้กับ thread local storage
  • บน Windows จะใช้รีจิสเตอร์ FS หรือ GS เพื่ออ้างอิง TEB(Thread Execution Block)
  • โปรเซส 32 บิตใช้ FS และโปรเซส 64 บิตใช้ GS
  • ในโหมด 64 บิต ค่าของ segment register ไม่ได้มีความสำคัญ

segment override: เกร็ดเพิ่มเติม

  • ในโหมด 32 บิต ค่าจริงของ segment register จะอ้างอิง segment descriptor
  • ในโหมด 64 บิต base จะถูกควบคุมโดย MSR
  • ใน WinDbg ไม่สามารถอ่านค่า segment ของโปรเซส 64 บิตได้โดยตรง

บทสรุป

  • บทความนี้รวบรวมเกร็ด x86 แบบสุ่ม ๆ ไว้หลายข้อ
  • การเขียน emulator ช่วยให้เข้าใจอย่างลึกซึ้งว่า CPU ทำงานอย่างไร
  • สามารถดูแหล่งข้อมูลดี ๆ เพิ่มเติมได้จากเว็บไซต์ของ Agner Fog

สรุปโดย GN⁺

  • อธิบายเกร็ดความรู้และเรื่องแปลก ๆ หลายอย่างที่ได้เรียนรู้ระหว่างเขียน x86 และ amd64 emulator
  • การเขียน emulator ช่วยให้เข้าใจการทำงานของ CPU ได้อย่างลึกซึ้ง
  • ครอบคลุมเกร็ดหลายเรื่อง เช่น วิธี encoding ที่หลากหลายของคำสั่ง int 3, prefix REX, และ segment override
  • ดูแหล่งข้อมูลเพิ่มเติมได้จากเว็บไซต์ของ Agner Fog

1 ความคิดเห็น

 
GN⁺ 2024-07-11
ความคิดเห็นจาก Hacker News
  • Intel SDM ระบุอย่างชัดเจนว่าคำสั่ง BSF/BSR เมื่อรับค่าอินพุตเป็น 0 จะมีค่าปลายทางที่ไม่กำหนดไว้ ส่วน AMD ระบุไว้ในเอกสารว่าในกรณีนี้ค่าปลายทางจะไม่ถูกแก้ไข
    • glibc ใช้ข้อเท็จจริงที่ไม่เป็นทางการว่าบน Intel ค่าปลายทางจะไม่ถูกแก้ไข
    • TZCNT/LZCNT เป็นรูปแบบของ BSF/BSR ที่มีคำนำหน้า F3 ซึ่งจะถูกละเลยบนโปรเซสเซอร์รุ่นเก่า ทำให้โค้ดเดียวกันอาจทำงานต่างกันบน CPU คนละตัว
  • มีคำบ่นเกี่ยวกับคำนำหน้าอยู่มาก แต่สิ่งนี้ไม่ใช่ปัญหาใหญ่ที่สุด เมื่อบิตขยาย REX/VEX/EVEX.RXB ไม่ถูกนำไปใช้ มันจะถูกเพิกเฉย
    • APX มีคำนำหน้า REX2 ที่สามารถเข้ารหัสรีจิสเตอร์ r16-r31 ได้ แต่ไม่สามารถใช้กับ xmm16-xmm31 ได้
    • คำนำหน้า EVEX มีเลย์เอาต์ต่างกันไปตาม opcode หลายแบบ
    • การใช้บิตขยายแตกต่างกันไปตามประเภทของรีจิสเตอร์
  • ความเห็นจากคนที่ชอบเขียนแอสเซมบลีโค้ด โดยชอบคุณภาพด้านสุนทรียะที่เรียบง่ายและตรงไปตรงมา
    • แชร์ประสบการณ์การเขียน mini VM เพื่ออธิบายเรื่องสแตกให้เพื่อนสาย JS เข้าใจ
    • กล่าวถึงว่าเพื่อนยุ่งกับงานพัฒนาเว็บจนไม่มีเวลาศึกษาเชิงลึก
  • จำผิดว่าเวอร์ชันดัดแปลงของ Salsa20 และ machine code อยู่ที่ cryp.to แต่เว็บไซต์ของ Dan Berstein คือ cr.yp.to
    • แชร์ประสบการณ์จากการทำงานด้านการเข้ารหัสข้อมูลในสตาร์ตอัปและทดสอบอิมพลีเมนเทชันหลายแบบ
  • แนะนำ Justine Tunney และอีมูเลเตอร์ของเธอ โดยเอกสารอธิบายการทำงานของ CPU ได้ดี
  • ไม่เห็นด้วยกับความเห็นที่ว่าการเขียน CPU emulator เป็นวิธีที่ดีที่สุดในการเข้าใจ CPU
    • มองว่าการสร้าง CPU ในระดับ gate level เป็นวิธีที่ดีกว่า
  • ไม่เห็นด้วยกับความเห็นที่ว่าแอสเซมบลี x86 ก่อปัญหามากกว่า RISC
    • x86 วิเคราะห์ได้ง่าย แต่ MIPS กลับยาก
  • แสดงความเคารพต่อนักพัฒนา x86 processor emulator
    • ระหว่างพัฒนา i386 emulator ได้เรียนรู้มากเกี่ยวกับ system call และ ELF
  • แชร์ประสบการณ์การเขียน x86 emulator
    • ย้อนความถึงการเคยเขียน toy emulator ที่รันโค้ด BIOS ช่วงเริ่มต้นได้
  • แชร์ความเห็นว่าชอบสไตล์และเลย์เอาต์ของบล็อก