x86 ud2 명령은 왜 '2'인가: 0F FF가 ud0, 0F B9가 ud1로 소급 명명된 사연
- ud2는 x86에서 아키텍처적으로 정의되지 않은 명령이며 실행하면 반드시 invalid opcode 예외가 발생함. 컴파일러는 도달 불가능한 코드 표시용으로 이를 넣는데, 예컨대 [[noreturn]] 함수가 반환하면 호출 뒤에 ud2를 배치해 다음 함수로 흘러가는 대신 크래시시킴
- 원래 x86에는 공식 undefined 명령이 없어서 사람들이 직접 바이트열을 찾아 썼고, 0F FF를 쓰는 쪽과 0F B9를 쓰는 쪽 두 파벌이 생김. 두 시퀀스 모두 invalid opcode 예외를 올렸음
- 인텔이 다음 프로세서에서 0F FF의 동작을 바꾸자 이를 의존하던 프로그램이 깨졌고, 관찰 가능한 모든 동작은 누군가 의존하게 된다는 Hyrum의 법칙 사례가 됨
- 인텔이 공식 명령을 만들면서 0F FF는 ud0, 0F B9는 ud1로 소급 명명했고 ud2가 권장 undefined opcode로 남음. ud2는 파라미터 없는 2바이트라 디코드만 되고 쓰이지 않는 소스와 데스티네이션을 다룰 필요가 없음
- ud0와 ud1은 파라미터를 쓰지 않아도 디코드는 되므로, 명령 디코딩이 not-present 페이지를 넘어가면 invalid opcode가 아니라 access violation이 발생함. 일부 구형 프로세서는 0F FF를 디코드하자마자 예외를 올려 페이지 끝에 걸친 경우 동작이 일관되지 않았음
Hacker News 의견들
x86 잘 모르는데 다른 아키텍처처럼 소프트웨어 인터럽트로 예외 못 올리나? 그런 기능이 있었는데 용도가 부족했던 건가
x86에도 INT Ib, INT1, INT3, INTO, BOUND 같은 게 있음
그건 사실상 관례 문제임. INT6 핸들러를 부르려면 그 핸들러가 기대하는 플래그와 레지스터를 코드로 채워야 하는데, 실제로 invalid opcode 예외를 터뜨리면 그 값들이 자동으로 채워짐
지금은 UD0 UD1 UD2가 SDM과 APM에 공식으로 들어 있음. 64비트 모드용 1바이트짜리 UDB(D6)도 x86-64에 오면서 생겼고, 예전부터 있던 UDW(FF FF)는 group #5에 modrm이 mod=11b r/m=111b /7 reg=111b인 형태라 메모리가 전부 1로 세팅되거나 버스가 1로 종단된 경우에 중요함
이거 그냥 추측 아님? 근거 있는 거야?
명령 동작 자체는 문서화돼 있고, 과거에 다른 invalid 명령을 같은 목적으로 쓴 역사도 잘 알려져 있음. 짧게 검색해선 인텔 공식 문서가 안 나오지만 이 사람이 그동안 써온 걸 보면 순수한 추측은 아닐 듯. 어차피 이 사람 추측이 다른 사람 확실한 사실보다 믿을 만함
첫 하드디스크 드라이브 문자가 C인 이유랑 같은 맥락임. A는 3.5인치, B는 5.25인치, C가 하드디스크
0F FF가 #1, 0F B9가 #2가 될 줄 알았는데 인텔이 0부터 세는 바람에 ud가 세 개가 된 게 읽으면서 좀 놀라웠음
기사는 읽고 댓글 단 거 맞음?
결국 0F FF 신도들이 UD0라는 영광을 받아서 진짜 원조 invalid opcode가 됐고, 0F B9 쪽은 UD1이라는 굴욕을 안게 된 셈