아래 코드를 실행하면 놀랍게도..
입력된 숫자에 대한 팩토리얼 값이 출력된다. 단, 플랫폼은 x86 한정으로..;;
(뭐, 컴퓨터가 돌아가는 원리를 아는 사람이라거나 맨날 기계어 코드 들여다보는 게 직업인 사람이라면 전혀 새삼스러운 일이 아니겠지만)
비주얼 C++뿐만이 아니라 도스용 DJGPP로도 프로그램이 잘 동작하는 걸 확인했다. 둘 다 IA32 아키텍처인 건 동일하니까 이는 당연한 귀결.
int main(int argc, char* argv[])
{
BYTE instrs[]={
0x55,
0x8B,0xEC,
0x83,0xEC,0x08,
0xC7,0x45,0xFC,0x01,0x00,0x00,0x00,
0x8B,0x45,0xFC,
0x89,0x45,0xF8,
0xEB,0x09,
0x8B,0x4D,0xF8,
0x83,0xC1,0x01,
0x89,0x4D,0xF8,
0x8B,0x55,0xF8,
0x3B,0x55,0x08,
0x7F,0x0C,
0x8B,0x45,0xFC,
0x0F,0xAF,0x45,0xF8,
0x89,0x45,0xFC,
0xEB,0xE3,
0x8B,0x45,0xFC,
0x8B,0xE5,
0x5D,
0xC3
};
PVOID pv = instrs;
int (*pfn)(int) = reinterpret_cast<int (*)(int)>(pv), y;
while(1) {
printf("? "); scanf("%d", &y); if(y<1) break;
printf("%d\n", pfn(y));
}
return 0;
}
프로그래밍 언어의 인터프리터 내지 just-in-time 컴파일러를 만든다거나,
가상 기계 에뮬레이터를 만드는 것은 어렵지 않다.
결국 핵심이 뭐냐 하면 컴퓨터가 직통으로 실행하는 코드 자체를 실행 시간에 메모리에다 생성하는 건데,
함수 포인터가 가리키고 있는 게 바로 저런 것들이다.
물론, 위에서처럼 실행해야 할 코드가 완전히 고정돼 있는 경우라면
소스 코드에다 인라인 어셈블리를 집어넣으면 되겠지만, 그 코드는 데이터 영역에 들어가는 게 아니라 소스 코드(text) 영역에 그대로 포함되어 버리게 될 것이다.
위의 팩토리얼 함수는 물론 컴파일러가 생성해 준 코드를 복사한 것이다.
최적화를 안 한지라, 간단한 for 루프 하나밖에 없는 함수가 코드 길이가 꽤 길다.
최적화를 하고 나면 정상적인 함수 입출력 껍데기에 해당하는 코드조차도 거추장스러운지 생성되지 않아서
그걸 저렇게 따로 떼어내서 쓸 수가 없었다.
Posted by 사무엘