1P by neo 2달전 | favorite | 댓글 1개

x86 에뮬레이터를 작성하면서 배운 이상한 것들

  • x86 및 amd64 에뮬레이터를 작성하면서 배운 다양한 트리비아와 이상한 점들에 대해 설명함
  • Time Travel Debugging(TTD)에서 CPU 에뮬레이터를 사용하여 프로세스의 실행을 명령어 수준에서 기록함
  • 첫 번째 버전의 TTD는 iDNA로 불리며, 어셈블리 코드로 작성되어 빠르지만 유지보수가 어려웠음
  • 두 번째 버전은 C++로 작성되어 유지보수성이 향상되었음

쓸모없는 x86 인코딩 트리비아

  • x86 인코딩 스킴은 동일한 명령어를 여러 가지 방법으로 인코딩할 수 있음
  • int 3 명령어는 CD 03 또는 CC로 인코딩될 수 있음
  • EAX 레지스터는 "누산기 레지스터"로 불리며, 인코딩에서 실제로 차이가 있음
  • REX 프리픽스는 64비트 코드에서 더 넓은 범위의 레지스터에 접근할 수 있게 함
  • 명령어는 최대 15바이트까지 길어질 수 있으며, 이를 초과하면 예외가 발생함
  • 주소 오버라이드 프리픽스는 64비트 모드에서 32비트 주소를 참조할 수 있게 함

이상한 플래그 특성

  • INC 명령어는 ADD 명령어와 달리 캐리 플래그를 업데이트하지 않음
  • CMPXCHG8B/CMPXCHG16B 명령어는 제로 플래그만 수정함
  • 시프트 및 회전 명령어는 시프트 양이 1보다 클 경우 오버플로우 플래그를 정의되지 않은 상태로 둠

시프트 명령어의 더 많은 놀라움

  • shr ax, 10hax 레지스터를 16비트 시프트하여 0으로 만듦
  • shr eax, 20heax 레지스터를 32비트 시프트하지만 값은 변경되지 않음
  • 시프트 양은 1FH로 마스킹됨

세그먼트 오버라이드

  • 세그먼트는 32비트 및 64비트 코드에서 여전히 사용되며, 주로 스레드 로컬 스토리지에 사용됨
  • Windows에서는 FS 또는 GS 레지스터를 사용하여 TEB(Thread Execution Block)를 참조함
  • 32비트 프로세스에서는 FS를 사용하고, 64비트 프로세스에서는 GS를 사용함
  • 64비트 모드에서는 세그먼트 레지스터의 값이 중요하지 않음

세그먼트 오버라이드: 더 많은 트리비아

  • 32비트 모드에서는 세그먼트 레지스터의 실제 값이 세그먼트 디스크립터를 참조함
  • 64비트 모드에서는 MSR에 의해 베이스가 제어됨
  • WinDbg에서 64비트 프로세스의 세그먼트 값을 직접 읽을 수 없음

결론

  • 이 글은 x86 트리비아의 무작위 목록을 제공함
  • 에뮬레이터를 작성하는 것은 CPU가 어떻게 작동하는지 깊이 이해하는 데 도움이 됨
  • Agner Fog의 웹사이트에서 훌륭한 리소스를 확인할 수 있음

GN⁺의 정리

  • x86 및 amd64 에뮬레이터를 작성하면서 배운 다양한 트리비아와 이상한 점들을 설명함
  • 에뮬레이터를 작성하는 것은 CPU의 작동 방식을 깊이 이해하는 데 도움이 됨
  • int 3 명령어의 다양한 인코딩 방법, REX 프리픽스, 세그먼트 오버라이드 등 다양한 트리비아를 다룸
  • Agner Fog의 웹사이트에서 더 많은 리소스를 확인할 수 있음
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에 따라 다른 레이아웃을 가짐
    • 레지스터 유형에 따라 확장 비트 사용이 달라짐
  • 어셈블리 코딩을 즐기는 사람의 의견. 간단하고 수직적인 미학적 품질을 즐김
    • JS 친구에게 스택을 이해시키기 위해 미니 VM을 작성한 경험을 공유함
    • 친구가 웹 개발로 바빠서 깊이 있는 공부를 할 시간이 없음을 언급함
  • Salsa20 변형과 머신 코드가 cryp.to에 있다고 잘못 기억함. Dan Berstein의 사이트는 cr.yp.to임
    • 스타트업에서 데이터 암호화 관련 작업을 하면서 다양한 구현을 테스트한 경험을 공유함
  • Justine Tunney와 그녀의 에뮬레이터를 추천함. 문서가 CPU 작동 방식을 잘 설명함
  • CPU 에뮬레이터 작성이 CPU를 이해하는 최고의 방법이라는 의견에 반대함
    • 게이트 레벨에서 CPU를 만드는 것이 더 나은 방법임
  • x86 어셈블리가 RISC보다 더 많은 문제를 일으킨다는 의견에 반대함
    • x86은 분석하기 쉽지만, MIPS는 어려움
  • x86 프로세서 에뮬레이터 개발자에 대한 존경을 표함
    • i386 에뮬레이터를 개발하면서 시스템 호출과 ELF에 대해 많이 배움
  • x86 에뮬레이터 작성 경험을 공유함
    • 초기 BIOS 코드를 실행하는 장난감 에뮬레이터를 작성한 경험을 회상함
  • 블로그 스타일과 레이아웃이 마음에 든다는 의견을 공유함