x86의 미정의 명령어는 왜 ud2라고 부를까? 왜 2일까?

4 days ago 15

ud2 는 ‘잘못된 연산 코드(invalid opcode)’ 예외 발생을 아키텍처 차원에서 보장하는 명령어로, 일부 컴파일러는 도달해서는 안 되는 코드가 실행될 때 프로그램을 중단하는 데 사용함 이름에 2가 붙은 이유는 기존 바이트 시퀀스 0F FF와 0F B9에 각각 ud0, ud1이라는 이름이 소급해서 붙었기 때문임 도입 경위는 추정에 따른 재구성으로, 프로그램들이 기존 미정의 연산 코드의 예외 발생 동작에 의존하면서 Intel이 영구적으로 유효하지 않은 명령어를 공식 지원하게 됐을 가능성이 있음 ud2는 피연산자가 없는 2바이트 명령어이므로, ud0와 ud1처럼 사용하지도 않을 피연산자를 디코딩할 필요가 없음 ud0와 ud1은 피연산자 디코딩이 존재하지 않는 페이지로 넘어가면 접근 위반을 일으킬 수 있어, 예외 동작이 일관되고 아키텍처로 보장되는 ud2를 쓰는 편이 좋음 ud2의 역할과 컴파일러의 사용 방식 ud2 는 x86 컴파일러 출력이나 API 우회(detour)를 시도한 소프트웨어의 충돌을 조사하는 과정에서 접할 수 있는 명령어임 아키텍처상 미정의 명령어로, 잘못된 연산 코드 예외를 반드시 발생시킴 일부 컴파일러는 도달 불가능한 코드를 표시하기 위해 이를 생성함 실행이 해당 위치에 도달하더라도 임의의 명령어를 실행하는 대신 충돌하도록 함 예를 들어 [[noreturn]] 함수 호출 뒤에 ud2를 넣으면, 함수가 예상과 달리 반환하더라도 다음 함수로 실행이 흘러가지 않고 프로그램이 충돌함 기존 바이트 시퀀스에서 공식 명령어로 이어진 경위 다음 도입 경위는 확정된 역사 기록이 아니라 추정에 따른 재구성임 초기 x86에는 아키텍처 차원에서 지정한 미정의 명령어가 없었으므로, 예외를 강제로 발생시키려는 개발자들은 안정적으로 예외를 일으키는 바이트 시퀀스를 찾았을 것으로 추정됨 한쪽은 0F FF를, 다른 쪽은 같은 성질의 0F B9를 발견했을 수 있음 두 방식 모두 작동하는 듯했고 서로에게 불이익을 주지도 않아, 어느 쪽을 써야 하는지를 두고 크게 다툴 이유는 없었음 두 시퀀스는 내부적으로 레지스터 목적지와 레지스터/메모리 소스라는 두 피연산자를 받는 것처럼 디코딩됨 다른 동작보다 먼저 예외가 발생하므로 피연산자 자체는 사용하지 않음 Intel의 후속 프로세서 개발 과정에서 기존 동작에 대한 소프트웨어 의존성이 드러났을 가능성이 있음 0F FF를 새 명령어에 할당했거나, 여전히 미정의 상태이지만 예외 대신 ...

Read Entire Article