1 điểm bởi GN⁺ 2024-07-11 | 1 bình luận | Chia sẻ qua WhatsApp

Những điều kỳ lạ học được khi viết trình giả lập x86

  • Giải thích nhiều trivia và điểm kỳ lạ học được trong quá trình viết trình giả lập x86 và amd64
  • Trong Time Travel Debugging (TTD), trình giả lập CPU được dùng để ghi lại việc thực thi của tiến trình ở mức lệnh
  • Phiên bản đầu tiên của TTD được gọi là iDNA, được viết bằng mã hợp ngữ nên nhanh nhưng khó bảo trì
  • Phiên bản thứ hai được viết bằng C++ nên khả năng bảo trì được cải thiện

Trivia mã hóa x86 vô dụng

  • Lược đồ mã hóa x86 có thể mã hóa cùng một lệnh theo nhiều cách khác nhau
  • Lệnh int 3 có thể được mã hóa thành CD 03 hoặc CC
  • Thanh ghi EAX được gọi là "thanh ghi tích lũy" và thực sự có khác biệt trong mã hóa
  • Tiền tố REX cho phép truy cập phạm vi thanh ghi rộng hơn trong mã 64-bit
  • Lệnh có thể dài tối đa 15 byte, vượt quá mức này sẽ phát sinh ngoại lệ
  • Tiền tố ghi đè địa chỉ cho phép tham chiếu địa chỉ 32-bit trong chế độ 64-bit

Đặc tính cờ kỳ lạ

  • Lệnh INC không cập nhật cờ carry, khác với lệnh ADD
  • Các lệnh CMPXCHG8B/CMPXCHG16B chỉ sửa đổi cờ zero
  • Các lệnh dịch và xoay sẽ để cờ overflow ở trạng thái không xác định nếu lượng dịch lớn hơn 1

Thêm nhiều bất ngờ về lệnh dịch

  • shr ax, 10h dịch thanh ghi ax 16 bit và biến nó thành 0
  • shr eax, 20h dịch thanh ghi eax 32 bit nhưng giá trị không thay đổi
  • Lượng dịch được mask bằng 1FH

Ghi đè đoạn

  • Segment vẫn được dùng trong mã 32-bit và 64-bit, chủ yếu cho thread-local storage
  • Trên Windows, thanh ghi FS hoặc GS được dùng để tham chiếu TEB (Thread Execution Block)
  • Trong tiến trình 32-bit dùng FS, còn trong tiến trình 64-bit dùng GS
  • Trong chế độ 64-bit, giá trị của thanh ghi segment không quan trọng

Ghi đè đoạn: thêm trivia

  • Trong chế độ 32-bit, giá trị thực của thanh ghi segment tham chiếu đến segment descriptor
  • Trong chế độ 64-bit, base được điều khiển bởi MSR
  • Không thể đọc trực tiếp giá trị segment của tiến trình 64-bit trong WinDbg

Kết luận

  • Bài viết này cung cấp một danh sách ngẫu nhiên các trivia về x86
  • Viết trình giả lập giúp hiểu sâu hơn về cách CPU hoạt động
  • Có thể xem các tài nguyên rất tốt trên website của Agner Fog

Tóm tắt của GN⁺

  • Giải thích nhiều trivia và điểm kỳ lạ học được khi viết trình giả lập x86 và amd64
  • Viết trình giả lập giúp hiểu sâu hơn về cách CPU hoạt động
  • Đề cập nhiều trivia như các cách mã hóa khác nhau của lệnh int 3, tiền tố REX, ghi đè đoạn, v.v.
  • Có thể xem thêm tài nguyên trên website của Agner Fog

1 bình luận

 
GN⁺ 2024-07-11
Ý kiến trên Hacker News
  • Trong Intel SDM, có nêu rõ rằng với lệnh BSF/BSR, khi đầu vào là 0 thì giá trị đích là không xác định. AMD thì tài liệu hóa rằng trong trường hợp này, thanh ghi đích không bị sửa đổi
    • glibc sử dụng thực tế không chính thức là trên Intel, thanh ghi đích cũng không bị sửa đổi
    • TZCNT/LZCNT là dạng BSF/BSR có tiền tố F3, và trên các bộ xử lý cũ thì tiền tố này bị bỏ qua. Cùng một đoạn mã có thể hoạt động khác nhau trên các CPU khác nhau
  • Có nhiều lời phàn nàn về tiền tố, nhưng đó không phải vấn đề lớn nhất. Các bit mở rộng REX/VEX/EVEX.RXB sẽ bị bỏ qua khi không được áp dụng
    • APX có tiền tố REX2 có thể mã hóa các thanh ghi r16-r31, nhưng không thể với xmm16-xmm31
    • Tiền tố EVEX có bố cục khác nhau tùy theo nhiều opcode
    • Tùy loại thanh ghi mà cách dùng bit mở rộng cũng khác nhau
  • Ý kiến từ một người thích lập trình assembly. Họ thích sự đơn giản và chất lượng thẩm mỹ theo chiều dọc
    • Chia sẻ trải nghiệm từng viết một mini VM để giúp một người bạn làm JS hiểu về stack
    • Nhắc rằng người bạn này bận làm web nên không có thời gian để học sâu hơn
  • Nhớ nhầm rằng các biến thể Salsa20 và mã máy nằm trên cryp.to. Trang của Dan Berstein thực ra là cr.yp.to
    • Chia sẻ kinh nghiệm từng thử nhiều cách triển khai khác nhau khi làm công việc liên quan đến mã hóa dữ liệu ở một startup
  • Đề xuất Justine Tunney và trình giả lập của cô ấy. Tài liệu giải thích rất tốt cách CPU hoạt động
  • Phản đối ý kiến cho rằng viết trình giả lập CPU là cách tốt nhất để hiểu CPU
    • Làm CPU ở mức cổng logic mới là cách tốt hơn
  • Phản đối ý kiến cho rằng assembly x86 gây ra nhiều vấn đề hơn RISC
    • x86 dễ phân tích, còn MIPS thì khó
  • Bày tỏ sự kính trọng với các nhà phát triển trình giả lập bộ xử lý x86
    • Trong quá trình phát triển trình giả lập i386, đã học được rất nhiều về system call và ELF
  • Chia sẻ kinh nghiệm viết trình giả lập x86
    • Hồi tưởng lại trải nghiệm từng viết một trình giả lập đồ chơi để chạy mã BIOS ban đầu
  • Chia sẻ ý kiến rằng họ thích phong cách và bố cục của blog này