블랙박스 해독: Intel 80386 마이크로코드 역어셈블

수십 년 동안 Intel 80386은 32비트 시대를 도입하고 멀티태스킹 운영 체제가 번창할 수 있게 한 복잡한 메모리 관리를 선보이며 현대 컴퓨팅의 초석이 되었습니다. 그러나 그 아키텍처 매뉴얼은 잘 문서화되어 있었지만, 하드웨어가 머신 코드를 어떻게 실행할지 지시하는 저수준 명령인 내부 마이크로코드는 완전한 블랙박스로 남아 있었습니다.

최근 연구자들과 애호가들의 협력적인 노력을 통해 80386 마이크로코드를 역어셈블하는 데 성공했습니다. 이 성과는 단순한 향수를 불러일으키는 업적이 아닙니다. 이는 고해상도 다이 이미징, 신경망, 그리고 세심한 논리 분석을 결합하여 전설적인 프로세서의 내부 작동 방식을 밝혀낸 리버스 엔지니어링의 마스터클래스입니다.

다이 이미지에서 바이너리 블롭으로

여정은 Ken Shirriff가 제공한 80386 다이의 고해상도 이미지로 시작되었습니다. 물리적 칩에서 데이터를 추출하는 것은 엄청난 작업입니다. 80386의 마이크로코드 ROM은 94,720비트로, 이전 모델인 8086의 10,752비트에 비해 압도적으로 큽니다.

실리콘 다이의 사진을 사용 가능한 바이너리 블롭으로 바꾸는 데는 정교한 파이프라인이 필요합니다. 팀은 ROM 구조를 식별하고 비트를 추출하기 위해 이미지 처리, 신경망, 그리고 인간의 도움을 받는 자동화 기술을 결합하여 사용했습니다. 바이너리 블롭을 확보한 후에는 진짜 도전 과제가 시작되었습니다. 바로 데이터를 해석하는 것이었습니다.

역어셈블의 기술

(8086과 달리) 가이드가 될 지도나 특허가 없는 상태에서, 팀은 패턴 인식과 블랙박스 분석에 의존해야 했습니다. 이 과정에는 몇 가지 중요한 돌파구가 포함되었습니다:

  1. 축 정렬(Axis Alignment): 그들은 바이너리 데이터를 한 축에는 마이크로 연산($μ-ops$)으로, 다른 축에는 해당 연산의 특정 비트로 재배열하는 방법을 식별했습니다.
  2. 필드 식별(Field Identification): 8086의 마이크로코드와 80386의 알려진 성능 특성(예: 2사이클 내에 ALU 연산을 수행할 수 있는 능력)을 분석함으로써, 소스 및 대상 레지스터를 위한 필드와 두 번째 ALU 입력의 존재를 추론했습니다.
  3. 명령어 매핑(Instruction Mapping): 명령어 디코더(여러 개의 작은 PLA로 구성됨)와 보호 테스트 PLA를 디코딩함으로써, 팀은 마침내 특정 x86 명령어를 그에 해당하는 마이크로코드 조각과 연결할 수 있었습니다.

하드웨어 가속 vs 마이크로코드

가장 눈에 띄는 발견 중 하나는 8086과 80386 사이의 철학적 차이입니다. 8086이 알고리즘을 구현하기 위해 마이크로코드에 크게 의존했던 반면, 80386은 대폭 증가한 트랜지스터 수를 활용하여 "하드웨어 가속기"를 구현합니다.

80386에서 마이크로코드의 많은 부분은 알고리즘을 직접 구현하기보다는 배럴 시프터(barrel shifter), 곱셈/나눗셈 하드웨어, 보호 테스트 유닛과 같은 이러한 가속기들을 설정하는 코디네이터 역할을 수행합니다. 이러한 변화는 이후 CPU의 더 복잡하고 고성능인 산업 설계로의 전환을 나타냅니다.

주요 발견 및 이상 현상

명령어 복잡성

80386 마이크로코드는 디코딩 ROM에서 215개의 엔트리 포인트를 포함하고 있으며, 이는 8086에서 발견된 60개에 비해 상당한 증가입니다. 이러한 증가는 새로운 명령어와 피연연산자 유형(레지스터 vs 메모리), CPU 모드(real vs protected), 그리고 REP 접두사의 존재 여부에 따른 다양한 루틴의 필요성 때문에 발생합니다.

"항상 실행되는" 마이크로코드

단순한 명령어를 위해 마이크로코드를 완전히 건너뛰는 "패스트 패스(fast path)"를 자주 사용하는 현대적 CPU와 달리, 80386은 항상 $μ-op$를 실행합니다. 모든 단일 명령어는 아무리 단순하더라도 마이크로코드로 처리됩니다.

잠재적인 40년 된 버그

아마도 가장 흥미로운 발견은 IO 권한 비트맵 처리에서의 잠재적인 결함함입니다. 역어셈블 결과는 4바이트 포트 액세스 시 마이크로코드가 처음 세 주소의 권한 비트만 확인하는 것 같다는 점을 시사합니다.

4바이트 포트 액세스가 발생하면 마이크로코드가 처음 3개 주소의 권한 비트를 확인하는 것으로 보입니다. 따라서 만약 그러한 액세스가 IO-port 공간의 가장자리에서 수행된다면... 액세스의 마지막 바이트는 잘못된 성공으로 처리될 수 있습니다.

이 버그는 모호하고 특정 CPU 리비전에서만 존재할 수 있지만, 이는 숨겨진 하드웨어 취약점을 찾아내는 데 있어 마이크로코드 분석의 지속적인 가치를 보여줍니다.

결론

80386 마이크로코드를 역어셈블하는 것은 호기심와 기술적 끈기의 승리입니다. 이는 프로세서를 신비로운 실리콘 조각에서 읽을 수 있는 명령어 세트로 변환하여, 386이 가상 86 모드와 메모리 페이징을 통해 가져온 복잡성의 폭발을 어떻게 처리했는지 그 신비함을 벗겨냅니다. 결과를 탐구하는 데 관심이 있는 분들은 x86 microcode repository on GitHub에서 전체 역어셈블 결과를 확인할 수 있습니다.

Sources