1 คะแนน โดย GN⁺ 4 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • อีมูเลเตอร์ x86-32 สร้างโค้ดเนทีฟด้วยการแปลงไบนารีเพื่อรันโค้ด x86-32 บนโปรเซสเซอร์อื่น และให้ประสิทธิภาพดีขึ้นมากเมื่อเทียบกับวิธีแบบอินเทอร์พรีเตอร์
  • อีมูเลเตอร์นี้สามารถอธิบายได้ว่า มอง x86-32 เป็นเหมือน ไบต์โค้ด และทำงานเสมือนอีมูเลเตอร์เป็นคอมไพเลอร์ JIT
  • โปรแกรมหนึ่งต้องจัดสรรหน่วยความจำประมาณ 64KB บนสแตก และต้องทำการกำหนดค่าเริ่มต้น โดยวิธีทั่วไปคือทำ stack probe ก่อน จากนั้นลด stack pointer แล้วกำหนดค่าเริ่มต้นหน่วยความจำด้วยลูปขนาดเล็ก
  • คอมไพเลอร์ของโค้ดนี้กลับสร้าง คำสั่งเขียนไบต์ แยกกัน 65,536 คำสั่งแทนการใช้ลูป โดยแต่ละคำสั่งมีขนาด 4 ไบต์ ทำให้ต้องใช้โค้ด 256KB เพื่อกำหนดค่าเริ่มต้นข้อมูล 64KB
  • ทีมอีมูเลเตอร์จึงเพิ่มโค้ดพิเศษในตัวแปลเพื่อจับฟังก์ชันนี้ และแทนที่ด้วย ลูปสั้นๆ ที่ให้ผลลัพธ์เทียบเท่ากัน

เบื้องหลัง: อีมูเลเตอร์ x86-32 และการแปลงไบนารี

  • บน Windows เคยมีอีมูเลเตอร์โปรเซสเซอร์ x86-32 สำหรับระบบที่ทำงานบนโปรเซสเซอร์ชนิดอื่นที่ไม่ใช่ x86-32
  • ต้นฉบับไม่ได้ระบุชัดว่ากรณีนี้ใช้กับโปรเซสเซอร์ใด
  • อีมูเลเตอร์นี้ใช้ การแปลงไบนารี เพื่อสร้างโค้ดเนทีฟที่ทำงานได้เทียบเท่ากับโค้ด x86-32 ต้นฉบับ
  • วิธีนี้ให้ประสิทธิภาพดีขึ้นอย่างมากเมื่อเทียบกับการอีมูเลชันแบบอินเทอร์พรีเตอร์
  • สามารถทำความเข้าใจได้โดยมองว่า x86-32 เป็นไบต์โค้ด และอีมูเลเตอร์เป็น คอมไพเลอร์ JIT

โค้ดที่เป็นปัญหา: การกำหนดค่าเริ่มต้นหน่วยความจำสแตก 64KB

  • โปรแกรมหนึ่งต้องจัดสรรหน่วยความจำประมาณ 64KB บนสแตก และต้องกำหนดค่าเริ่มต้นให้มัน
  • วิธีมาตรฐานคือทำ stack probe ก่อน เพื่อตรวจสอบว่าสามารถใช้หน่วยความจำ 64KB ได้หรือไม่
  • จากนั้นจึงลบ 65,536 ออกจาก stack pointer แล้วกำหนดค่าเริ่มต้นหน่วยความจำด้วยลูปขนาดเล็กที่กระชับ

การคลี่ลูปเกินเหตุของคอมไพเลอร์

  • คอมไพเลอร์ที่คอมไพล์โค้ดนี้ไม่ได้สร้างลูปสำหรับกำหนดค่าเริ่มต้นทีละไบต์
  • แต่กลับคลี่ลูปออกเป็น คำสั่ง “เขียนไบต์ลงหน่วยความจำ” แยกกัน 65,536 คำสั่ง
  • แต่ละคำสั่งมีความยาว 4 ไบต์
  • ผลลัพธ์คือ ต้องใช้ โค้ด 256KB เพื่อกำหนดค่าเริ่มต้นข้อมูล 64KB

การรับมือของทีมอีมูเลเตอร์

  • ทีมอีมูเลเตอร์เพิ่มโค้ดพิเศษลงในตัวแปลเพื่อจับฟังก์ชันนี้
  • ฟังก์ชันที่ตรวจพบจะถูกแทนที่ด้วย ลูปสั้นๆ ที่ให้พฤติกรรมเทียบเท่ากัน
  • การจัดการนี้ไม่ได้แปลโค้ดโปรแกรมต้นฉบับแบบตรงไปตรงมา แต่เป็นการเปลี่ยนแพตเทิร์นโค้ดที่ไม่มีประสิทธิภาพระหว่างการอีมูเลชันให้เป็นรูปแบบที่กระชับกว่า

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

 
GN⁺ 4 시간 전
ความคิดเห็นจาก Lobste.rs
  • ชอบคอมเมนต์ที่อธิบายเรื่อง loop unrolling ให้ Raymond Chen ฟังอยู่เหมือนกัน

    • คอมเมนต์นั้นอาจเขียนขึ้นไม่ใช่แค่เพื่อผู้เขียนบล็อก แต่เพื่อ ผู้อ่านทั่วไป ด้วย
      คนที่มาอ่านบทความแบบนี้ไม่ได้รู้พื้นฐานครบทุกอย่างเสมอไป เลยมีหลายคนที่รู้สึกขอบคุณกับเบาะแสที่ช่วยให้ไปเรียนรู้ต่อได้
    • ไม่เห็นคอมเมนต์นั้นนะ น่าจะถูกลบไปแล้ว แต่ถ้าเป็น Raymond Chen ล่ะก็ คนคนนั้นคือตำนานมีชีวิตเลย
      https://joelonsoftware.com/2004/06/…
    • ทำให้นึกถึงตอนหลายสิบปีก่อนบน Slashdot ที่มีคนพยายามอธิบายเรื่อง Perl ให้ larry@wall.org ฟัง
  • คิดว่าน่าจะเป็นบน Alpha เพราะมีงานจำนวนมหาศาลที่ทุ่มลงไปกับ x86 emulator สำหรับแพลตฟอร์มนั้น