윈도우 운영체제가 인식하는 실행 파일 포맷인 PE(portable executable)의 헤더를 보면,
이 EXE/DLL이 실행되는 플랫폼(x86, x64, IA64 등등)이라든가, 이 실행 파일의 특성을 나타내는 플래그 등 여러 정보가 존재한다.
그런데 그 플래그 중에는 'Large address aware' 여부를 나타내는 플래그가 있다.
이건 무엇을 뜻하며, 왜 만들어진 것일까?

윈도우 NT는 도스의 잔재 없이 처음부터 순수 32비트로 개발된 운영체제이다.
32비트 공간에서는 최대 2^32 = 4GB 크기의 가상 메모리를 사용할 수 있는데, MS는 전통적으로 하위 2GB는 응용 프로그램이, 상위 2GB는 커널이 사용하는 구도로 운영체제를 설계했다.

그때는 램은커녕 하드디스크 용량도 4GB보다 훨씬 적던 시절. 그러니 그때 32비트는 가히 무한대에 가까운 공간이었으며, 메모리 분배를 어떻게 한다고 해도 이상할 게 없었다.
응용 프로그램은 언제나 하위 2GB만을 사용하다는 게 무슨 뜻일까?
포인터에서 32비트 크기가 다 쓰이는 게 아니라, 최상위 1비트는 절대로 1이 될 일이 없다는 말이다.

그래서 일부 잔머리 잘 굴리는 프로그래머들은 포인터에다가도 자신만의 1비트짜리 boolean 정보를 최상위 비트에다 얹고, 포인터를 쓸 일이 있으면 그 값을 잠시 제거한 후 사용했다고 한다. 흠좀무.

그런데 세상이 변해서 이제 램이 기가바이트급 스케일이 되었고, 32비트 공간만으로는 부족한 시대가 왔다. 본격적으로 64비트 시대가 도래하기 전부터 데이터베이스처럼 아주 memory-intensive한 프로그램을 돌리던 업계에서는, 유저와 커널을 2:2로 가르지 말고 3:1로 갈라서 응용 프로그램에다가 메모리를 좀더 많이 얹어 달라고 MS에다 끊임없이 요구했다. 그래서 MS는 '물리 주소 확장' 모드라는 걸 만들어 줬다.

사실, 커널도 메모리, 좀더 정확히 말하면 주소 공간이 의외로 많이 필요하다. 2:2도 오히려 부족한 감이 있다. 커널 코드를 얹고 각종 커널 오브젝트를 관리하는 메모리만 필요한 게 아니기 때문이다. 가상 메모리라는 시스템은 그 개념상 메모리를 관리하기 위한 메모리도 요구하는 법. 그와 관련되어 방대한 공간이 필요하며, 디바이스 드라이버를 얹고 돌리기 위한 메모리 등등도 따지면 결코 만만한 수준이 아니다.

3:1로 가르면 응용 프로그램이야 사용 가능한 메모리가 좀더 늘며, 종전에는 응용 프로그램이 한번에 약 1GB 남짓밖에 매핑을 못 하는 memory mapped file도 훨씬 더 큰 크기까지 확장할 수 있다. 하지만 만들 수 있는 프로세스/스레드 수가 감소하며 네트웍이라든가 운영체제의 전반적인 기능상의 한계가 매우 커지고, 운영체제가 이론적으로 관리 가능한 총 물리 메모리의 양도 줄어든다! 이 tradeoff를 반드시 잊지 말아야 한다.

그런데 문제는...
그렇게 3:1로 응용 프로그램의 메모리 주소를 확장하면...
드디어 최상위 비트가 1인 포인터 값이 응용 프로그램으로 오는 게 가능해진다는 것.
그렇다면, 예전에 놀고 있던 최상위 비트를 다른 용도로 활용하던 프로그램을 이런 확장 환경에서 돌리면.....;;; 더 이상의 자세한 설명은 생략한다.

그래서 호환성을 목숨처럼 1순위로 강조하는 MS는, 아무 프로그램이나 일방적으로 넓어진 포인터를 주는 게 아니라, 넓어진 포인터를 줘도 안전하다고 플래그가 따로 지정되어 있는 프로그램에 대해서만 제 기능을 다하도록 하는 정책을 선택했다. 그것이 바로 large address awareness이다. 이 플래그가 없이 빌드된 프로그램은 여전히 메모리를 2GB씩밖에 못 쓴다. 마치 윈도우 XP 이후에도, 별도의 매니페스트를 내장하고 있지 않은 옛날 프로그램들은 비주얼 스타일 테마가 적용되지 않는 것과 같은 맥락으로 말이다.

단, 이건 EXE에 한해서이다. DLL은 그런 선택의 권리가 없다. 확장 주소가 지원되는 EXE에 붙을 수도 있고 지원 안 되는 EXE에 붙을 수도 있으며, 어느 때건 동작을 잘 해야 한다. 따라서 DLL은 반드시 확장 주소를 지원하도록 작성되어야 한다.

본격적으로 64비트 환경이 되면서 확장 주소의 진정한 의미가 드러났다. 이제는 상위 1비트 정도가 아니라 아예 테라바이트급 메모리 주소에도 접근 가능해야 하며, 64비트 프로그램은 '확장 주소 지원' 플래그가 반드시 있어야 한다. 이 플래그가 없으면, 비록 x64 내지 IA64 아키텍처용으로 만들어진 64비트 프로그램이라 할지라도 포인터의 주소로는 여전히 무려 2GB 이내의 값만 들어온다. -_-
포인터 크기를 4바이트 int 크기로 하드코딩하고 제작된 무개념 프로그램을 최대한 쉽게 64비트로 포팅할 수 있게 배려한 것이다. 물론 이 역시 EXE에 한해서이지만 말이다.

large address aware 옵션은 비주얼 C++의 x86 플랫폼에서는 호환성 차원에서 디폴트로 꺼져 있다. 즉, 사용자가 별도로 옵션을 켜지 않으면, 2GB까지만 인식하는 프로그램을 만든다.
하지만 x64/IA64 플랫폼에서는 사용자가 별도로 이 옵션을 끄지 않으면 디폴트로 켜져 있으며, 코드가 2GB 정도가 아니라 4GB 이상의 공간도 안전하게 인식하는 것으로 간주한다. 둘이 묘한 차이가 있다는 것을 기억하자.

물론 굳이 램이 4GB가 아니더라도 64비트는 CPU가 한번에 정보를 처리하는 단위 자체가 더 크다는 점 하나만으로 32비트보다 대용량 데이터를 처리하는 성능이 더 뛰어나다. double 실수형을 하나 스택에 얹을 때만 해도 32비트에서는 CPU 명령을 최소 둘 이상 써야 하는데 64비트에서는 한 번만에 끝난다는 소리이지 않은가. 그렇기 때문에 램 용량이 32비트 크기를 초과하기 전부터도 64비트 프로세서가 개발되어 일부 제한된 영역에서 쓰이기도 했던 것이다.

잘 알다시피 64비트 윈도우는 과거 16-32비트가 그랬던 것처럼 그 정도로 지저분한 호환 계층은 제공하지 않으며, 한 프로세스 공간에 64-32비트 코드가 공존하는 것을 허용하지 않는다. 그래도 윈도우 핸들값은 여전히 32비트 범위 안에만 존재하며 32와 64비트가 값을 그대로 공유 가능하다는 게 신기하다. 하긴, 윈도우 9x에서는 윈도우 핸들값이 아예 16비트 범위에 있었지만 말이다. ^^ 썽킹이라는 말도 참 오랜만에 다시 듣는다.

Posted by 사무엘

2010/04/12 09:12 2010/04/12 09:12
, ,
Response
No Trackback , 9 Comments
RSS :
http://moogi.new21.org/tc/rss/response/242

Trackback URL : http://moogi.new21.org/tc/trackback/242

Comments List

  1. 땅콩맨 2010/04/12 09:32 # M/D Reply Permalink

    실행파일의 새로운 면모를 다시금 확인하게 되었네요. ^^
    좋은 글 감사합니다.

  2. 김기윤 2010/04/12 09:34 # M/D Reply Permalink

    이쪽 이야기는 언제나 재밌군요 ^-^

    앞으로도 사용할 용량은 계속 커질테니 언젠가는 128비트 운영체제가 나올지도 모를 일이죠 (..)

    뭐, 물론 7~15년 정도 뒤의 일이겠지만..

  3. 사무엘 2010/04/13 09:43 # M/D Reply Permalink

    윈도우 말고 다른 운영체제들도 발전사라든가 과거의 흑역사, API 구조 같은 걸 공부하면 재미있는 게 많을 텐데 하는 궁금증도 들더군요.
    그나저나 과연 64비트 공간마저 부족해질 날은 지구가 멸망할 때까지 과연 오긴 할까 궁금..;;
    64비트 포인터는 상위 1비트 정도가 아니라 최소 바이트나 워드 단위로 아직 쓰이지 않고 있기 때문에, 그 공간을 갖고 잔머리 굴리는 프로그래머도 있을 겁니다. ^^

    1. 아라크넹 2010/04/16 17:14 # M/D Permalink

      리눅스의 경우 2.6 전까지 운영체제 차원에서 쓰레드를 지원하지 않았던 흑역사가 있습니다. 대신 clone 시스템 콜을 써서 주소 공간을 공유하는 경량 프로세스로 쓰레드가 구현되었죠.

  4. 주의사신 2010/04/16 20:09 # M/D Reply Permalink

    windows에서 호환성과 관련하여 하나 재미있는 일화를 소개하자면은요(뭔가 얘기하면 다 알고 계셔서 가끔은 얘기하기 겁난다는...).

    dos에서 windows 3.1로 넘어갈 적에 MS에서 호환성 검사를 하느라고, 구할 수 있는 프로그램은 다 구해서 돌려보는데, 심시티는 매번 죽더랍니다.

    그래서 심시티를 역어셈블링해서 보니까, dos에서는 메모리에 직접 접근이 가능하다는 사실을 이용해서, 메모리를 잡고 사용하고 해제한 후에, 바로 그 주소를 다시 할당해서 사용하는 방식으로 구현이 되어 있음을 알아냈다고 합니다.

    그래서 windows 3.1에서 심시티가 돌아갈 때에는 그 방식을 에뮬레이팅 하는 방식으로 해결해 돌아가게 해 주었다고 합니다.

    아마 이런 노력이 있었기에 지금의 윈도우 제국이 있는듯합니다.

    1. 아라크넹 2010/04/17 14:54 # M/D Permalink

      생각보다 그러는 케이스가 꽤 많습니다. 레지스트리 편집기에서 "Compat"가 들어가는 키 찾아 보면 꽤 있죠. 이를테면 IE, DirectX, Windows 모두 호환성을 위한 별도 리스트가 몇 개씩 있습니다.

  5. 사무엘 2010/04/16 23:55 # M/D Reply Permalink

    아라크넹: 그쪽은 원래부터 워낙 스레드보다는 프로세스 찍어내길 좋아했던 곳이니까...

    주의사신: 저도 옛날에 비슷한 얘기를 들었던 것 같습니다. MS는 충분히 그런 짓 하고도 남을 곳입니다.
    한글 입력기 개발자로서 저의 경우를 첨언하죠. 과거 윈도우에 TSF 시스템을 구현한 DLL 내부를 들여다보면 netscape는 물론이고 무려 webeditor.exe (나모 웹에디터!!) 같은 문자열도 들어있습니다. TSF의 전신이자 MS의 흑역사라 할 수 있는 글로벌 IME를 지원하던 극소수의 프로그램을 따로 배려한 조치였던 것 같습니다. EXE 파일 이름을 식별해서 말이에요.

  6. 김 민규 2010/04/17 20:01 # M/D Reply Permalink

    저는 이번 학기에 컴퓨터 구조라는 과목을 배웁니다.
    레지스터, 어셈블리, 등등...
    안배웠으면 이 글이 무슨 말 하는지 몰랐겠죠. 아는 만큼만 보이니까...

    재밌네요. 그렇게 잔머리를 굴려서 한 비트씩을 자기꺼로 사용하고..
    굳이 그렇게까지 안 해도 될 것 같은데..ㅋ 나름의 사정이 있었을까요.

    1. 사무엘 2010/04/18 23:13 # M/D Permalink

      공돌이 암흑의 세계로 한발 한발 깊이 들어오시는군요. ^^;;
      다른 언어들보다도 특히 C/C++은 컴퓨터 구조를 잘 알아야 제대로 써먹을 수 있는 언어입니다. 뉴비 프로그래머에게 포인터가 어려운 존재인 이유도 딴 게 아니라 컴퓨터 자체의 내부 동작 방식을 몰라서이죠.

      "화장실에서 최후의 한 방울까지 철저히 관리하라"도 아니고 저 때는 메모리가 부족해서 "최후의 한 비트도 낭비하지 말라" 였던 것 같습니다. ㅋㅋ

Leave a comment
« Previous : 1 : ... 2003 : 2004 : 2005 : 2006 : 2007 : 2008 : 2009 : 2010 : 2011 : ... 2204 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

Site Stats

Total hits:
3050469
Today:
1489
Yesterday:
2142