본인은 내 연배 사람들의 평균 이상으로, 심지어 나보다 나이가 더 많은 사람들 이상으로 레트로 컴퓨팅에 관심이 많다. 그 이유는.. 글쎄, 그 시절 당대엔 너무 비싸서 만져 볼 엄두를 못 냈던 최신 최고급 최첨단 하드웨어와 소프트웨어들이 지금은 너무 값싸지고, 싸구려를 넘어 역사 속의 퇴물이 된 게 경이롭고 신기하게 느껴지기 때문인 것 같다.

어린 시절에 굶주림을 겪었던 기성세대들이 지금 이렇게 먹거리가 싸고 풍부해진 뒤에도 늘 절약하고 비상시를 생각하고 많이 쌓아 놓는 습관을 평생 못 버리는 편이라지 않는가?
그런 것처럼 본인은 어린 시절에 저런 식으로 최신 문물의 이기에 대한 욕구불만(?)을 겪었던 게 지금 이런 추억과 집착으로 표출되는 것 같다. 나 자신에 대해 스스로 생각해 보니 그렇게 느껴진다.

1. 메모리

16비트 컴퓨터는 8비트보다야 훨씬 더 풍족한 환경이다. 특히 한글· 한자 같은 복잡한 문자까지 실용적인 해상도로 표현할 수 있을 정도로 성능이 받쳐 주는 마지노 선이기도 하다. CPU 속도뿐만 아니라 메모리(폰트..)나 그래픽(해상도)에서도 말이다.

하지만 컴퓨터 성능이 좀 더 향상되자 16비트도 금세 한계를 보였다. 16비트는 그 특성상 가깝게는 64KB, 그리고 x86 PC 기준 거시적으로는 1MB / 640KB의 한계에 매여서 이걸 극복하느라 온갖 지저분하고 복잡한 편법이 동원되어야 한 암울한 환경이기도 했다.
세그먼트가 어떻고 메모리 모델이 어떻고 far 포인터가 어떻고..;; 그리고 EMS는 뭐고 XMS는 뭐냐. x86 PC 말고 다른 16비트 CPU 동네에서는 상황이 어땠는지 개인적으로 매우 궁금하다.

EMS는 뭔가 특수한 방법으로 접근하는 부가적인 메모리를 장착해서 1MB 이상의 물리 메모리를 확보하는 방식이었다. 글쎄, EMM386이라는 도스 드라이버 이름이 암시하는 것과는 달리, 얘가 XT 시절부터 먼저 등장했다.
그러다가 80286 CPU의 기능을 활용해서 XMS라는 규격이 추가로 등장했다. 얘가 진짜로 더 자연스럽고 직관적인 방식으로 주 메모리의 연장선상으로 메모리를 더 확장해 준다.

사용자 삽입 이미지

MS-DOS 5.0에서 himem.sys라는 드라이버가 추가됐는데 이건 그냥 이유 불문하고 필수 로딩 드라이버였다. 그리고 DOS=HIGH니 LOADHIGH (LH)니, 뭔가 HI/HIGH가 붙은 게 그야말로 640KB 기본 메모리를 확보하기 위한 마법의 주문인 것처럼 컴퓨터 잡지에서 소개되곤 했다.
1MB 이상 메모리를 확보하는 것 자체는 가능했지만 현실에서 컴퓨터가 정보를 직통으로 취급하는 최소 단위는 여전히 64KB였고, 그나마도 접근성이 제일 좋은 영역은 1MB에서 그나마 384KB를 떼어낸 하위 640KB였기 때문이다. 뭐가 이리 복잡해..

정리하자면 EMS가 먼저 등장했고, 그 다음이 XMS이다. EMS는 확장 메모리를 반쯤 파일처럼 취급하는 방식인 반면, XMS에서는 같은 16비트이지만 286 CPU의 기능을 활용해서 확장 메모리에 CPU가 직통 접근 가능해졌다. 그리고 기존 도스용 프로그램이나 드라이버를 640KB 이후의 상위 영역에다가 올려 놓는 기법도 XMS와 함께 등장했다.
메모리 운용 방식이 까탈맞은 게임 중에서는 emm386 구동 절대 금지, 또는 반대로 EMS 필수.. 이러는 경우가 있었다. 이러니 config.sys 내용이 걸레짝처럼 복잡해질 수밖에 없었다. 도스 6.0에서는 멀티부팅이라는 기능까지 등장했고 말이다.

물론 어떤 경우에든 640KB 이전 기본 메모리를 최대한 많이 확보해 놓는 건 필수였다. 이게 마치 Windows 3.x 리소스 퍼센티지와 비슷한 개념이었다. 부팅 직후에 580~600KB 정도 남아 있으면 최적화를 아주 잘 한 것이었는데.. 한글 바이오스, 씨디롬, 디스크 캐시 같은 것들을 띄우다 보면 메모리가 금세 뚝뚝 줄어들었다.

이런 복잡한 메모리 삽질은 386 이상 CPU에서 제공하는 보호 모드, 가상 메모리 기능과 함께 역사 속으로 사라졌다. DPMI는 EMS/XMS 따위보다 더 상위 기술을 명시하는 규격이다. 32비트 도스 extender가 그 시절엔 정말 구세주 소리를 듣지 않을 수 없었다. 1990년 중반대의 도스용 게임을 실행할 때 DOS/4G 시그널이 뜨는 게 정말 간지 그 자체였다. ^^

2. 도스용 디바이스 드라이버(sys)

도스 시절에는 컴퓨터에 어떤 하드웨어를 인식시키기 위해서 해당 장치의 드라이버를 실행해서 올리는 절차가 있었다. config.sys라는 시작 스크립트에다가 DEVICE=어쩌구저쩌구 드라이버 파일 경로를 지정해 주면 됐다. 이건 무려 MS-DOS 2.0 시절부터 있었던 전통이라고 한다.

여기서 개인적으로 의문이 들었다. DEVICE로 로딩되는 *.sys 드라이버들은 분명 컴파일된 기계어 코드가 들어있는 실행 파일의 특수한 형태일 텐데.. 얘는 어떻게 만드는 걸까?
옛날 자료를 뒤져 보니 1980년대에 MS C 4.0 (!!! Visual C++ 4가 아님!)과 매크로 어셈블러를 써서 빌드하고 만든 경우가 있었다고 한다. ㄲㄲㄲㄲㄲㄲ
com과 비슷한데 그래도 자그마한 헤더가 들어있으며, 나름 한 sys 파일 안에 2개 이상 여러 드라이버가 있을 수도 있었나 보다.

config.sys는 부팅 때 단 한 번만 실행됐다. 부팅이 끝난 뒤에 얘들을 다시 실행하거나, 실행된 디바이스 드라이버를 제거할 수 없었다. 그러니 다루기가 좀 불편하다.
그 시절엔 부팅 후에 sys 파일을 실행해 주는 별도의 유틸리티가 있었다. 얘는 어떤 원리로 동작했는지 모르겠다만, 개인적으로 유용하게 썼던 기억이 남아 있다.

그리고 시스템을 건드리는 유틸이 처음엔 sys 형태로 개발되었지만 나중에 exe 형태로 바뀐 경우도 종종 있었다.
emm386 드라이버가 대표적인 예이고(DOS 4.0에서는 sys, 5.0 이후부터 exe), 디스크 캐시라든가 램 드라이브, 각종 한글 바이오스 소프트웨어도 1980년대엔 sys이다가 나중에 com/exe 기반의 램 상주 프로그램으로 바뀌었다.
마우스 드라이버는 sys였던 적이 없이 전통적으로 mouse.com이었던 것 같고..;; 그때는 msherc나 simcga처럼 그래픽 카드를 흉내 내는 램 상주 드라이버도 있었다.

나중에 Windows 9x 시절에는 vxd라는 드라이버가 있었는데 NT 계열부터는 소리 소문 없이 사라졌다.
도스용 아래아한글이나 이야기(PC통신!!)에서 쓰였던 덧실행 프로그램도 뭔가 특수하게 빌드된 프로그램이지 싶은데..
이렇게 기계어 코드를 생성하는 계층이랑, 껍데기 실행 파일을 생성하는 계층이 같지 않으니 컴파일러와 링커의 계층이 구분되었던 것 같다. 마치 압축 알고리즘과 컨테이너 구조의 차이와 비슷하다.

3. PC 스피커로 현실 사운드 흉내 내기

오늘날 우리가 사용하는 PC의 원조인 IBM PC라는 건 원래 업무용으로 개발됐다. 이 때문에 그래픽이나 사운드 쪽 지원은 원가 절감을 위해 우선순위에서 밀렸으며, 당대의 타 컴퓨터들에 비해 스펙이 뒤쳐졌다.
그래픽이야 초창기 CGA니 EGA니 하던 IBM 보급품이 얼마나 열악했는지는 더 설명이 필요하지 않고.. 사운드도 상황이 다르지 않았다. PC 스피커라고 불리던 IBM 보급품은 그냥 삑삑 띡띡거리면서(beep) 오류가 발생했을 때 최소한의 자기 상태만 청각 피드백으로 전달할 수 있는 정말 원시적인 물건이었다.

자연에서 발생하는 소리는 아무래도 부드러운 삼각함수 곡선의 합성으로 표현된다. 허나, 이 PC 스피커는 얼마나 단순했으면 생성 가능한 소리의 파형이 최대값 아니면 최소값으로 이산적-_-이었다. 음량을 나타내는 진폭조차 조절이 안 되고.. 진짜 그 특유의 날카롭고 투박한 비프음밖에 내지 못한 것이다. 자연스러운 삼각함수이면 소리굽쇠나 전화기 신호음 비슷한 소리라도 났을 텐데, 그렇지도 않다. ^^

그런데 1980년대 말에는 RealSound라고 PC 스피커를 극한까지 튜닝해서 얘만으로 최소한 단음 멜로디보다는 더 정교한 소리를 내는 기법이 개발되어 쓰였다고 한다. 단순투박한 비프음이라도 다양한 주파수로 아주 잘게 쪼개고, 이것들을 합성해서 또 다른 소리를 만들어 내는 거다. 이미지에서 디더링의 사운드 버전이나 마찬가지다.

이렇게 해서 표현 가능한 음질은 채널은 당연히 모노 한정이고, sampling rate는 11khz와 22khz의 중간인 18khz 남짓이었다고 한다. 그 시절 컴퓨터 사양을 감안하면 나쁘지 않았다.
다만, 문제는 표현 가능한 음색이랄까 이거 구분이 6비트밖에 안 됐다는 거..

아까 오리지날 PC 스피커는 최대값 아니면 최소값 2단계뿐이니 1비트인데, 이걸 딱 32배까지 늘리는 게 한계였다.
실용적인 사운드 카드에서는 최저 음질이 8비트부터(256) 시작이고 CD급 음질이라면 16비트가 보통인데 6비트는 확실히 자연스러운 소리를 재현하기에는 부족한 음질이었다.

이걸로 청취 가능한 사람 목소리를 낼 수는 있었다. 하지만 칙칙한 금속 기계음이 섞인 저음 남자 목소리 정도나 내며, 유선 전화기보다도 음질이 안 좋았다. 그냥 전용 사운드 카드로 음질 더 좋은 사운드를 내보내는 것보다 CPU에 걸리는 부하도 더 컸을 것이다.

하지만 비싼 사운드 카드 없이 보급 PC 스피커만으로 삑삑 단음이 아니라 사람 목소리 비스무리한 거, 툭툭 소리, 비트가 가미된 테크노 BGM이 흘러나오는 것만으로도 어디냐. (☞ 예시 1 / 예시 2)
PC 스피커로 사운드 카드 흉내를 내는 기술은 소수의 게임이나 유틸에서 알음알음 전수되어 쓰였던 것 같다. 그래픽 분야로 치면 VGA mode X라든가 CGA 160*100 16컬러 같은 꼼수와 비슷해 보인다.

4. 텍스트 모드 폰트

1980년대에 PC의 그래픽 카드는 CGA, EGA를 거쳐 VGA로 업그레이드 됐다. 그 과정을 거치면서 그래픽 모드의 해상도가 올라가고 지원되는 색깔 수가 늘었다.
덕분에 그래픽이 아닌 텍스트 모드에서도 자그마한 8*8 폰트를 동원해서 종전의 25줄이 아니라 43/50줄을 표시할 수 있게 됐다.
하긴, 요즘이야 큼직한 화면에서 70~80줄도 한번에 보면서 코딩을 하는데.. 꼴랑 25줄은 화면이 작아도 너무 작다.;;;

이렇게 색깔과 해상도가 올라간 거야 수긍이 가는 변화인데, 이것 말고 EGA/VGA가 과거의 CGA에 비해 향상된 게 더 있었다. 바로 텍스트의 폰트를 customize할 수 있게 된 것이다.
CGA에서는 그 알량한 폰트가 ROM에 박혀 있었던 반면, EGA/VGA에서는 이게 가변적인 RAM 영역으로 옮겨졌다. 정확하게는 자기네 ROM으로부터의 복사본이겠지만..

이 덕분에 몇몇 창의적인 프로그램들은 비록 텍스트 모드에서 돌아가지만 128번 이후의 특수문자들을 마개조해서 GUI 비주얼을 얼추 구현할 수 있었다. 도스용 Norton 유틸리티가 대표적인 예다.

사용자 삽입 이미지

체크나 라디오 버튼, 스크롤바 버튼을 그럴싸하게 그려 넣는 건 기본이고, 더 압권인 건 마우스 포인터까지 그래픽 모드처럼 구현했다는 것이다. 당장 위의 스샷을 보시라~! 지금 저건 텍스트 모드인데도 말이다!!
마우스 포인터가 차지하는 4개 영역에는 기존 문자에다가 마우스 포인터를 위치별로 합성한 4개 문자를 실시간으로 생성해서 그때 그때 바꿔 준 것이다. 이게 그 당시 하드웨어로 어떻게 가능했는지 모르겠다.;;

이런 비디오 마개조는 한글 바이오스 같은 프로그램과는 당연히 상극이었기 때문에 같이 사용할 수 없었다. 그러고 보니..

  • VGA에서 텍스트 모드의 해상도는 640*400이 아니라 720*400이었다. 폰트는 8*16 것을 쓰지만 글자 사이에 1픽셀 여백이 있었다. 단지, 몇몇 선문자는 예외적으로 그 여백 부분까지 픽셀을 채웠기 때문에 선이 한데 이어져서 보였을 뿐이다.
  • VGA 텍스트 모드에서는 글자색은 16개가 지원됐지만 배경색은 기본적으로 어두운 계열 8개만 지원됐다. 그러고 글자색을 깜빡거리게 하든지, 아니면 깜빡이지 않는 대신 밝은 계열 배경색 8개를 추가로 사용할지를 무슨 API를 통해 지정할 수 있었다. 참 신기한 형태의 설계이다.
  • VGA가 아니라 모노크롬 MDA 시절에는 색깔이 없는 대신 글자에 진하게, 밑줄 같은 속성을 줄 수 있었고..ㄷㄷㄷ
  • 그런데 개인적으로 텍스트 모드에서 이런 색깔 장난질을 할 수 있었던 언어는 베이식밖에 없었다. C/파스칼엔 텍스트 색깔 지정과 관련된 표준 API가 없었기 때문이다. (3rd party 라이브러리를 써야..)

Posted by 사무엘

2023/08/22 08:35 2023/08/22 08:35
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/2198

1. 32비트 컴파일러: 16비트 메모리 접근의 한계를 극복하기

예전에도 언급한 적이 있지만.. 1993년 말에 발매되었던 Doom 게임은 그야말로 충격적인 3차원 그래픽 덕분에 게임 업계에 큰 충격을 선사했다. 업계 종사자들은 기술 수준 자체뿐만 아니라 "얘는 어셈블리어를 거의 사용하지 않고 순수 C만으로 개발되었습니다"라는 존 카맥의 말에 더 큰 충격을 받게 됐다.

훗날(1997년) Doom의 소스 코드가 공개되면서 이 말은 사실임이 밝혀졌다.
Doom은 무슨 16비트 Windows 같은 쑤제 어셈블리어 튜닝 위주로 개발된 게 아니라, Windows NT처럼 굉장히 이식성 있게 개발되었다. 그러니 Doom 엔진 기반의 수많은 게임과 mod들이 온갖 플랫폼으로 이식되어 만들어질 수 있었다.

단지, 오리지널 도스용의 경우, 컴파일러를 그 당시에 흔하던 볼랜드나 MS 같은 16비트용을 쓴 게 아니라 Watcom이라는 다소 생소한 32비트 고성능 제품을 썼을 뿐이다.
그리고 어셈블리어를 안 쓰더라도 고정소수점이라든가, IEEE754의 특성을 이용해서 3차원 그래픽용 실수 연산(삼각함수, 제곱근, 벡터 정규화...)을 왕창 빠르게 수행하는 각종 tweak들은 응당 최대한 구사해서 성능을 끌어올렸다.

그러니 Doom은 아직 상대적으로 생소하던 32비트 컴파일러라든가 DOS/4G 도스 익스텐더 같은 물건의 인지도를 끌어올려 줬다. 이렇게 Doom을 통해 Watcom 컴파일러까지 알렸던 id 소프트웨어에서는 훗날 퀘이크를 만들어서 이번에는 오픈소스 진영의 걸출한 도스용 32비트 컴파일러이던 djgpp를 알리게 되었다.

운영체제 자체를 OS/2나 Windows NT처럼 통째로 32비트로 쓰기에는 아직 기계값이 너무 비싸고 특히 메모리가 부족했다. 그러니 도스에서 돌아가는 일부 대형/고사양 프로그램이 자체적으로 도스의 한계를 극복하고 보호 모드로 진입하는 솔루션을 내장했던 것이다.

생각해 보니 국내에서도 아래아한글 2.1이 전문용은 Watcom C/C++을 이용한 32비트 전용으로 만들어졌다. 얘는 발매 시기가 심지어 Doom보다도 3개월 남짓 더 앞섰다(1993년 9월 vs 12월). 그러니, 터보 C, 볼랜드 C++ 하던 그 시절에도 32비트 컴파일러에 대해서 알 사람은 이미 다 알기는 했던 모양이다.

다만, 아직도 286 똥컴이 많이 굴러다니고 서민용 운영체제들은 아직도 16비트 도스와 Windows가 주류인데, 내 프로그램을 386 전용으로 개발하는 것에 대한 득과 실을 신중하게 따져야 했다. 오죽했으면 아래아한글도 후속 버전인 2.5와 3.0에서는 일반용/전문용 구분이 없어지고 그냥 hwp86.exe와 hwp386.exe 두 에디션을 모두 내장하는 것으로 형태가 바뀌었다. 추가 글꼴과 사전 컨텐츠는 '확장팩'으로 분리되고 말이다.

아래아한글은 Phar Lap 도스 익스텐더를 사용했다. 아래아한글이 그 시절의 도스용 게임처럼 DOS/4G(W) 로고를 띄우면서 실행되었다면 무척 볼 만했을 것이다.
86과 386 에디션은 성능 말고는 덧실행 프로그램이 지원되는지의 여부가 가장 큰 차이점이었다. 덧실행은 16/32비트용이 따로 나오지 않고 32비트 전용이었기 때문이다.

화면 보호기들, 그리고 확장팩에서 제공되었던 프라임 영한사전도 다 덧실행 프로그램이었다.
먼 옛날 1.2 시절에는 별도의 액세서리로 테트리스 게임이 있었는데 나중에 그게 덧실행으로 컴백한 걸 보니 개인적으로 감회가 새로웠었다.

이렇게 1990년 중반에 도스용 프로그램들의 32비트화 추세와 달리, 마소는 진작부터 PC에서 도스를 Windows로 대체하려는 큰 그림을 갖고 있어서 그런지.. 도스용으로 32비트 컴파일러를 결코 내놓지 않았다. 정작 자기들은 그 기술을 내부적으로 보유하고 사용했으면서 말이다.
Visual C++ 1.5x는 16비트 도스/Windows 바이너리들을 빌드할 수 있었는데, 명령 프롬프트에서 돌아가는 컴파일러와 링커 같은 툴들은 그냥 32비트 프로그램이 아니라 32비트 PE 기반의 콘솔 프로그램이었다.

Windows NT 같은 데서는 직통으로 실행 가능하고, 도스에서 실행되면 stub으로 embed된 도스 익스텐더가 컴을 보호 모드로 진입시키고 CreateFile/GlobalAlloc 같은 Win32 API를 제공해서 프로그램을 실행했다.
스레드를 만들지는 못했겠지만 컴파일러· 링커가 사용하는 Win32 API야 뭐 파일이나 메모리 I/O 정도밖에 없었을 것이고, 이건 도스 익스텐더가 감당 가능했다. 결국 한 바이너리만으로 도스와 Windows에서 모두 사용 가능.

이건 뭐 콘솔 프로그램계의 Win32s나 마찬가지인 엄청난 기술인데.. 마소의 Visual C++에서 이런 이중 바이너리를 만드는 걸 end-user에게 지원한 적은 내가 알기로 없다.
마치 C# 네이티브 코드 컴파일러만큼이나 대외적으로 공개되지 않고 마소 내부에 봉인된 기술인 것 같다.

2. 슈퍼 VGA 라이브러리: 표준 VGA의 한계를 극복하기

IBM 호환 PC라고 불리는 물건에서 IBM이 주도하는 PC의 단일/표준 규격이라는 건 286 AT 이후로 없어졌다. 그러니 286 이후로 최초의 386 PC는 IBM이 아닌 컴팩에서 출시되기까지 했다.
그리고 그래픽 카드도 절대불변 단일 표준은 1987년의 구닥다리 VGA가 마지막이다. 표준 VGA는 800*600 해상도조차 지원하지 않았으며, 그나마 색깔이 아쉬운 대로 다양해진 256색은 겨우 320*200에서밖에 지원되지 않아서 업무라기보다는 그냥 게임 전용 모드로만 쓰였다.

그 뒤로 VGA보다 더 높은 해상도와 더 많은 색상을 지원하는 규격은 그야말로 온갖 싸제 SVGA 제조사들이 난립하면서 파편화 천국이 됐다. VESA 같은 규격이 괜히 필요해진 게 아니다.

이게 불과 1990년대 초반의 일이니, 앞에서 언급한 보호 모드가 어떻고 DPMI가 제정되던 때와 시기적으로 비슷하다. 하긴, 1990년에 나온 그 옛날 프로그램인 Deluxe Paint조차도 처음 실행될 때 맨 아래에 1024*768 256색 SVGA 모드가 있긴 했다. 물론 당대에 그걸 선뜻 고를 수 있을 정도의 금수저 컴퓨터를 소유한 사용자는 매우 소수였을 것이다.

마소의 베이직 컴파일러야 SCREEN 명령으로 SVGA 지원은 전무했다. API 구조가 완전히 다른 3rd-party 라이브러리를 구해서 써야 했다.
볼랜드의 경우는 상황이 약간 낫다. 비록 자체적으로는 VGA까지밖에 지원하지 않았지만, 일종의 그래픽 드라이버인 bgi 파일이 내부 스펙이 공개돼 있고 확장 가능했기 때문에 이걸 기반으로 SVGA 라이브러리를 만든 곳이 있긴 했다.

검색을 해 보니 Jordan Hargraphix 소프트웨어가 이 업계의 독자적인 큰손이었던 모양이다. 이미 1991년 무렵부터 유명했다.
바이오스를 거치지 않고 일명 VGA mode X라고 불리는 320*240, 400*300 같은 변형 모드까지 다 지원했다.
그때는 소프트웨어가 잘못된 명령을 내려서 컴퓨터만 뻗게 하는 게 아니라 모니터를 손상시키는 것도 가능했던 시절이다. (주사율 변조..) 옛날에 CGA도 160*100 같은 tweak mode가 있었다고 하는데 그것만큼이나 신기한 일이 아닐 수 없다.

다만, BGI라는 그래픽 API는 무려 1980년대 후반에 개발된 것이며, 아무리 bgi 드라이버를 새 하드웨어에 맞게 확장한다 해도 256색 이상의 색을 지원하는 것은 구조적으로 불가능했다고 한다. 트루컬러 SVGA를 지원하려면 완전히 새로운 독자 라이브러리를 써야 했다.
BGI는 색상을 관리하는 게 RGB값 기반이 아니라 팔레트 인덱스 기반으로 고정돼 있었던 모양인데, 16비트 시절에 이는 충분히 수긍이 간다. 쟤가 무슨 Windows GDI 급으로 하드웨어 통합과 추상화를 표방한 물건은 아니었으니 말이다.

도스용 아래아한글은 16비트 바이너리의 경우 Turbo/Borland 컴파일러로 개발되었다. 하지만 아주 초창기인 1.x 시절부터 그래픽 라이브러리를 독자 구현했는지, 볼랜드의 보급 BGI 라이브러리를 사용한 흔적이 전혀 없는 것이 매우 흥미롭다.
이건 비슷한 시기에 도스용 한메 타자 교사도 마찬가지다. 얘도 MS C로 개발되었지, 의외로 볼랜드 출신이 아니다.

Posted by 사무엘

2019/03/23 08:31 2019/03/23 08:31
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1600

1. COM

1970년대 중반, MS-DOS의 전신격인 CP/M 때부터 있었던 완전 초창기 실행 파일 포맷이다. 고안자는 개리 킬달.
엄밀히 말해, 얘는 파일 포맷이라 할 것도 없는 쌩 메모리 이미지 덤프였다. 그 어떤 고유한 헤더나 메타데이터도 없이 그냥 곧장 기계어 코드와 데이터가 쭉 이어질 뿐이었다. 코드와 데이터는 모두 64KB 단일 세그먼트에 묶여 있었고, 메모리 주소의 첫 256바이트는 시스템 용도로 예약되어 있어서 프로그램이 사용할 수 없었다.

확장자가 com인 실행 파일은 그냥 명령 프롬프트에서 돌아가는 간단한 유틸밖에 없을 것 같지만, 그래도 겨우 몇만 바이트 남짓한 com 형태로 그래픽 모드에서 실행되는 게임도 많이 나왔었다. 그래픽이라고 해 봤자 320*200 4색 CGA 수준이긴 했지만.. Alley Cat처럼 말이다.
1980년대에 들어서 컴퓨터의 대세가 8비트에서 16비트로 넘어가고 성능과 메모리 용량이 향상되자, 이 형식은 큰 프로그램을 만들기에는 너무 비좁아졌다. 그래서 확장할 필요가 생겼다.

2. MZ EXE

1983년, MS-DOS 2.0에서 최초로 도입됐다. 그 전의 1.0은 파일 시스템에 서브디렉터리라는 게 지원되지 않았으며 실행 파일도 아직 COM밖에 없었다.
EXE는 단일이 아닌 다중 세그먼트(특히 코드 영역과 데이터 영역의 분리)를 도입하여 64KB 공간 한계를 얼추 극복했다. 메모리 모델이니, far near 포인터니 뭐니 하면서 일이 굉장히 복잡해지긴 했지만 말이다.
또한, 멀티태스킹 환경에 대비해서 재배치 정보도 도입했다. 이제 좀 운영체제에서 파일을 있는 그대로 메모리에 올리는 게 아니라 최소한의 가공과 상대 주소 보정을 하는 loader가 필요해졌다.

오늘날 모든 EXE들은 앞부분에 MZ라는 문자로 시작하는 간단한 헤더를 갖추고 있다. MZ는 EXE 파일 포맷의 설계자인 당시 마소의 프로그래머 Mark Zbikowski의 이니셜이다! zip 압축 파일의 식별자인 PK (개발자 필립 카츠)만큼이나 세계에서 제일 유명한 파일 포맷 식별자 이니셜일 것이다. MZ 저분은 미국 토박이라고 하지만, 이름으로 보아하니 러시아 계열 이민자의 후손인 듯하다.

비록 도스는 역사 속으로 사라졌지만, Windows용 실행 파일들은 지금까지도 과거 호환을 위해서 앞부분에 최소한의 MZ EXE 헤더 껍데기는 넣어 놓는 게 관행이 돼 있다.
한편, 32비트 이후부터는 프로그램들이 옛날처럼 다시 단일 세그먼트 기반 flat 모델로 돌아갔다. 단지, 그 세그먼트의 이론적 최대 크기가 꼴랑 64KB이던 것이 4GB로 왕창 커졌을 뿐이다.

3. NE (new)

1985년에 발표된 Windows 1.0과 함께 등장한 포맷이다. 도스와는 다른 방식의 API 호출, exe와 dll의 구분, 표준화된 리소스와 버전 정보 데이터, 함수의 import와 export 내역처럼 도스용 exe에는 없던 추가적인 정보가 많이 필요해진 관계로 새로운 실행 파일 포맷을 또 제정한 것으로 보인다. 단, 맨 앞부분은 그냥 도스 EXE처럼 시작하고, 새로운 방식은 다른 오프셋에서부터 시작된다. 이는 NE 다음의 PE도 마찬가지이다.

사실, NE는 Windows뿐만 아니라 마소에서 1986년경에 잠시 만들다 말았던 일명 '멀티태스킹 MS-DOS 4.0'(일반적인 그 MS-DOS 4.0 말고)용 실행 파일 포맷으로도 쓰였다고 알려져 있다. 하지만 도스는 텍스트 기반 환경이지만 Windows는 GUI 환경이고, 16비트 Windows에는 딱히 콘솔(명령 프롬프트)이라는 서브시스템이 존재하지 않았다. 그러니 바이너리 수준에서의 파일 포맷만 일치할 뿐, 양 플랫폼의 실행 파일을 딴 데서 원활하게 실행할 수는 없었을 것이다.

Windows 1.x부터 3.x까지 16비트 시절에 실행 파일 포맷은 크게 바뀌지 않았다. 단, 2에서 3으로 넘어가던 시절에는 Windows에 386 확장 모드라는 게 도입되었기 때문에, 이 프로그램은 종전의 리얼(real) 모드뿐만 아니라 보호(protected) 모드에서도 잘 실행된다는 보증 플래그가 추가되었다. 평범한 Windows API만 쓴 프로그램이 여기에 큰 영향을 받지는 않았겠지만, 그래도 혹시나 해서 말이다.

1980년대 왕창 옛날에 만들어졌던 일부 Windows용 프로그램들은 95뿐만 아니라 3.x에서 실행해도 "구버전용임. 여기서도 일단 실행은 되지만 케바케이기 때문에 온전하고 정상적인 동작을 기대할 수 없음. 최신 버전을 구해서 쓰셈.." 이런 주의 메시지가 뜨는 게 있었는데, 바로 이 플래그가 없이 옛날 방식대로 빌드된 프로그램이어서 그렇다.
특히 대화상자가 캡션(제목 표시줄)이 없이 표시되는 프로그램을 보면 옛날 냄새가 풀풀 난다. 캡션은 popup 윈도우가 아닌 overlapped 윈도우의 전유물이던 시절이 있었기 때문이다.

NE 방식의 실행 파일에는 각종 코드와 데이터, 리소스들이 resident, non-resident, discardable 이런 식으로 속성 구분이 있었다. 컴퓨터에 메모리는 왕창 부족한데, CPU와 운영체제 차원에서의 가상 메모리 지원이 없고, 그 열악한 환경에서 멀티태스킹을 구현하려다 보니, 돌아가는 방식이 가난함과 처절함 그 자체였다.
읽어들인 데이터는 언제든지 주소가 재배치되거나(단편화를 막고 연속된 많은 영역의 메모리를 확보할 수 있게), 삭제되어서 디스크로 되돌아갈 수 있었다. 반드시 메모리에 언제나 불러들여 놓는 데이터는 성능 차원에서 정말 중요한 것에만 한해서 지정해야 했다.

4. PE (portable)

1993년에 등장한 Windows NT 3.1에서 첫 도입된 또 다른 새로운 실행 파일이다. AT&T에서 오래 전에 개발한 COFF라는 오브젝트/라이브러리 파일 포맷의 연장선상에 있다. 아마 Windows NT 개발진의 출신 배경이 그쪽 계열 연구소여서 이런 포맷에 친숙하지 않았나 싶다. 덕분에 마소에서 개발하는 개발툴들은 16비트 시절에는 obj/lib의 포맷으로 인텔에서 개발한 OMF 방식을 썼지만 32비트부터 COFF로 갈아탔다. 그리고 exe/dll을 로딩하는 방식도 쿨하게 memory mapped file 방식으로 바꿨다.

PE는 현대적인 32비트 가상 메모리 환경에 맞춰졌기 때문에, 16비트 NE처럼 수동 메모리 관리를 염두에 둔 지저분한 속성이 존재하지 않는다. 세그먼트 대신에 코드, 데이터, 리소스 등의 용도별 섹션이 있고, 이들 섹션은 간단한 문자열 태그로 구분하기 때문에 섹션의 추후 확장이 가능하다. 그리고 헤더에 CPU 식별자도 넣어서 굳이 x86뿐만 아니라 다른 CPU 아키텍처의 실행 파일도 이 방식으로 기술 가능하게 했다.

훗날 64비트 CPU가 등장하면서, 아니 정확히는 1990년대 말에 IA64의 출시를 염두에 두고 PE의 기본 틀은 동일한데 메모리 주소나 몇몇 size 필드만 4바이트에서 8바이트로 확장된 일명 PE+ 규격이 나왔다. 그래도 기존 32비트에서도 얘를 알아보고 최소한 "에러 메시지+실행 거부" 정도의 대처는 할 수 있다.
리소스는 64비트도 32비트와 바이너리 차원에서 포맷이 완전히 동일하다. 이게 무슨 기계어 코드도 아닌데 필드 크기가 굳이 64비트 크기로 확장됐다거나 한 건 없다. 문자열이 유니코드 기반으로 바뀌었으니 16비트 방식과는 호환되지 않지만 32와 64비트끼리는 호환된다.

오늘날은 재래식 네이티브 코드뿐만 아니라 닷넷 기반(가상 머신), 그리고 UWP용(일명 metro) 앱 같은 것도 나왔지만, 이들도 실행 파일들의 기본 골격은 PE로 동일하다. 그 안에서 읽어들이는 시스템 DLL과 구동 방식이 서로 차이가 날 뿐이다.

Posted by 사무엘

2018/06/17 08:36 2018/06/17 08:36
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1501

1. 도스 시절 명령어

도스에서 파일(과 디렉터리)을 다른 곳에 복사하는 명령은 copy이다. 얘는 명령 셸인 command.com이 자체 지원하는 내장 명령이다.
그런데 도스에는 copy의 일종의 강화 버전이라 할 수 있는 xcopy라는 것도 있으며, 이건 별도의 프로그램을 통해 실행되는 외부 명령이다.

xcopy는 일반 copy와 달리 (1) 서로 다른 드라이브 사이에 서브디렉터리까지 재귀적으로 통째로 복사하는 걸 지원했으며, (2) 복사에 사용하는 메모리 버퍼 크기가 더 크고, 여러 개의 파일을 한꺼번에 읽은 뒤(대략 수백 KB 정도 크기까지) 타겟에다 쓰는 걸 지원했다. xcopy의 전치사 X는 일반적으로 cross라고 발음되었다.

지금 생각해 보면 이 둘은 차별화 요소가 전혀 될 수 없으며 굳이 분리할 필요가 없다. 그냥 copy가 원래 (2)처럼 동작하면 되고, (1)은 /s 같은 옵션을 추가해서 지원하면 될 일이다.
하지만 옛날에 xcopy가 외부 명령으로 존재했던 이유는 겨우 그 정도 고급 복사 옵션/기능마저도 command.com에다 상시 집어넣고 있기에는 메모리가 부족하고 아까웠기 때문이다. 옛날에는 베이직 인터프리터가 Ready 출력할 메모리조차 아까워서 프롬프트를 Ok로 바꾼 시절이 있었다는 것 기억하시는가? (단 3바이트를 아끼려고!) 검색을 해 보니 xcopy는 1987년, MS-DOS 3.2에서 첫 도입됐다고 한다.

하긴, 옛날에는 다단계 디렉터리를 재귀적으로 탐색하면서 뭔가를 하는 일이 쉽지 않아서 외부 유틸리티를 많이 이용해야 했다. 파일 찾기는 말할 것도 없고, 지우는 것도 옛날에는 deltree라는 명령이 따로 있었지 싶다. 그건 지금은 del에 /s옵션으로 통합됐지만 말이다.
유닉스 계열 셸은 내장과 외장 명령어 구분이 어찌 되나 모르겠다. cp, mv, rm은 외부 프로그램인 것 같던데 설마 pwd, cd 이런 것들도 다 외부 프로그램이려나?

그리고 옛날에는 플로피 디스크(일명 디스켓)란 게 쓰여서 파일 시스템 차원에서 완전히 똑같은 디스크 복제를 해 주는 diskcopy라는 외부 명령이 있었다. 얘는 굳이 외부 명령으로 만들 거면 디스크 이미지 파일을 만들거나 이로부터 복제 디스크를 만드는 기능도 같이 있었으면 좋았을 거라는 아쉬움이 남는다.

1.2~1.44MB짜리 디스크를 단일 드라이브에서 복사하려면 source와 target 디스켓을 여러 번 갈아 끼워야 했는데.. Norton Utilities 같은 다른 유틸리티들은 EMS 및 XMS 메모리를 활용하여 한 번만 갈아 끼우고 바로 복사가 된다는 걸 장점으로 내세우곤 했다. 프로그램을 하나 설치하려 해도 "제품의 이제 1~N번 디스크를 넣고 아무 키나 누르세요" 이러던 참 아련한 옛날 추억이다.

2. 16비트 Windows의 실행 모드

예전에 언급한 바와 같이, 1990년대 초중반에 Windows라는 운영체제가 32비트 플랫폼으로 처음 갈아타던 시절에는 Win32 API라는 것의 구현체가 Windows NT, Windows 95, Windows 3.1+Win32s라는 세 계통으로 나뉘었다. NT가 가장 이상적인 레퍼런스 구현체이고, Win32s는 제일 허접하다.

그리고 그 중간의 95는 비록 NT처럼 스레드도 지원하고 도스로부터 많이 독립했다고는 하지만, 도스로부터 완전히 독립했다기보다는 도스를 내부적으로 흡수· 합병한 것에 가깝다. Windows NT의 마이너 축소판이라기보다는 Win32s가 각종 한계 없이 제대로 구현된 형태라고 보는 게 더 타당하다.

그런데 95 계통의 전신이라 할 수 있는 Windows 3.0이 나왔을 때에는 동일 제품· 단일 바이너리 하에서 실행 모드가 세 갈래로 나뉘었다. 바로 8086 리얼 모드, 286 표준 모드, 386 확장 모드이다.
Windows NT 4가 가장 많은 아키텍처를 지원하는 32비트 운영체제였다면, Windows 3.0 (3.1 말고)은 실행 모드가 가장 다양했던 16비트 도스용 운영 환경(?)이었다.

원래 Windows 1과 2에서는 리얼 모드밖에 존재하지 않았으며, Windows는 진짜 도스 위의 덧실행 껍데기 그 이상도 이하도 아니었다. 리얼 모드에서는 메모리가 기본 640K밖에 없었으며, 그 번거로운 16비트 Windows 3.x보다도 프로그래밍 환경이 더 열악했다.

그러다 Windows 2.0의 후속 버전으로 2.1은 286 표준 모드를 도입한 Windows/286과, 386 확장 모드의 전신인 Windows/386 이렇게 두 갈래로 나왔다. 사실, 16비트 80286 프로세서에도 보호 모드가 있긴 했지만 프로그래밍에 애로사항이 많았는지 그걸 사용한 프로그램은 매우 소수였으며 여전히 거의 봉인돼 있었다. 그냥 EMS/XMS 같은 규격으로 메모리를 수백 KB 남짓 더 사용할 수 있다는 것에 의미를 둬야 했다. 386 확장 모드도 첫 버전답게 문제가 많았으며, 2.11이 더 나와야 했다.

그러다가 Windows 3.0은 리얼, 286 표준, 386 확장을 모두 통합하여 출시됐다. 이때는 DPMI 규격도 갓 제정되었기 때문에 2.x 시절보다 보호 모드 지원도 더 개선되었다.
이때는 3.0에다가 멀티미디어 API가 최초로 추가된 확장팩이 나왔으며, 3.1은 네트워크 API가 추가된 Windows for Workgroup 3.11, 그리고 중국어 입출력 지원이 추가된 3.2 이런 식으로 기능 확장팩이 많던 시절이었다. 지금처럼 인터넷을 통한 업데이트가 가능한 시절도 아니었으니 말이다.

Windows 3.1에서는 리얼 모드가 삭제되고 win /2 또는 /3을 통해 286 표준 모드만 지원하지만, 이것은 성능이 굉장히 많이 열화된 모드였다. 그리고 Windows 95부터는 표준 모드도 빠져서 기술적으로 언제나 386 확장 모드로만 동작하는 형태가 됐다.

이렇듯, Windows 3.x는 비록 순수한 32비트 운영체제는 아니지만 보호 모드라든가 도스용 프로그램을 내부에서 구동할 때처럼 일부 기능에서 80386 이상 CPU가 제공하는 가상화 기능을 사용하기 때문에 결과적으로 32비트 CPU가 필요했다. 386 확장 모드가 지원하는 기능이 그런 것이었다.
이는 과거에 존재하던 PIF 편집기가 확장 모드에서는 표준 모드에 비해서 지원하는 옵션이 얼마나 더 다양해지는지를 보면 얼추 짐작 가능하다. 286 표준 모드에서는 요게 전부이던 옵션이..

사용자 삽입 이미지

386 확장 모드에서는 XMS뿐만 아니라 EMS 규격, 그리고 멀티태스킹 우선권 등 다양한 옵션들이 별도의 대화상자와 함께 추가되는 걸 알 수 있다.

사용자 삽입 이미지사용자 삽입 이미지

Windows 95 역시 순수 32비트 프로그램이 아니면 도스용 프로그램에 대해서만 제대로 된 가상 머신과 선점형 멀티태스킹을 지원했다. 16비트 Windows 프로그램을 강제 종료하면 운영체제와 얽혀 있는 스레드 동기화 오브젝트 같은 것이 얼어붙으면서 시스템의 안정성에 심각한 문제가 발생하곤 했다.

LimitEmsPages 이런 함수는 32비트가 아니라 이미 Windows 3.x 시절부터 deprecated돼 있었는데, 아마 리얼 모드 시절의 잔재이지 싶다.
Windows 1~2.x용 실행 파일은 후대 Windows와 실행 파일 포맷은 동일하지만(NE) 내부의 플래그로 구분되어 있어서 3.x에서 실행하면 "제대로 실행되지 않을 수 있음" 경고가 뜨곤 했다. 요컨대 Windows의 역사를 살펴보면, 16비트에서 32비트로 넘어갈 때만치 큰 변화는 아니지만, 같은 16비트 안에서도 1~2.x와 3.x 사이에 보호 모드가 도입되기 전과 후에는 기술적으로 나름 변화와 단절이 있었다고 볼 수 있다.

3. 외주로 제작되었던 보조 프로그램과 게임

Windows에 내장돼 있는 기본 프로그램들 중에는 마소에서 직접 만들지 않은 외주 프로그램도 있다. Windows 95 시절에 잠깐 있었던 하이퍼터미널이라는 터미널 접속 프로그램이 대표적인 예로, 스플래시 화면이라든가 각종 UI 외형이 대놓고 기존 마소 프로그램과는 어울리지 않아서 마소 자체 개발이 아니라는 걸 알 수 있었다.

또한 게임 중에서도 Windows XP에까지 제공되었던 3D 핀볼(시네마트로닉스 개발, 맥시스 유통)은 외부 프로그램이었으며, Vista/7 시절에 그래픽이 쇄신했던 지뢰찾기 등의 기본 게임들도 외주였다(Oberon games).

그런데 더 옛날에 Windows 3.1의 내장 프로그램들을 보면, 굉장히 단순하게 생겼고 이 정도면 자체 제작했을 법도 한 프로그램이 About 대화상자를 보면 외주인 경우가 은근히 더 있었다. 게다가 아래의 목록에서 보다시피 제작자/제작사가 프로그램마다 완전 제각각이었다.

  • 계산기: Kraig Brockschmidt
  • 터미널: Future Soft Engineering 사
  • 레코더: Softbridge 사
  • 지뢰찾기: Robert Donner & Curt Johnson
  • 카드놀이: Wes Cherry

그러니 Vista/7 이전에 제공되던 기본 게임들도 알고 보니 외주였던 셈이다. 특히 지뢰찾기는 Windows 1.0부터 3.0까지 존재하던 Reversi(일명 오델로)를 대체할 목적으로 3.1에서 처음 선보였던 게임이기도 하다.
레코더의 경우 Windows의 역사상 거의 전무후무하게 존재하던 키보드· 마우스 매크로 유틸리티인데 95와 그 이후로는 결코 재등장하지 않았으니 희소성이 크다.

물론 이것들 말고 프로그램 관리자, 파일 관리자, 제어판이라든가 간판 앱인 문서 작성기(오늘날의 워드패드)와 페인트(오늘날의 그림판)은 외주가 아니라 내부 자체 제작이다.

4. 색깔의 미묘한 차이

말이 나왔으니 옛날 추억 회상을 더 해 보자면,
컴퓨터의 주메모리가 아니라 비디오 메모리가 딱 1MB이던 시절에는 Windows 3.1의 비디오 모드를 (1) 꼴랑 640*480 저해상도인 대신에 트루컬러, (2) 800*600에서 적당하게 하이 컬러, 아니면 (3) 1024*768에서 256색.. 셋 중 하나로 골라 쓰는 재미(?)가 있었다.

그리고 Windows 3.1은 원래는 우리에게 익숙한 짙은 파란색으로 윈도우의 굵은 틀을 표현했지만, 하이 컬러 이상부터는 어인 일인지 은은한 하늘색으로 색깔을 바꿔 표시했다. 왜 무슨 근거로 색깔을 바꿨는지는 모르겠지만 개인적으로 아주 신기하게 느껴졌었다.

사용자 삽입 이미지사용자 삽입 이미지

그 이전 3.0은 슈퍼 VGA나 트루컬러로 진입할 일이 있긴 있었는지, 그래픽 드라이버가 개발되거나 3.1 것과 호환되긴 했는지에 대해 본인은 아는 바가 없으며, 이에 대해서 회의적이다.

Posted by 사무엘

2018/03/04 08:30 2018/03/04 08:30
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1464

컴퓨터에서 돌아가는 프로그램들에는 각각 current directory라는 개념이 있다. 그래서 파일이나 디렉터리를 지정할 때 매번 드라이브 또는 볼륨의 이름부터 쓰는 게 아니라 그걸 생략하고 이름만 달랑 적거나, ..₩ 처럼 간편하게 ‘상대 경로’를 지정해 줄 수 있다.

기술적으로 봤을 때 current directory는 프로세스 전체 단위로 공유되는 속성이다. 스레드 단위가 아니다.
한 디렉터리 아래에 있는 모든 파일과 디렉터리를 조회하는 건 보통 SetCurrentDirectory를 이용해서 함수의 재귀호출로 구현하는 편인데(이름을 줘서 하위 디렉터리로 갔다가 앞으로 되돌아갈 때는 간편하게 ".."만 지정하면 됨), 이건 여러 스레드가 동시에 수행되지 않게 해야 한다.

여러 군데에서의 디스크 수색을 굳이 동시다발적으로 하려면 해당 함수가 경로 문자열 관리를 자체적으로 해서 FindFirstFile에 언제나 절대경로만 전해 주거나, 아니면 상대 경로를 쓸 거면 아예 별도의 프로세스를 만들어서 돌리게 해야 한다.

그런데 여기서 한 가지 의문이 생긴다. 각 드라이브별로 직전까지 작업하던 디렉터리 정보가 운영체제 차원에서 자동으로 보존될까, 그렇지 않을까?

C:\>cd windows

C:\Windows>d:

D:\>cd doc

D:\doc>c:

C:\Windows>d:

D:\doc>


드라이브별 커런트 디렉터리란, 위의 예에서 C에서는 Windows가 보존되고, D에서는 doc가 보존되는 것을 말한다.

그런데 정답부터 말하자면 그건 운영체제가 일일이 자동으로 기억하고 챙겨 주지 않는다.
당장 탐색기나 파일 열기 대화상자의 주소창에서 c: 나 d: 라고만 달랑 쳐 보아라. 이 경우 언제나 해당 드라이브의 루트 디렉터리로만 가지, 명령 프롬프트일 때처럼 직전에 해당 드라이브에서 마지막으로 살펴보던 디렉터리를 기억하지 않는다. 오히려 명령 프롬프트가 예외적으로, 유일하게 그걸 별도로 지원해 주고 있다.

그럼 질문의 초점이 이렇게 바뀔 것이다. 명령 프롬프트만 왜 그러는 걸까?
물론 명령 프롬프트는 GUI와 달리 '뒤로' 같은 버튼이 없으니 디렉터리를 기억해 주는 게 사용자의 입장에서 편리하다. 그리고 더 큰 이유는 먼 옛날 MS-DOS와의 호환을 위해서이다.

MS-DOS의 최초 버전인 1.0은 무려 1981년에 출시되었으며, 얘는 파일 시스템에 디렉터리라는 개념을 지원하지 않았었다. 즉, 모든 디스크는 루트 디렉터리만 존재했으며, 파일 이름에 (역)슬래시 기호가 들어갈 일이 없었다.

마치 Windows 1.0이 프로그램 창을 겹치게 배열하는 게 지원되지 않았던 것과 동급으로 정말 믿어지지 않는다. (뭐, 기술적인 한계 때문은 아니고, 애플 사와의 특허 분쟁을 피해 가느라 일부러 기능을 cripple시킨 것이지만) 1980년대 초의 열악한 컴퓨터는 무슨 매체든 디스크의 공간이 상상하기 힘들 정도로 작고 좁았으니 굳이 디렉터리 계층 구조의 필요가 존재하지 않았던 듯하다.

그러다가 DOS 2.0부터는 드디어 파일 시스템 차원에서 디렉터리가 도입됐다.
그런데 DOS 1.0용으로 개발된 프로그램은 디렉터리라는 걸 전혀 인식하지 않고 역슬래시 문자도 아예 사용하지 않으니 2.0에서 루트가 아닌 다른 디렉터리에 있는 파일을 읽고 쓸 방법이 없다.

그러니 이 문제를 최대한 호환성을 존중하며 해결하기 위해, :₩로 시작하지 않는 경로는 이제부터 상대 경로로 간주시켰다. 그리고 각 드라이브별로 커런트 디렉터리라는 개념을 도입하여, 상대 경로는 루트 고정이 아닌 커런트 디렉터리에 있는 파일에 접근하는 것으로 정책을 바꿨다. 운영체제가 일종의 state machine 역할을 대신해 주는 셈이다.

Windows는 앞서 살펴보았듯이 모든 드라이브를 통틀어서 단일 current directory만 관리하지 DOS처럼 동작하지 않는다. 단지 명령 프롬프트에서는 특수한 환경변수를 운용해서 사용자가 돌아다닌 디렉터리를 드라이브별로 추적하여 도스의 동작을 흉내 내 준다. 이건 물론 오늘날까지도 전적으로 호환성 차원에서 해 주는 것일 뿐이다. the old new thing 블로그를 보면 더 자세한 설명을 볼 수 있다. 환경변수를 사용하는 이유는 이 프로세스로부터 새로 실행된 child 프로세스에게까지 current directory 변경의 여파가 자동으로 이어지게 하기 위해서라 한다.

“타 드라이브의 current directory”라니, 지금까지 한 번도 진지하게 생각해 본 적이 없었는데.. 굉장히 흥미로운 사실을 알 수 있었다. 예전에 Windows 9x에서 존재하던 CD ... (점 3개 이상)처럼 뭔가 호환성과 관련된 사연이 있었던 것이다.

1.
컴퓨터에서 옛날에는 하나밖에 없는 게 당연하다고 여겨졌으나 나중에는 여러 개 존재할 수도 있게 된 것의 예로는 디렉터리뿐만 아니라 CPU 코어(멀티코어!)라든가 모니터(최소한 듀얼..)도 해당되지 싶다.
그러니 하나밖에 인식을 안 하는 소프트웨어에 대해서는 무조건 붙박이가 아니라 현재 default로 지정되어 있는 것 하나를 기준으로 동작하게 운영체제가 샌드박스 처리를 잘 해 줘야 할 것이다.

하드웨어 말고 소프트웨어적인 요소 중에서도 클립보드 같은 건 운영체제 API 차원에서 다변화될 가능성이 있다. 그것 말고는... 설마 한 컴퓨터에 마우스 포인터 같은 게 둘 이상 존재할 일이 있을지는 모르겠다.
마우스 말고 터치스크린은 여러 손가락이 동시에 눌러질 수 있다. Windows 98에서 멀티모니터 지원이 최초로 도입됐다면 Windows 7부터는 멀티터치 지원 기능이 최초로 추가됐는데, 본인은 지금까지 멀티터치 관련 기기나 API를 접할 일이 전~혀 없었다. 문자 입력과도 분명 연계가 가능할 텐데 그쪽으로 연구할 기회가 없었다.

2.
그러고 보니 시스템 전체 차원에서의 current 설정 vs 특정 항목별 current/default 설정이라는 양대 구도는 Windows의 IME에서도 동일하게 찾아볼 수 있다.
Windows에서 돌아가는 모든 UI 스레드들은 어떤 입력 언어/로케일과 연결돼 있다. 이것은 영어 드보락, MS 일본어 IME, 날개셋 등등 중 하나로.. 키보드 드라이버, IME/TSF 모듈을 모두 통합하는 개념이다.

각 스레드들이 서로 다른 입력 언어와 연결 가능하지만(Alt+Shift, Ctrl+Shift, 또는 도구모음줄 클릭), 어떤 스레드가 새로 생성되었을 때 맨 처음 기본으로 지정되는 'default 입력 언어'라는 건 따로 있다. 이건 제어판에서 변경 가능하다. 이게 디렉터리로 치면 current directory에 가깝다.

그런데, 사실은 한국어, 중국어, 일본어 등 각 언어별로도 말 그대로 default 입력 언어가 있다. 한 언어에 속하는 IME들이 여러 개 있을 때, 사용자가 Alt+Shift로 언어만 그걸로 전환하면 그 언어의 default IME에 속하는 놈이 기본 선택된다. DOS에서 존재하던 드라이브별 current directory처럼 말이다.

내 경험상 전체 default IME라든가, 언어별 default IME 같은 건 프로그래밍을 통해 알아 내거나 변경하는 뾰족한 방법이 없다. MSDN을 뒤져 보면 비슷한 기능을 하는 API가 있긴 하지만 current, active, default 등 용어도 혼란스럽고 기능들이 문서화된 대로 정확하게 동작하질 않는다. 더구나 Windows 8부터는 Win+Space를 통해 IME들을 언어 구분 없이 한 리스트에서 쭉 고르게 UI가 바뀌어서 언어별 default IME라는 건 개념이 굉장히 모호해지기도 했다.

이 방식은 운영체제에 설치된 입력기가 적을 때는 깔끔하지만 10개 가까이 많아지면 화면이 굉장히 난잡해진다. 언어별로 구분하는 Windows 7 이하 기존 방식도 여전히 필요하다고 생각된다.

Posted by 사무엘

2017/08/04 08:35 2017/08/04 08:35
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1389

오늘날 Windows에서 실행되는 모든 프로그램들.. exe, dll 따위는 잘 알다시피 portable executable이라는 형식으로 만들어져 있다. 하지만 이 파일 포맷도.. 처음 만들어지던 당시에 여전히 컴퓨터에서 현역이던 도스와 최소한의 호환성을 유지할 필요가 있었기 때문에, 맨 앞에 MZ로 시작하는 16비트 도스 헤더를 여전히 갖추고 있다.

호환성이란 게 딴 게 아니고, 도스에서 Windows용 프로그램이 실행됐을 때 컴퓨터가 다운되는 게 아니라 "이 프로그램은 도스용이 아닙니다" 같은 짤막한 에러 메시지라도 뜨게 하는 것 말이다.

옛날에 Win32s가 제대로 설치되지 않은 상태에서 32비트 프로그램을 Windows 3.1에서 실행했더니.. "상위 버전에서 실행해 주십시오 / Win32s를 다시 설치해 주십시오" 이런 말이 메시지 박스 형태로 뜨는 게 아니라 황당하게 This program cannot be run in DOS mode라고.. 지금 시스템이 아예 Windows가 아닌 듯한 자비심 없는 메시지가 도스창에 떴다. 20여 년 전에 그 인상이 무척 강렬했었다. 요즘은 32비트 OS에서 64비트 exe의 실행을 시도해도 에러 메시지가 그 정도로 막나가는 형태는 아니다.

Windows용 프로그램들은 빌드할 때 그렇게 도스에서 잘못 실행됐을 때를 대비해 짤막하게 대신 실행해 줄 도스용 일명 "stub" 프로그램을 링크 옵션으로 지정할 수 있다. 이름하여 /STUB. 이걸 지정하지 않으면 아까 같은 저런 짤막한 에러 메시지 한 줄만 찍는 기본 stub 프로그램이 들어간다.
16비트 시절에 Visual C++ 1.5x를 보면 그 예제 stub 프로그램 자체가 winstub.exe라고 있었다. 하지만 그 이후부터는 디폴트 stub 프로그램은 그냥 링커 내부에 내장되어 버렸는지 그런 게 따로 있지는 않다.

프로그램을 특수하게 빌드하면 그런 stub을 아예 전혀 집어넣지 않는 것도 가능하다. 맨 앞에 MZ, 그리고 0x3C 오프셋에 PE 헤더가 있는 지점만 들어있으면 되고 나머지 칸은 몽땅 0으로 채움. 심지어 PE 헤더가 0x3C 오프셋보다도 전에, 도스 EXE 헤더가 있어야 할 지점에서 바로 시작하는 것도 가능하다.

미래에 마소에서 빌드하는 EXE/DLL들은 번거로운 This program cannot be ... 메시지를 떼어내고 이렇게 만들어져 나올지도 모른다. 물론 이런 프로그램은 Windows 환경에서 실행하는 건 문제 없지만 만에 하나 어느 레트로 변태 덕후가 그걸 굳이 도스에서 실행해 보면 컴퓨터가 어찌 되는지 책임 못 지는 상태가 될 것이다.

반대로 기본 stub 대신에 꽤 규모 있는 16비트 프로그램을 집어넣어서 동일 EXE가 도스에서도 그럭저럭 기능을 하고 Windows에서도 GUI를 띄우며 제대로 실행되는 프로그램을 만든 경우가 있다. Windows 9x 시절엔 레지스트리 편집기가 그러했다. 이건 Windows에서 보기 드문 하이브리드 universal binary 형태의 프로그램인 것 같다.
16비트 프로그램이 자기 자신 EXE를 열어서 PE 헤더를 파싱해서 리소스 같은 걸 읽어들이는 코드가 같이 빌드되었다면.. 도스 파트가 나중에 합쳐진 Windows 파트와 더불어 한 리소스를 공유하는 형태로 실행될 테니 이 역시 무척 흥미로울 것이다.

이 시점에서 문득 궁금해졌다.
링커가 얹어 주는 기본 stub 프로그램은 명령어가 겨우 몇 바이트밖에 되지 않는다. 얘들은 무슨 의미를 갖고 있는지, 혹시 옛날 16비트 NE 시대와 지금의 PE 시대에 stub 프로그램에 차이가 있는지..?
그래서 오랜만에 도스 API와 8086 어셈블리 명령어 레퍼런스까지 찾아서 stub 프로그램을 분석해 봤다.

stub 프로그램의 코드는 이게 전부이다.

(1) 0E        PUSH CS
(2) 1F        POP DS
(3) BA 0E 00  MOV DX,000E
(4) B4 09     MOV AH,09
(5) CD 21     INT 21
(6) B8 01 4C  MOV AX,4C01
(7) CD 21     INT 21
"문자열"


(1), (2) 맨 앞의 PUSH와 POP은 데이터 세그먼트를 코드 세그먼트의 값과 맞추는(DS=CS) 일종의 초기화이다. 스택에다가 CS 값을 넣은 뒤 그걸 DS로 도로 가져오는 거니까.
지금 이 프로그램은 화면에다 찍을 에러 메시지도 기계어 코드와 정확하게 같은 영역에 있으므로 저건 수긍이 가는 조치이다.

(3) 그 다음으로 DX 레지스터에다가 16진수로 0xE, 즉 14를 기록한다. 저 stub 프로그램은 길이가 정확하게 14바이트이다. 이 값은 프로그램의 시작 지점을 기준(0)으로 해서 그로부터 14바이트 뒤에 있는 문자열을 가리킨다.

(4) AX 레지스터의 high byte에다가 9를 기록한다.

(5) 이렇게 기록된 AX와 DX 레지스터 값을 토대로 0x21 인터럽트를 날려서 도스 API를 호출한다. 도스 API 중 9는 DX가 가리키는 주소에 있는 문자열을 화면, 정확히는 표준 출력에다가 찍는 기능을 수행한다.
그런데 굉장히 기괴한 점이 있는데.. 얘가 받아들이는 문자열은 null-terminated가 아니라 $-terminated여야 한다!

믿어지지 않으면 아무 Windows용 EXE/DLL이나 헥사 에디터로 열어서 앞부분의 에러 메시지 텍스트가 무슨 문자로 끝나는지를 확인해 보시기 바란다.
왜 그렇게 설계되었는지 모르겠다. 파일이나 디렉터리 이름을 받는 도스 API들은 당연히 null-terminated 문자열인데 말이다.

(6) 그 다음, AX 레지스터에다가 0x4C (high)와 0x1 (low)을 기록하고..

(7) 또 도스 API를 호출한다. 0x4C는 프로그램을 종료하는 기능을 하며, 종료와 동시에 low byte에 있는 1이라는 값을 에러코드로 되돌린다. 정상 종료는 0인데 1은 뭔가 오류와 함께 종료되었음을 나타낸다.
사실, 도스 API 레퍼런스를 보면 AH 값으로 0도 프로그램을 종료시키는 역할을 하는 듯하다(도스 1.0때부터 최초). 하지만 모종의 이유로 인해 그건 오늘날은 사용이 별로 권장되지 않으며 0x4C가 원칙이라 한다(도스 2.0에서부터 추가됨).

이렇게 분석 끝. 정말 간결 단순명료하다.
참고로 도스 EXE에서 헤더를 제끼고 기계어 코드가 시작되는 부분은 0x8~0x9 오프셋에 있는 unsigned short값에다가 16을 곱한 오프셋부터이다. 가령, 거기에 04 00 이렇게 적혀 있으면 0x40 오프셋부터 디스어셈블링을 해 나가면 된다. EXE는 헤더에 고정 길이 구조체뿐만 아니라 가변 길이인 '재배치 섹션'이 나오고 그 뒤부터 코드가 시작되기 때문이다.

그럼 과거 16비트 Windows에서 쓰이던 stub은 어떻게 돼 있었을까?
거의 차이가 없긴 한데, 문자열이 들어있는 위치와 얘의 주소를 전하는 방법이 달랐다.

(1) E8 53 00  CALL 0056
"문자열"
20 20 20 20 .. padding 후
(2) 5A        POP DX
(3) 0E        PUSH CS
(4) 1F        POP DS
(5) B4 09     MOV AH,09
(6) CD 21     INT 21
(7) B8 01 4C  MOV AX,4C01
(8) CD 21     INT 21


(1) 맨 먼저 JMP도 아니고 웬 CALL 인스트럭션이 나온다. 기계어로 표기할 때는 인자값이 0x53이어서 3바이트짜리 자기 자신 인스트럭션 이후에 0x53바이트 뒤로 가라는 뜻이 되는데, 영단어로 바꿔서 표기할 때는 자기 자신 원래 위치 기준으로 0x56바이트 뒤가 된다. 이 위치는 그냥 바로 다음 (2) 명령이 있는 곳과 같다.

(2) 함수 호출을 했는데 RET를 하는 게 아니라 스택을 pop하여 DX 레지스터에다 가져온다. 그렇다. 아까 그 call에 대한 복귀 주소에 문자열이 담겨 있으니, 아까 같은 하드코딩이 아닌 요런 방식으로 문자열 주소를 얹었다.

(3) (4) 이제부터는 아까처럼 DS = CS 해 주고,

(5)~(8) 아까와 동일. 문자열을 찍은 뒤 프로그램을 종료한다.

이런 초간단 초미니 프로그램은 exe가 아니라 com 형태로도 만들지 말라는 법이 없어 보인다. com은 그 어떤 헤더나 시그니처도 없이 첫 바이트부터 바로 기계어 코드와 데이터를 써 주면 되는.. 정말 원시적이기 그지없는 바이너리 덤프일 뿐이기 때문이다. 빌드 날짜, 버전, 요구하는 아키텍처나 운영체제 등등 그 어떤 부가정보도 존재하지 않는다.

요즘 프로그래밍 언어들이 기본 제공하는 런타임들의 오버헤드가 너무 크다 보니, 이에 대항하여 세상에서 제일 작은 "Hello world" 프로그램 이런 것에 집착하는 덕후들이 있다. Windows 프로그램의 경우 프로그램을 특수하게 빌드하여 CRT 라이브러리는 당연히 떼어내고, 코드와 데이터도 한 섹션에다 우려넣고, 거기에다 후처리까지 해서 단 몇백 바이트만으로 MessageBoxA(NULL, NULL, "Hello, world!", 0) 하나만 호출하는 프로그램을 만든 예가 있다.

그러나 이런 것들도 com 앞에서는 몽땅 버로우 타야 한다. 얘는 아예 파일 포맷 자체가 없으니까. 이 이상 더 줄일 수가 없다. com 형태로 만든 Hello world 프로그램은 겨우 20몇 바이트가 전부이다.
무슨 명령어를 내렸는지 기억은 안 나지만 컴퓨터를 재시작시키는 com 파일이 있었는데, 얘는 크기가 겨우 2바이트에 불과했다.

(1) BA 0C 01  MOV DX,010C
(2) B4 09     MOV AH,09
(3) CD 21     INT 21
(4) B8 01 4C  MOV AX,4C01
(5) CD 21     INT 21
그 뒤에 "Hello, world!$" 같은 문자열. 따옴표는 제외하고.


com은 exe처럼 코드/데이터 세그먼트 DS=CS 따윈 전혀 신경 쓸 필요 없이, 바로 본론부터 들어가면 된다. 그 대신 com은 16비트 단일 세그먼트 안에서 코드와 데이터 크기 한계가 모두 64K라는 치명적인 한계를 갖는다. 메모리 모델로 치면 그 이름도 유명한 tiny 모델 되겠다. 애초에 exe가 16비트 CPU에서 저 한계를 극복하고, 또 멀티태스킹에 대비하여 재배치도 가능하게 하려고 만들어진 포맷이기도 하다.

아, 아주 중요한 사항이 있다. com에서는 첫 256바이트, 즉 0x100 미만의 메모리 주소는 시스템용으로 예약되어 있어서 사용할 수 없다. 내 코드와 데이터는 0x100부터 시작한다. 그렇기 때문에 저 프로그램의 코드 크기는 12바이트이고, 문자열은 0xC 오프셋부터 시작하긴 하는데 거기에다가 0x100을 더해서 DX에다가는 0x10C를 써 줘야 한다.

Windows PE에다 비유하자면 0x100이 고정된 base address값인 셈이다. 그리고 DX의 값은 그냥 VA이지 RVA가 아니다.
과거에 굴러다니던 exe/com 상호 변환 유틸리티들이 하던 주된 작업 중 하나도 이런 오프셋 재계산이었다. 그리고 com에서 exe라면 모를까 더 넓은 곳에서 좁은 곳으로 맞추는 exe -> com은 아무 exe에 대해서나 가능한 게 물론 아니었다. (단일 세그먼트 안에서만 놀아야..) 과거 도스에 exe2bin이라는 외부 명령어가 있었는데 걔가 사실상 exe2com의 역할을 했다.

아무튼, 저 바이너리 코드와 문자열을 헥사 에디터를 이용해서 입력한 뒤, 파일을 hello.com이라고 명명하여 저장한다. 이걸 도스박스 같은 가상화 프로그램에서 도스 부팅하여 실행하면 신기하게도 Hello, world!가 출력될 것이다.
고급 언어를 사용하지 않고 컴파일러 나부랭이도 전혀 동원하지 않고 가장 원초적인 방법으로 나름 네이티브 실행 파일을 만든 것이다. 사용 가능한 코드와 데이터 용량이 심각하게 작다는 것과, 요즘 64비트 Windows에서는 직통으로 실행조차 할 수 없다는 게 문제이긴 하지만. (네이티브 코드라는 의미가 없다~!)

이런 식으로 컴퓨터에 간단히 명령을 내리고 램 상주 프로그램이나 바이러스 같은 것도 만들기 위해 옛날에는 debug.com이라는 도스 유틸리티가 요긴하게 쓰였다. 간단한 어셈블러/디스어셈블러 겸 헥사 에디터로서 가성비가 뛰어났기 때문이다. edlin 에디터의 바이너리 버전인 것 같다.

오늘날 어셈블리어라는 건 극소수 드라이버/컴파일러 개발자 내지 악성 코드· 보안· 역공학 같은 걸 연구하는 사람들이나 들여다보는 어려운 물건으로 전락한 지 오래다. 하지만 이것도 알면 디버깅이나 코드 분석에 굉장한 도움이 될 듯하다.
디스어셈블리 자체는 주어진 규칙대로 바이트 시퀀스를 몇 바이트씩 떼어서 명령어로 분해해 주는 비교적 간단한 작업일 뿐이다. 파서(parser)가 아니라 스캐너(scanner) 수준의 작업만 하면 된다.

하지만 디스어셈블리가 골치 아프고 귀찮은 이유는 코드의 첫 실행 지점을 정확하게 잡아서 분해를 시작해야 하며, 그래도 어느 게 코드이고 어느 게 데이터인지가 프로그램 실행 문맥에 의해 시시각각 달라지고 무진장 헷갈리기 때문이다. 데이터는 백 날 디스어셈블링 해 봤자 아무 의미가 없고, 오히려 코드의 분석에 방해만 된다. 이런 역공학을 어렵게 하기 위해서 디스어셈블러를 엿먹이는 테크닉도 보안 분야에는 발달해 있다.
하긴, 코드와 데이터가 그렇게 경계 구분 없이 자유자재로 변할 수 있는 게 "폰 노이만 모델 기반의 튜링 기계"가 누리는 극한의 자유이긴 하다.

Posted by 사무엘

2016/12/17 08:34 2016/12/17 08:34
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1306

DOS 회상

1. 들어가는 말

오늘날의 거대하고 복잡한 운영체제와는 달리, 도스는 이니셜 D-_-가 암시하듯이 달랑 플로피디스크 한 장만으로 부팅이 가능할 정도로 참을 수 없이 작고 가벼웠다. 정말 필수불가결인 파일은 부팅에 쓰이는 io.sys, 그 뒤 셸 역할을 하는 텍스트 명령 해석기인 command.com이 전부다.
msdos.sys라는 파일도 있는데 얘는 정확하게 무슨 존재인지 모르겠다.

그리고 사실은 config.sys의 DEVICE 명령을 통해 실행되는 sys 파일과, com 실행 파일이 서로 무슨 차이가 있는지도 모르겠다. 마우스, 그래픽 카드 에뮬(simcga, msherc ^^), 사운드(sound, unsound) 같은 여러 램 상주 드라이버들은 com이었지만, 씨디롬 드라이브는 sys였으며 그것도 주 메모리를 꽤 많이 차지하는 드라이버였다. 단, 부팅 후에 sys 파일을 별도로 실행해 주는 유틸리티가 있기도 했다.

디스크로부터 파일을 읽으려면 파일 시스템이 정립돼 있어야 하며, 이건 운영체제가 하는 일 중 하나이다. 그런데 그 운영체제를 로딩하는 프로그램도 파일 형태로 저장돼 있다. 이런 '닭이 먼저냐 계란이 먼저냐' 딜레마를 해소하기 위해서는, 부팅에 쓰이는 운영체제 프로그램은 디스크에 단순히 파일 형태로만 존재하는 게 아니라, 컴퓨터 바이오스가 물리적이고 원초적으로 인식 가능한 첫 지점에 저장돼 있어야 한다. 이건 굳이 도스뿐만 아니라 어느 운영체제라도 마찬가지이다.

도스는 단일 사용자 단일 프로그램 구동 체계이다 보니, 한 프로그램이 그야말로 컴퓨터 하드웨어를 전부 있는 그대로 조종 가능하게 허용하는 백지수표, 열린 허허벌판 같은 환경이었다. 프로그램의 인터페이스도 명령 기반, TUI, GUI 등 제각각이었고 정말 창의적이었다. 요즘 프로그램들만치 UI가 획일화됐다는 느낌이 없이 형형색색 컬러풀했다.

물론 그건 거시적인 관점에서는 그리 효율적이지 못하다. 이런 빵빵한 컴퓨터 자원에서 여러 프로그램을 동시에 실행하고 작업 전환을 할 수 없다면 그것도 컴퓨터에 대한 예의-_-가 아니다.
그러니 운영체제가 더 강력하게 모든 걸 통제하는 지금 같은 환경으로 궁극적으로는 바뀌는 게 맞긴 하지만.. 인제 와서 도스가 다시 새삼스럽게 그리워질 때도 있다.

2. 역사

본인이 경험한 MS-DOS의 가장 옛날 버전은 학교 내지 컴퓨터 학원에서 봤던 3.2/3.3이다. 2.x 이하나 4는 실물로 구경을 못 해 봤다. 다만, 5.0과 6.2는 집 컴퓨터에 내장돼 있던 물건이다 보니 개인적으로 친숙하다.

1981년에 첫 출시되었다고 전해지는 MS-DOS 1.0은 그야말로 정말 골동품 폐물이었다고 한다. 그리고 Windows 1.0이 프로그램 창을 겹치게 배열하는 걸 지원하지 않았다면, DOS 1.0은 디스크에 서브디렉터리를 만드는 걸 지원하지 않았다..;;
그나마 도스가 최소한의 도스다운 틀을 갖춘 건 2를 거쳐서 3.x대에 와서부터이다. 특히 5.25내지 3.5인치 고밀도(1.2, 1.44MB) 플로피디스크를 지원하기 시작한 첫 버전이 이 버전이기 때문이다. 3.x에 와서야 좀 물건다운 물건이 나왔다는 점에서는 도스와 Windows가 역사가 서로 비슷한 것 같다.

그 다음 4.0의 아주 기념비적인 업적은 파일 시스템이 FAT12에서 FAT16으로 확장되어, 이론적으로 지원 가능한 디스크 볼륨의 용량이 2GB로 커진 것이다.
그 시절에 기가바이트는 가히 꿈의 규모였기 때문에 홍보 자료에서는 그냥 '제한이 없어졌다'라는 표현이 관용적으로 쓰였다. 참고로, FAT12 시절의 하드디스크의 용량 한계는.. 고작 32MB였다. =_=;;

또한 MS-DOS shell이라고 나름 드래그 드롭도 지원하고 Windows GUI를 어설프게 베낀 듯한 파일 관리자 셸이 추가된 것도 4부터이다. 하지만 MS-DOS 4는 구체적인 내역은 모르겠지만 불안정하고 버그가 많아서 좀 문제작으로 남았다고 한다.

도스 5.0에서 기념비적인 업적은 그 이름도 유명한 HIMEM.SYS와 DOS=HIGH일 것이다. EMM386은 4.0 때 SYS 버전이 있었지만 5.0부터는 EXE로 형태가 바뀌었다고 한다.
또한 이 버전에서는 과거의 불편하던 EDLIN을 대체하는 QBASIC 기반의 텍스트 에디터가 추가되었으며, 명령 프롬프트에서 cursor 이동을 자유롭게 할 수 있게 하고 히스토리 기능도 넣어 주는 DOSKEY 유틸도 이때 추가됐다.

지워진 파일을 첫 글자 이름을 집어넣어서 복구하는 undelete 역시 아마 6이 아닌 5에서 첫 추가됐지 싶다. 이건 PC-tools나 노턴 유틸리티가 먼저 제공하던 꼼수 기능이었는데 동일 기능을 도스에서 직접 수용한 것이다.

그 뒤 6.0은.. 변한 게 많았다.
가장 유명한 건 하드 디스크를 압축해 주는 '더블 스페이스'라는 유틸리티의 도입이다.
이건 무슨 요술을 부리거나 하드 디스크를 물리적으로 어떻게 하는 게 아니라, 그냥 파일 시스템 차원에서 데이터를 zip 같은 소프트웨어 압축을 적용하는 것일 뿐이다. 당장 용량 확보에는 도움이 되지만 디스크의 액세스 속도가 좀 느려지고 에러에 취약해지며, 하드웨어를 좀 험하게 다루는 일부 프로그램과는 트러블의 여지가 생긴다.

참고로 1993~1994년이면 Windows 3.1이 보급되고 어지간한 PC의 하드디스크는 몇백 MB 정도이던 시절이다.
더블 스페이스는 그렇잖아도 꽤 중요하고 민감한 간판 기능인데, 버그를 많이 잡고 안정화를 더 시켜서 6.2가 나왔다.
그런데 이게 '스태커'라는 타사의 제품을 무단 도용한 것으로 판결이 나서 '더블 스페이스'를 뺀 6.21이 나왔고, 저작권 문제를 해결하여 '드라이브 스페이스'를 대신 도입한 6.22로 6.x대가 마무리 되었다. 지금이야 마소에 대해서 IE 브라우저의 독점 소송이 유명하지만, 1990년대 중반엔 저거 저작권 침해 소송이 IT 업계에서 굉장한 화두였다.

압축 유틸리티 말고도 6.x대엔 멀티 부팅이라는 매우 유용한 기능이 추가됐다. 즉, C/C++의 조건부 컴파일처럼 사용자가 선택한 옵션 방식대로 디바이스 드라이버를 로딩하여 부팅할 수 있게 됐다는 것이다.
그리고 디스크 점검 scandisk, 조각 모음 defrag, 시스템 점검 msd, 주 메모리 확보 유틸리티 memmaker 등이 추가되고 PC-Tools로부터 라이선스 받은 안티바이러스 msav 같은 유틸도 도입됐다. 덕분에 노턴 유틸리티가 예전보다는 좀 덜 필요해졌다.

모든 내부/외부 명령에 /? 옵션을 줬을 때 도움말이 나오는 것도 처음부터 존재한 게 아니었다. 6이거나 아니면 5부터인데 그건 정확하게 기억이 안 난다. 옛날에는 도움말 텍스트를 일일이 내장시켜 줄 정도로 컴퓨터의 메모리나 디스크 용량이 충분하지 못했기 때문이다.

단독 제품으로서 MS-DOS의 역사는 1994년에 출시된 6.22가 끝이었다. 도스는 Windows 95/98/ME와 함께 7.0. 7.1. 8.0 버전으로 명맥을 유지하다가 2000년에 드디어 20여 년의 긴 수명을 마치고 역사 속으로 사라졌다.
도스 외부 명령어 중에서 몇몇 필요한 건 Windows 9x 계열에서는 Windows\command로 갔고, NT 계열은 그냥 system32 디렉터리에 있다. 그리고 NT 계열은 format이나 diskcopy 같은 유틸리티도 콘솔에서 실행될지언정 도스가 아니라 Windows용 프로그램이라는 차이가 있다.

3. 그 당시의 유사품/경쟁자

한편, 도스의 바리에이션으로는..
PC-DOS는 그냥 MS-DOS가 IBM 브랜드만 달고 나온 동일 제품이었다고 한다. 한동안 그러다가 6.x대부터는 서로 다른 길을 가기 시작했는데 이미 그때는 PC 환경이 Windows로 충분히 넘어가기 시작했으니 별 의미는 없다. 따지고 보면 IBM은 OS/2가 망한 데다, 도스 분야도 뒷북으로 끝나고 별 재미를 못 본 셈이다. "IBM 호환 PC"라는 걸출한 대인배 이름만 남긴 채 PC 시장에서는 철수했다.

DR-DOS는 MS-DOS의 전신인 CP/M을 직접 만든 게리 킬달이라는 엔지니어가 '디지털 리서치'라는 회사를 세워서 따로 만든 MS-DOS의 대항마이다. '디알'이지 '닥터 도스'는 아님.. 뭔가 기능이 MS-DOS보다 뛰어났다고 얘기는 들었는데 구체적인 내역은 잊어버려서 기억이 안 난다.
DR-DOS를 '노벨' 사가 인수하여 새로 내놓은 것이 '노벨 도스'이며, 이건 1990년대 초중반까지 나왔다.

한편, 4DOS는 커널을 처음부터 새로 만드는 건 아니고 명령 인터프리터인 COMMAND.COM만 대체하는 기능 확장판으로 컴덕들에게 많이 알려져 있었다. 이걸 시먼텍(Symantec) 사에서 인수하여 자신들이 인수한 다른 유명 솔루션인 '노턴 유틸리티'에다가 집어넣은 것이 NDOS이다. 각종 도스 명령들에서 2% 부족하던 것을 보완하는 편의 기능이 굉장히 많았던 걸로 기억한다. (가령, 중간에 파일이 사라져도 괜찮은 batch-to-memory 배치 파일)

그리고 8.3 짧은 파일 이름의 한계를 보완하기 위해, 내부적으로 descript.ion이라는 숨김 파일을 만들어서 파일명에 대한 '주석'을 표시하는 것도 4DOS의 작품이었다. 옛날에 MDIR도 이걸 지원했다. 파일이 복사· 이동· 개명· 삭제됐을 때 주석도 같이 관리하는 게 좀 번거로운 일이 됐으니까.. NTFS처럼 운영체제의 파일 시스템 차원에서 메타데이터를 관리하는 기능이 없으면 어쩔 수 없이 셸 유틸리티가 뒷감당을 해야 한다.

4. MS-DOS의 한글화

MS-DOS가 최초로 한글판이 나온 것도 2나 3 버전부터이지 싶다. 정말 먼 옛날에는 마소가 잠깐 동안 조합형 코드 기반으로 도스를 한글화화기도 했다는데 지금으로서는 거의 Windows 2.1의 한글판 같은 도시전설이 돼 간다.
허나, 1987년에 지금의 KS X 1001, 그 당시의 KS C 5601 완성형이 제정되자마자 표준을 잘 지키는 마소는 완성형으로 광속으로 갈아탔다. 그게 이미 도스 3 시절의 일이다. 마소는 그냥 표준을 따른 것일 뿐이지만, 결과적으로 조합형 코드를 죽이고 한글을 파괴한 원흉(?)으로 일부 진영으로부터 좀 지탄받곤 했다.

그런데 한글 MS-DOS가 텍스트 모드에서 한글 입출력을 구동해 주는 바이오스 유틸리티를 처음부터 내장하고 있지는 않았던 것 같다. 쉽게 말해 hbios와 그 특유의 바탕체 글꼴을 구경한 건 최소한 도스 5나 6부터이다. 3이나 4 시절에나 그런 게 없었으며, 한글 바이오스는 다른 프로그램으로 구동했었다. 이건 내 기억이 잘못됐을 수도 있음.

hbios는 Windows 95로 가면서 mshbios로 이름이 바뀌었으며, 그 당시의 고유 글꼴은 <날개셋> 편집기에 '마소바탕'이라는 글꼴을 통해 구경할 수 있다. 도깨비나 태백한글 같은 싸제 한글 바이오스들은 조합형/완성형, 두벌식/세벌식, 명조/고딕 등 글꼴과 글자판과 코드를 다 선택 가능했지만, 마소의 보급 바이오스는 당연히 완성형, 두벌식, 명조로 다른 선택의 여지가 없었다.

전에도 한번 얘기한 적이 있었지만, 마소에서 한글화한 프로그램들은 2바이트 문자에 대한 처리가 굉장히 잘 돼 있었다. 2바이트를 구성하는 앞뒤 문자 중 하나가 가려지거나 지워지면 다른쪽 문자도 반드시 같이 사라졌기 때문에 텍스트 모드에서 메뉴나 대화상자가 표시될 때도 문자가 깨지는 걸 보이는 법이 없었다. 이에 대한 처리가 세심하게 돼 있었다.

5. 도스 시절의 멀티태스킹

비록 그래픽은 아니고 텍스트 기반이긴 하지만, Windows 3.x 비스무리한 도스 기반 멀티태스킹 운영환경(운영체제는 아니고..)으로 DESQView 같은 프로그램이 있었다. 난 이름만 들어 보고 실제로 구경은 못 했다. 외국에서는 그럭저럭 쓰는 사람이 있었던 듯하지만 Windows의 등장 이후에는 조용히 역사 속으로 사라졌다.

그리고 사실은 더 발전된 멀티태스킹 운영체제를 마소에서 직접, 그것도 Windows나 OS/2와는 별개로 만들려는 시도를 한 적이 있었다. 무려 1986년, Windows조차 이제 막 개 허접한 1.0이 나왔던 시절에 MS-DOS 3을 기반으로 일명 '멀티태스킹 MS-DOS 4.0'이 계획되었던 것이다. 이것은 앞서 언급한 그 도스 4.0과는 무관한 새로운 개발 브랜치였다.

멀티태스킹 MS-DOS 4는 제품이 나오기는 했고 의도도 나쁘지 않았지만, 1980년대 중반에 시대를 너무 앞서간 문제작이었다. 그 옛날에 그 열악한 하드웨어 환경에서 도대체 뭘 더 바라겠는가? 컨셉에 비해 상품성이 떨어졌다.
게다가 그 당시 마소는 지금처럼 독자적인 불특정 다수용 유명 소프트웨어를 독점 판매하는 공룡 기업이 아니었으며, 여전히 하드웨어 제조사에다 소프트웨어를 납품하면서 먹고 사는 기업이었다. 즉, 지금으로서는 상상이 잘 안 되지만, 업계에서의 위상이 '갑'이 아니라 '을'이었다.
프로젝트를 발주했던 IBM이 이 물건을 더 구입해서 사용하지 않겠다고 선언하자 프로젝트는 흑역사가 되었고, 이 멀티태스킹 MS-DOS 4는 오히려 유럽의 일부 컴퓨터에 OEM 형태로 공급되는 걸로 개발 계보가 끝났다.

멀티태스킹 MS-DOS 4는 비록 GUI 환경은 아니지만 Windows의 전유물로만 알려졌던 NE (new executable) 실행 파일도 지원하고 지금으로서는 무척 신기한 면모가 많았다고 한다. 정작 NE를 사용하던 Windows는 NT가 등장하기 전에는 콘솔 모드라는 게 없었는데, GUI 기반이 아니던 멀티태스킹 도스가 NE를 어떤 형태로 사용했는지 궁금하다.

6. 맺는 말

도스 시절에 메모리 관리를 하는 건 요즘으로 치면 연봉별로 돈 관리하는 요령과 비슷했다. 램이 1MB 이하일 때, 2MB일 때, 4MB일 때, 8MB 이상일 때... HIMEM.SYS와 EMM386을 세팅하는 법, 기본 메모리를 최대한 확보하는 법, 메모리가 왕창 많이 있다면 램 드라이브와 디스크 캐시를 운용하는 요령 등.. 그런 게 1990년대 컴퓨터 잡지들이 고급 정보랍시고 많이 다룬 정보였다.
지금으로서는 그저 격세지감이 느껴질 뿐이다. 그 당시에 기본 메모리라는 개념은 돈에다 비유하자면 당장 손에 있는 현금이고, 나머지 확장 메모리는 통장 잔고나 신용카드 같다는 생각도 든다. =_=;;

MS-DOS의 역사를 살펴보면 많은 걸 느낀다. 금수저 출신의 독종에 천재에 똘끼와 운, 엔지니어 기질과 사업가 기질을 모두 갖고 있는 사람이라면 무슨 여건에다 던져 놔도 결국은 성공했겠다 싶다. 공부만 계속했어도 교수나 변호사가 됐을 사람이 결국은 소프트웨어의 황제로 등극해서 교수· 변호사보다 더한 억만장자가 됐으니까.

물론 빌 역시 그 과정에서 언제나 실력만으로 정정당당하게 승부하지는 않았으며, 경쟁자 치사하게 죽이기 같은 짓을 전혀 안 했다는 건 아니다. MS의 모든 기술과 제품이 100% 빌의 머리에서 비롯된 원천기술인 건 아니며, 그가 미래에 대해 예측한 것이 전부 적중한 것도 아니었다. 그래도 그는 자기보다 더 똑똑한 엔지니어들을 한데 통솔하고 이끌어서 시너지 효과를 잘 낼 줄을 알았다. 그리고 실수를 하고 병크를 저지르더라도, 회사를 완전히 말아먹을 정도로 치명적으로 하지는 않았으며 곧 수습했다.

한편, 게리 킬달은 뭔가 스티브 워즈니악 같은 포스가 느껴지는 공돌이로 보이는데, 실력에 "비해" 빛을 못 보고 좀 어이없게 훅 가 버린 게 안타깝게 느껴지기도 한다.
기술만 있고 너무 고지식하기만 하면 저렇게 되기 쉬운데, 나부터가 딱 그런 스타일이라는 게 문제임.. -_-;;

Posted by 사무엘

2016/05/18 08:39 2016/05/18 08:39
,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1228

도스와 유닉스 명령창 공히 디렉터리를 이동할 때는 cd 내지 chdir이라는 명령을 사용한다. 단, 도스는 드라이브 이름을 A~Z 알파벳 한 글자로 표현한다는 게 마치 날개셋의 수식 변수만큼이나 특이하며, Windows는 이 관행을 그대로 물려받았다. 파일명에 대소문자를 구분해서 표현은 하지만 유닉스와는 달리 이를 서로 다른 것으로 취급하지는 않는다. 또한 디렉터리 구분자가 /가 아니라 \(역슬래시)라는 것도 유닉스 계열과 다르다.

그 뿐만이 아니다. 도스는 cd라고만 치면 현재 디렉터리를 표시만 해 주는 반면, 유닉스는 cd라고 치면 그냥 자신의 홈 디렉터리, Windows로 치면 "C:\Users\계정명" 정도로 이동해 버린다. 도스가 유닉스의 다른 개념들은 다 따 왔어도, 이건 다중 사용자라는 개념이 없던 물건이다 보니 홈 디렉터리 같은 건 도입하지 않기 때문이다. 유닉스에서 지금 디렉터리를 표시하는 명령은 잘 알다시피 pwd라고 따로 있다.

그렇게 도스와 유닉스 계열이 차이가 나는 와중에도 . 가 현재 디렉터리를 의미하고 ..는 부모 디렉터리를 의미한다는 건 둘이 동일하다. cd ..를 하면 부모 디렉터리로 갈 수 있다. 다만, 문법이 둘이 완전히 동일한 건 아닌지라.. 도스는 cd..라고 둘을 띄지 않아도 됐던 반면, 유닉스는 둘을 띄워야 한다는 깨알같은 차이점이 또 있다.

그런데 Windows 9x의 도스창에서는 숨겨진 기능이 더 있었다. cd 다음에 점을 세 개 이상 늘어놓음으로써 두 단계 이상의 조부모 디렉터리로 이동이 가능했다. cd...처럼. 그럼 저건 cd ..\.. 를 의미한다. 네 개 이상 숫자를 얼마든지 늘어놓아도 된다.
게다가 이건 파일 시스템 차원에서 공식적으로 인식하기라도 하는지, 굳이 cd에서만 쓸 수 있는 게 아니다. dir ... 이라고 하면 두 단계 상위 디렉터리를 조회할 수 있고, Windows의 파일 열기/저장 대화상자에서도 "..."이라고 치면 동일 기능이 동작했다.

Windows 9x는 C:\Windows 디렉터리를 가 보면 readme 등 몇몇 '읽어 보세요' 문서가 html이나 doc나 rtf가 아니라 txt 파일로 들어 있었는데, 그 중엔 tips.txt가 있다. 그 파일에 cd...에 관한 언급이 존재한다.

MS-DOS COMMAND PROMPT
=====================

Directory Shortcuts
-------------------
Related directories have the following shortcuts:

. = current directory
.. = parent directory
... = parent directory once removed
.... = parent directory twice removed

For example, if you are in the C:\Windows\System\Viewers
directory, and you enter cd... at the command prompt, the
directory changes to C:\Windows.


위는 영문판 Windows ME, 아래는 한글판 Windows 95의 tips.txt 내용 일부이다.

* 디렉토리 단축키
다음과 같은 디렉토리 관련 단축키를 사용할 수 있다.
. = 현재 디렉토리
.. = 상위 디렉토리
... = 하나의 디렉토리가 삭제된 상위 디렉토리(Windows 95에 새로 추가)
.... = 두 개의 디렉토리가 삭제된 상위 디렉토리(Windows 95에 새로 추가)
예를 들어, C:\Windows\System\Viewers 디렉토리에서 명령 프롬프트에 cd....를
입력하면 디렉토리는 C:\로 바뀐다.


이 기능은 이전의 도스 시절엔 존재한 적이 없었으며 Windows 95에서 처음으로 추가되었다는 것이 명시되어 있다. 또한 95의 문서에서는 ....로 디렉터리를 세 단계 건너뛰는 예를 제시하는 반면, 후대 98/ME의 문서는 ...로 두 단계만 건너뛰는 예를 제시한다. C:\로 바뀌는 건 cd\와 동일하기 때문에 예제를 바꾼 게 아닌가 싶다.
참고로 Windows의 한글판은 98부터 '디렉토리'라는 표기가 '디렉터리'로 바뀌고, 문서들의 문체가 반말에서 존댓말로 바뀌었다.

놀라운 사실은, 이 기능은 오늘날의 Windows NT 계열에서는 지원되거나 존재한 적이 전혀 없었고 오로지 95, 98, ME만의 관행이었다는 점이다.

사용자 삽입 이미지

The old new thing 블로그의 설명에 따르면 cd ...는 노벨 네트웨어(Novell NetWare)라는 네트워크 솔루션에서 제공하는 명령 문법과의 호환성 때문에 편의 차원에서 도입된 기능이라고 한다. 그땐 노벨 사의 IPX/SPX 프로토콜 기반으로 네트워크 구성요소들도 있었으니 수긍이 간다.

그리고 9x와 달리 NT에서 ...를 지원하지 않은 이유는, 윈NT가 사용하는 NTFS 파일 시스템에서는 '.'나 '..'와는 달리 '...'는 그 자체가 올바른 파일이나 디렉터리 이름이 될 수 있기 때문이다. 그렇기 때문에 NT 계열에서는 이런 기능을 앞으로 지원할 의향은 더욱 없다고 봐야 할 것이다. 그냥 cd..\..를 해야지, 약칭인 cd...는 IPX 프로토콜이 존재하던 Windows 9x 시절의 추억으로 old timer들에게 남을 것으로 보인다.

9x 시절에는 dir con\con이던가, '실행' 대화상자에서 con\con 이런 걸 치면 운영체제를 뻗게 하고 도스창을 강제 종료시키는 게 가능했다. 이건 꽤 유명한 버그였으며 ME에서야 보정을 통해 패치가 됐다. cd ...는 그것만큼이나 9x 시절에 파일 시스템과 관련해 흥미로운 고유 아이템 추억거리인 것 같다.

여담으로, 명령 프롬프트에서 공백은 여러 명령 인자 토큰들을 구분하는 역할을 한다. 그렇기 때문에 거기서 공백이 들어간 파일을 표시하기 위해서는 파일명 전체를 ""로 싸야 하며, 각종 프로그래밍 언어에는 따옴표 문맥을 인식하면서 공백 기준으로 명령 인자들을 파싱· 토큰화하는 라이브러리도 존재한다. 그러나 이 cd 명령만은 예외로 공백이 들어간 디렉터리도 CD Program Files 라고만 쳐도 인식되게 되어 있다. cd /?를 해 보면 이 사실을 확인할 수 있음.

그리고 cd에는 드라이브까지 같이 변경하는 명령이 한동안 존재하지 않았다. 도스 커맨드 셸의 대체제이던 4DOS 내지 NDOS에서는 자체적인 명령 확장을 통해서 그런 기능을 제공하곤 했는데, 오늘날 Windows에서는 /D 라는 별도의 옵션을 줘야만 드라이브도 변경 가능하다. 아마 드라이브를 변경하지 않는 게 보장된다는 무슨 호환성 때문에 옵션 형태로 기능을 추가한 것 같다. 참고로 /D는 9x의 도스창에는 존재하지 않으며, Windows NT 계열의 명령 프롬프트에만 있다. ...를 지원하지 않는 대신 /D가 있는 셈이다.

Posted by 사무엘

2016/04/16 08:30 2016/04/16 08:30
,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1215

1.
먼 옛날, 윈도 98을 쓰다가 2000으로 갈아탔을 때, 난생 처음으로 Windows NT 계열을 구경하고서 굉장히 놀랐던 기억이 지금도 선하다.

NT 계열은 일단 마의 리소스 퍼센티지 제약이 없었으며, 말로만 듣던 2바이트 문자열 기반의 유니코드 API가 잘 지원되었다. 이 둘은 매우 크게 다가온 아이템이다.
작업 관리자가 9x 계열에 비해서는 넘사벽급으로 잘 만들어져 있었고, 도스창이 아닌 정식 명령 프롬프트가 제공되었다. 이 외에도 EXE/DLL 내부의 리소스를 수정하는 API가 사용 가능한 것도 좋았다. (9x 계열은 16비트 바이너리의 리소스만 고칠 수 있었음)

윈도 95/98에서는 못 보던 파일은 ntoskrnl.exe, csrss.exe, lsass.exe, ntdll.dll, hal.dll, ntvdm.exe, svchost.exe 등이다.
그 반면, 윈도 9x의 잔재이던 파일은 msgsvr32.exe, win386.swp, system.dat, user.dat, winoa386.mod, *.vxd, win.com 같은 것이다.

윈도우 2000/XP부터는 NT 커널 덕분에 주기적으로 재부팅을 할 필요가 없어졌다.
하지만, 주기적으로 재설치도 거의 할 필요가 없어진 건 Vista 이상인 듯하다. XP는 이 범주에까지 넣기에는 좀 2% 부족한 구석이 있었다.

2.
과거에 Windows 9x 시리즈와 Windows NT는 구조적으로 여러 차이가 있었지만, 프로그래머의 관점에서 중요한 특징 중 하나는 '이식성'이었다.
NT는 하드웨어에 종속적인 계층이 철저히 분리되어 설계되었으며 커널이 대부분 어셈블리가 아니라 C/C++이라는 '고급 언어'로 작성되었다. 마치 유닉스처럼. 덕분에 인텔 x86뿐만 아니라 90년대 당시로서는 MIPS, Alpha 등 다양한 아키텍처용 윈도 NT가 나오기도 했다.

NT는 설계 차원에서 특정 하드웨어의 특성에 맞는 '타협'을 별로 안 하고 추상화 계층이 많이 존재하다 보니 깔끔함, 안정성, 범용성 등 많은 장점을 얻을 수 있었다. 게다가 그 시절에 벌써 유니코드를 염두에 두고 wide string을 기본적으로 사용하기 시작한 건 상당한 선견지명이다. 물론 그 대신 시스템 요구 사항이 당연히 1990년대의 가정용 PC가 도저히 범접할 수 없을 정도로 높았다. 메모리와 속도 모두.

이런 NT와는 달리, Windows 95는 이상이 아닌 현실을 추구하였다. 도스와 윈도 3.1을 돌릴 수 있는 정도의 램 한 자릿수 MB대 똥컴을 타겟으로 하여 Win32 API를 최대한 많이 구겨 넣었다. 이 과정에서 지금은 당연시되고 있는 유니코드 API조차도 메모리를 필요 이상으로 많이 잡아먹는 다고 판단되어 과감히 짤려 나갔다.

9x 커널의 소스에는 도스 레거시를 비롯해 오로지 x86 CPU에만 최적화된 쑤제 어셈블리 코드가 난무하였다. 그렇게까지 극도로 최적화를 하고 성능을 짜내야만 메모리 사용량을 1K라도 줄일 수 있을 테니 말이다. 9x는 NT보다 배고픈 운영체제인 것이다. 그럼에도 불구하고 OS/2를 PC 환경에서 완전히 몰아내고 Windows 천하통일을 이루는 데 기여한 일등공신은 NT가 아니라 95였음이 부인할 수 없는 사실이다.

OS/2를 개발하던 마소의 엔지니어들이 떨어져 나가서 따로 만든 게 NT라고는 하지만, OS/2 자체는 NT 같은 이식성 있는 형태라기보다는 9x에 더 가까운 어셈블리 최적화 컨셉이었다고 한다. OS/2는 NT 뺨치는 수준의 앞서 나간 최첨단 운영체제이긴 했지만, 내부 구조가 이식성보다는 역시나 x86에 너무 종속적이었다는 뜻. 그래서 다른 아키텍처로 이식은커녕, 같은 x86 컴에서 가상화 소프트웨어로도 돌리기가 곤란할 정도라고 한다.
(그래도 지금은 x86에서 맥 OS X 해킨토시까지 돌리는 세상이 됐는데 설마 OS/2를 못 돌리나 싶다.)

3.
더 옛날, 도스 시절에는 뭔가 새로운 하드웨어를 사용하려면 램 상주 프로그램을 덕지덕지 실행해 놔야 해서 몹시 불편했다. CD롬조차도!

  • 사운드: sound / unsound (굉장한 옛날 유물. 왠지 '불건전하다!'가 생각 나는 건 기분 탓. ㅋㅋㅋ)
  • 그래픽: simcga, msherc (이것도 옛날 유물. msherc의 경우, QuickBasic에도 포함돼 있었다.)
  • 마우스: mouse (단, 윈도 3.x는 별도의 램상주 드라이버 없이도 마우스를 스스로 인식하여 실행되었음!)
  • CD롬: mscdex (기본 메모리를 상당히 많이 차지했음)

아마 USB 포트가 도스 시절에 도입됐다면, 이걸 인식시켜 주는 램 상주 프로그램도 당연히 필요했을 것이다.
아, 텍스트 모드에서 한글을 구동해 주는 프로그램도 빼먹을 수 없다. hbios / mshbios(윈도 95) 같은 것.
그 외에 화면 캡처나 게임 위저드 같은 램 상주 유틸리티는 하드웨어 인식보다는 편의 기능 분야에 속한다.

요즘은 환경변수 같은 건 PATH에서나 제일 많이 쓰이고, C/C++ 프로그래머에게는 컴파일러의 동작에 필요한 include 및 라이브러리 디렉터리를 지정할 때나 쓰이는 게 고작이다.
하지만 옛날에 사운드 블래스터라는 사운드 카드가 있던 시절에는 기본 IRQ 번호던가 뭔가도 환경변수에다 지정해 놓곤 했으며, 각종 게임의 환경설정 프로그램에는 사운드 종류와 그런 세부 정보도 입력을 받곤 했다.

이것도 정말 까마득한 옛날 얘기가 됐다.
도스용 프로그램들에는 파일 메뉴에 '도스 나들이(DOS Shell)' 기능이 있던 시절이니까 말이다.
운영체제가 이렇게 방대하고 권한이 커지면서 상당수의 유틸리티들은 의미를 퇴색했으며, 전문화된 고급 셸 아니면(토탈 커맨더 같은) 더 전문적인 유지보수 유틸리티(노턴 고스트?) 내지 안티바이러스/보안 쪽으로 업종을 세분화· 전환하는 게 불가피해졌다.

4.
태초에 도스는 검은 화면에 흰 프롬프트밖에 없었을 뿐만 아니라 명령어를 입력하는 환경도 굉장히 자비심이 없었다.
삽입/삭제 모드 같은 개념이 없을 뿐만 아니라, 애초에 이미 입력된 글자를 지우지 않고서는 앞 글자로 cursor를 옮기는 것 자체가 불가능했다. 즉, 왼쪽 화살표만 눌러도 마치 bksp를 누른 것처럼 앞글자가 지워지면서 cursor가 앞으로 이동했다.

명령 히스토리는 직전의 딱 한 단계만 지원했다. F1~F3을 눌러서 직전 명령을 한 글자씩 복구하거나 첫 n 글자 또는 전체를 한꺼번에 불러오곤 했다. 그 시절을 혹시 기억하는 분이 계시는지?

그나마 doskey.com이라고 아마 도스 3~4쯤에서 추가된 걸로 추정되는 외부 명령 램 상주 유틸리티를 실행하면 위/아래 화살표로 히스토리가 가능하고 좌우 cursor 이동이 자유롭게 가능해졌다. 지금은 너무 당연하게 여겨지는 기능이 옛날에는 별도의 프로그램을 통해서만 접근 가능한 액세서리 기능이었던 것이다.

윈도 NT의 명령 프롬프트는 기본적으로 이 모드인 듯한데, 그런데 tab을 눌러서 파일/디렉터리 이름을 자동 완성하는 기능은 윈도 XP에서 처음으로 추가되었다. 세상에, NT4와 2000 시절까지만 해도 이런 기능이 없었으며, tab을 누르면 그냥 문자적인 탭이 그대로 삽입되곤 했다.

단, 기능 추가만 있는 건 아니다. 윈도 XP까지는 탐색기에서 파일이나 디렉터리를 명령 프롬프트에다 drag & drop을 하면 그 이름을 자동으로 삽입해 주는 기능이 있었는데 아마 윈도 Vista부터는 그 기능이 의도적으로 삭제되었다. 보안 때문에 취해진 조치라고 하는데 이런 편리한 기능에 도대체 무슨 보안 문제가 있는지는 나로서는 알 길이 없다.

명령 프롬프트를 전체 화면으로 실행하는 기능 역시 Vista에서부터 삭제되었다. 딱히 별 의미가 없어지기도 했으니.
어디 이 뿐이랴. 2000까지만 해도, 콘솔창 내용을 마우스로 긁는 '빠른 편집' 모드는 곧장 사용 가능했던 반면 XP부터는 먼저 속성 창을 거쳐서 강제로 켜야만 사용 가능하게 바뀌었다. 이건 보안 이유 때문은 아니고, 마우스를 지원하는 도스용 프로그램과의 호환 때문에 취해진 조치라고 한다.

제아무리 도스 기반이 아닌 NT 계열의 명령 프롬프트라 해도, 문자 인코딩부터가 2바이트 ANSI 코드 페이지와 여전히 얽혀 있고 도스의 흔적을 완전히 걷어내지는 못한 듯하다. 그래도 64비트부터는 16비트 코드 자체가 이제 지원되지 않는데 더 좀 걷어내도 되지 않나 싶다.
기존 명령 프롬프트보다 더 강력한 대체제라고 일컬어지는 PowerShell이라는 물건이 있긴 하나, 본인은 그런 게 있다는 것만 알고 이게 특별히 장점이 무엇인지는 알지 못한다.

아 그리고. 지긋지긋한 Terminal 내지 굴림체 말고 Consolas 내지 Courier, Lucida Console 같은 글꼴을 좀 쓰고 싶은데 Wndows는 공식적으로는 명령 프롬프트의 글꼴을 자유자재로 바꾸는 방법을 제공하지 않는다. 마치 uxtheme을 해금/탈옥시키듯이 레지스트리를 조작해서 글꼴을 바꾸는 방법이 인터넷에 있긴 한가 본데 본인은 성공하지 못했다.

Posted by 사무엘

2015/03/02 19:28 2015/03/02 19:28
, , ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1068


블로그 이미지

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

- 사무엘

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:
3057875
Today:
2398
Yesterday:
1713