1) 지식 창고는 본인이 작성한 콘텐츠(팁/노하우/리소스/강좌 등)을 무료 혹은 가상화폐인 납포인트를 통해 공유하는 공간입니다.
2) 본인이 작성한 콘텐츠에 대해서만 지식 창고에 등록할 수 있으며, 저작권에 위배되는 콘텐츠는 사전경고 없이 삭제될 수 있습니다.
3) 콘텐츠 구매 및 첨부파일 다운로드는 회원그룹 '연구원' 이상 가능하오니, 경험치를 쌓아 진급한 후에 이용 부탁드립니다.
4) 무료 콘텐츠의 본문은 구매절차 없이 즉시 이용할 수 있으며, 판매 납포인트가 있는 콘텐츠는 구매 후 이용할 수 있습니다.
5) 콘텐츠 판매에 따른 납포인트 수익은 지정한 비율(50%)에 따라 판매자에게 지급하며, 납포인트 수익을 통해 진급을 빨리할 수 있습니다.
6) 구매 후 평가를 하면 구매 납포인트의 20%를 돌려 드립니다.
판매자 | 프리미엄 | 판매 납포인트 | 무료 | 평점 | 0점 / 총 0명 참여 |
---|
***************************< 캠퍼스 C 강좌 >******************************
[제목] :
[코드] : campusc1-022 (초급)
[교재] : CAMPUS C (초급, Third edition) [출판사 : 책과스승]
[알림] :이 파일은 "캠퍼스 C"에서 모든 분께 공개한 "초급 강좌"입니다.
이 [알림]의 내용을 지우지 않는다면 누구에게나 임의로 복사해 줄 수
있습니다.그러나 이 강좌 내용에 대한 저작권은 "캠퍼스 C"에 있습니다.
[연락처] : 605-8662 (서울) ("캠퍼스 C", 도서출판 "책과 스승")
천리안 : go campusc
나우콤 : go lcampc
하이텔 ID : campusc
****************************<< 목 차 >>************************************
<1> CPU 에 대해서..
1> CPU에 대해서 알아야 할 것 ( 소프트웨어 측면에서 )
2> 일반 레지스터 4개 ( AX, BX, CX, DX )
3> 세그먼트 레지스터 4개 ( CS, DS, SS, ES )
4> 기타 레지스터 ( SP, BP, SI, DI )
5> 플래그 ( Flag ) 레지스터
<2> IBM-PC 에서 주소 만드는 법
<3> 디버거(debugger)를 이용하여 CPU를 건드려 보자
1> 디버거의 기능
2> CPU 의 레지스터를 조작하자.
3> 메모리를 조작하자.
**************************< 내용 시작 >********************************
<1> CPU 에 대해서..
1> CPU에 대해서 알아야 할 것 ( 소프트웨어 측면에서 )
2> 일반 레지스터 4개 ( AX, BX, CX, DX )
3) 세그먼트 레지스터 4개 ( CS, DS, SS, ES )
4) 기타 (SP, BP, SI, DI,)
5) 플래그 ( Flag ) 레지스터
***********************************************************************
1> CPU에 대해서 알아야 할 것 ( 소프트웨어 측면에서 )
-----------------------------------------------------------------------
복잡한 스트락춰를 계속하느라고 재미가 없는 것 같은데, 오늘은
프로그램 이란걸 좀더 근본적으로 알기 위해서, 기본 내용을 다뤄 보기로 합
니다. 그렇다고 스트락춰의 내용이 끝난 건 아닙니다. 스트락춰는 이제 우리
의 새로운 기초가 된 것일 뿐으로서 앞으로 우리의 강좌가 끝날 때까지 계속
될 것입니다.
오늘 다뤄 볼 내용은 C 가 컴파일된 후 프로그램은 실제로 어떻게
돌아가는지를 알아 보자는 것인데, 그 중에서도 CPU와 메모리 의 관계를 좀
더 근본적인 측면에서 다뤄 봅니다.
CPU 가 어떻게 생겼는지는 아실 것입니다. 아직도 형태를 모르시면
지금이라도 컴퓨터를 끄고 뜯어보세요. 그리고 CPU의 "역할" 및 "중요성"에
대해서도 더 이상 언급을 안해도 어느 정도 짐작하실 것입니다.
하드웨어 적인 측면에서 보면 CPU에 대해서 공부할 것은 정말 많지
요. 그에 비해 소프트웨어 적인 측면에서는, 즉 다시 말해서 우리 같이 프로
그램을 짤 사람들이 CPU에 대해서 알아야 할 것은 비교적 간단합니다. 그것
을 정리하면 다음과 같습니다.
1. 데이터 버스(data bus)의 폭은 얼마인가 ? (2,4,8 바이트인가 ?)
2. 어드레스 버스(address bus) 의 폭은 얼마인가 ? ( // )
3. 레지스터 의 종류 및 역할
이 3 가지 측면에서만 고려하면 됩니다. 이 중에서 1, 2 번은 [19쪽]
의 아래에 표로 잘 정리되 있습니다.
"어드레스 버스"와 "데이터 버스"에 관해서는 공개강좌에 따로 자세
하게 쓴 적이 있으므로 그걸 읽어 보시면 더욱 자세히 이해가 되실 것이고,
여기서는 간단히 언급해 보면,
첫째로 "데이터 버스"의 폭은 고속도로의 차선과 같은 개념이라고
했습니다. 즉 표에서 8086 CPU는 "16"이라고 되있는 데 16차선입니다.
80386DX 같은 것은 "32" 차선이지요. 따라서 당연히 이 값이 클수록 "정체현
상" 없이 차가 더 많이 지나갈 수 있는 것이지요. 이 폭은 숫자의 크기에 비
례해서 성능이 좋아지는 것이지요. 예를 들면 16비트 짜리 보다 32비트 짜리
는 정확히 2배의 데이터를 동시에 더 실어 나를 수 있는 겁니다. 요즘 맥킨
토시에서 선전하는 "파워(power) PC"는 64비트 짜리라고 선전하고 있지요.
정말 놀라운 발전입니다. 저는 대형 컴퓨터에 대해서는 잘 모르지만, 128 비
트짜리 컴퓨터 얘기를 들어본 기억이 없습니다. 그렇다면 아무리 커봐야 64
비트 짜리 라는 얘기인데, PC(개인용 컴퓨터) 주제에 외형상 같은 용량을 가
지다니 놀라울 지경입니다. 이 정도쯤되면 "워크스테이션 (workstation)"과
는 거의 구분하기가 불가능한 지경에 이르고 말았습니다. 일반적으로 워크스
테이션이란 것은 PC(개인용 컴퓨터) 보다 한 단계 윗급의 성능이라고 여겨져
왔는데, 이런식으로 PC가 발전하면 더이상 이런 구분은 무의미하지요. 좌우
간 데이터 버스의 폭은 이와 같이 컴퓨터의 기본적인 성능에 아주 중요한 요
소 입니다.
둘째로 "어드레스 버스"의 폭은 현재 8086인 경우 20비트 인데, 이
크기면 1M의 메모리 아파트 주소를 지정할 수 있다는 것을 아시지요 ? 이것
도 잘 모르시는 분은 [2쪽]부터 시작 되는 "크기의 세계"를 먼저 읽어 보세요.
여기서도 잠깐만 설명을 하면, 이 어드레스 버스는 데이터 버스와 달리 약간의
계산을 필요로 하지요. 예를들면 어드레스 버스가 "한 가닥" 있다고 칩시다.
그리고 다음과 같이 설계를 합니다.
1. 이 버스에 전기가 흐르면 "0 번지" 메모리 아파트 가 열린다.
2. 전기가 안 흐르면 " 1 번지" 아파트에 문이 열리도록 한다.
이와같이 전기줄 "한 가닥"으로 "2 가지" 경우의 선택을 할 수 있기
때문에 2가닥이 있으면 4가지 경우( 2 x 2)의 경우가 되는 겁니다. 즉 선이
하나씩 늘어날 때마다 "2배" 씩 용량이 커지는 것이지요. 따라서 어드레스
버스가 20비트인 8086 CPU16비트인 경우 "2의 20제곱"인 1M 인데 반하여 어
드레스 버스가 32비트인 80386dx 같은 경우는 4G(기가)로 기하급수적으로 커
지는 것이지요.
술취한 어른들은 가끔 택시를 탈 때 "따불~"을 외치시던데, 혹시 이
"두배(double)"의 위력을 아직도 모르시는 분들은 한번 잘 생각해 보세요.
이런 이야기도 있지않습니까. 컴퓨터를 배운 영리한 학생이 다음과 같이 요
구를 합니다.
"아버지 ! 용돈을 아래같이 주시길 제안 합니다.
1일에는 2원,
2일에는 4원
3일에는 8원
4일에는 16원
5일에는 32원
.
.
.
이렇게 하여 31일 까지 매일 주세요"
즉, 매일 "따불(double)"로 달라는 것이지요. 신문 보시던 정신 없는 아버지
의 경우라면 아들이 갑자기 미쳤나 할겁니다.
"그 돈으로 험난한 이 세상을 매일 어찌 살아 갈려구..."
혹은, 정신없이 "오냐 !" 하고 도장이라도 찍는 날에는 아마 "아들과의 전
쟁"이 한바탕 벌어질 겁니다.
한 달은 31일이 최고지만 그 다음날인 32일의 경우는 CPU 80386DX의
어드레스 버스의 폭과 똑같은 4G (4배 x 2의 30 제곱) 만큼을 아들에게 바
쳐야 됩니다. 기왕 말이 나왔으니 좀더 계산해 볼까요.
4 G --> 4 x 2의 30승
--> 4 x (2의 10승) x (2의 10승) x (2의 10승)
--> 4 x 1024 x 1024 x 1024
귀찮으니까 조금 깍아서 1024를 1000 이라고 하고 계산해 보면,
--> 4 x 1000 x 1000 x 1000
--> 4 x 1000000000
--> 4,000,000,000 원
이게 얼마인지 보기에도 정신이 없는데, 40억이군요. 그러니까 그 전날 31일
에는 "20억"정도만 용돈으로 주면 되겠군요. 이것도 약간 깍은 금액인데...
이제 다시 16진법으로 따지면, 2의 32승은 4G(기가)만큼의 메모리
아파트를 지정할 수 있는 어마어마한 값입니다. 요즘 여러분의 컴퓨터에는
보통 메인 메모리를 4메가 에서 8메가 정도 쓰고 있을 겁니다. 데이타를 많
이 필요로 하는 "그래픽"을 하는 분들이 16메가 에서 32메가 정도를 쓰는 정
도이니 4G (기가) (4096 메가와 같음) 를 사용하려면 아직 멀었지요 ?
따라서 어드레스 버스는, 데이터 버스와 달리 아무리 CPU의 성능이
좋아지더라도 (현재로는) "32비트" 비트 이상 넘어갈 이유가 별로 없습니다.
아직 확인은 못해봤지만, 파워 PC의 어드레스 버스도 32비트 정도 일겁니다.
혹시 정확한 자료를 가지고 계신 분은 좀 알려 주시면 고맙겠습니다.
그리고 기왕 파워 PC 얘기가 나왔으니 잠깐 얘기를 하면 이 CPU의
종류는 RISC ("리스크" 라고 읽음) 타입입니다. 이것은 기존의 80286 ,80386
따위의 CISC ("씨스크" 라고 읽음) 타입과 대조를 이루는 것인데 결론 부터
말하면 RISC 방식이 더 나중에 개발된 방법으로 연산 속도가 더 빠르고 성능
이 좋습니다. 여기서
RISC란 --> Reduced Instruction Set Computing 의 약자이고
CISC란 --> Complexed Instruction Set Computing 의 약자인데
CISC는 해석해 보면 "복잡한 명령어 세트를 가진 계산방식" 쯤 될겁
니다. 여기서 말하는 "명령어 세트" 란 언젠가도 얘기했던 "기계어 명령어
(instruction)"를 말합니다. 아직 기억 하시는지 모르겠는데, 이를테면, CPU
에 "44" 따위의 숫자(명령어)를 넣어주면 "죽어" 라는 뜻이고, "33" 이란 명
령어를 넣어주면 "더해라" 따위의 뜻이라는 것인데, 우리가 지금 쓰고 있는
80286, 80386 따위의 CISC 타입의 칩은 이런 명령어의 수가 정말 "복잡하게
(complex)너무 많다"는 것입니다. 그래서 "좀 간단하게 명령어를 줄여
(reduce) 볼 수 없을 까 ?" 하고 궁리를 해서 만든 것이 "RISC 타입"입니다.
이런 개념은 이미 여러분도 잘 알고 있습니다. 가장 흔한 예로 집에
있는 가전 기기 사용 경우이지요. 요즘 나오는 TV 나 VTR 같은 것들 "예약
녹화"다 " 음향 선택 기능이다" 등등해서 설명서가 공책보다도 두껍지 않습
니까 ? 그런데 혹시 그런 기능 다 쓰고 있는 사람 봤습니까 ?
심지어 우리집에 있는 VTR로는 4년이 다 되도록 테이프 빌려다가 열심히 보
기만 했지 그 흔한 "수동 녹화" 한번 안 해봤습니다. 그래서 가끔 후회도 하
지요. 이럴 줄 알았으면 "재생 전용" 싸구려 VTR을 살 걸 ...
여러분께서도 나중에 어셈블러를 공부하다 보면 이런걸 똑같이 느낄
겁니다. 즉 어셈블러 명령어 중에서 실제로 많이 쓰는 명령어는 몇개 안되고
나머지 수많은 명령어들은 생전가야 쓰지를 않는다는 거지요. 여기에는 두가
지 이유가 있습니다. 첫째는 진짜 쓸일이 없어요. 둘째는 쓸일이 있기는 한
데 다른 명령어를 잘 쓰면 그 일을 할 수 있어요. 그래서 매일 쓰던 익숙한
명령어로 쭈물럭 거리고 해결을 하지, 잘 안써보던 명령어를 쓰려고 하지를
않어요.
좌우간 이래저래 쓸데없이 노는 명령어들이 많아서 사람들이 " 그래
결심했어 ! 이럴 바에야 다 없에버리고 꼭 필요한 명령어만 쓰는, 간단한 명
령어 세트(Reduced Instruction set)를 쓰는 CPU를 만드는 거야 !"
이렇게 만들었으니 물론 나쁠리가 없겠지요. 그래서 현재 까지는 주
로 "워크스테이션" 급의, PC 보다 한 단계 위 수준급의 컴퓨터에서 RISC 칩
을 써왔던 것이지요. 그러나 이제는 버젓이 PC 라는 이름을 붙인 "파워 PC"
가 RISC 방식의 칩을 사용하다니 좌우간 오래오래 살아 봐야 하겠습니다.
펜티엄 칩은 CPU의 구조가 아직도 32 비트 CISC 타입이라고 하는
데, 제가 이 글을 쓰는데 참고로 하고 있는 이 광고가 (파워 PC 쪽 자료 이
기 때문에) 정확한지는 몰라도, 설명 대로라면 펜티엄의 성능이 약간 떨어지
는 것 같군요. 이외에도 CPU의 성능을 구분하는 "수퍼 스칼라 구조"나 "파
이프 라인" 등과 같은 특성이 있지만, 더 자세한 내용은 나중에 중급 과정에
서나 계속 하기로 하지요.
3번 레지스터의 종류및 역할에 대해서는 철저하게 학습을 해야 합니다.
[20,23쪽])에 레지스터의 그림이 있습니다. 이런 레지스터들이
실제로 우리가 쓰는 CPU의 내부에 들어가 있습니다.
그림에 보다시피 286 과 386의 레지스터에는 차이가 있습니다. 따라
서 자세하게 들어가면 기능의 차이가 많지만 지금 C 강좌에서는 그렇게 까지
알아볼 필요는 없고 단지 286에 대해서만 알아봅니다.
지금 우리가 쓰고 있는 터보 씨 컴파일러도 기껏해야 286 명령어밖
에 만들어 내지 못합니다. 따라서 여러분이 아무리 386, 486 컴퓨터를 갖고
있어도 사실, 터보 씨를 쓰는 한 그다지 좋은 성능을 내지 못할 것입니다.
터보 씨 컴파일러에 가서 [Options] [Compiler] [Code generation]
[Instruction set] 을 줄줄이 선택해 봅니다 여기서 "8086/88" 이나
"80186/80286" 을 선택할 수 있게 되있습니다. 혹시 그나마 8086/88 로 선택
돼 있는 분들은 80186/80286 으로 바꿔 놓으시길 바랍니다.
볼란드 C++ 컴파일러에서는 386 코드를 만들어 내므로 386 이상이
되는 시스템을 가지신 분들은 이런 컴파일러를 사용하는 게 좋을 것입니다.
그러나 소프트웨어 세계에서는 항상 "호환성" 이라는 문제가 있습니다. 386
코드로 생성 되 있는 프로그램은 당연히 286 시스템에서는 돌아가지 않을 것
입니다. 따라서 개인적으로 사용할 프로그램이라면 상관없겠지만 상품으로
나갈 프로그램이라면 심각하게 고려를 해 봐야 합니다. "과연 모든 사람들이
386 시스템을 가지고 있는지를.."
따라서 이제부터, 가장 기초가 되는 286 CPU의 레지스터들을 아래에
서 기능별로 자세하게 알아봅니다.
-----------------------------------------------------------------------
2> 일반 레지스터 4개 ( AX, BX, CX, DX )
-----------------------------------------------------------------------
[20쪽])의 그림 중 제일 윗 부분에 있는 4개의 레지스터를 우리는
일반 레지스터라고 (general purpose REGISTER) 라고 부르지요.
우연인지 필연인지 이름이 외기도 쉽게 a,b,c,d 순으로 AX,BX,CX,DX
입니다. 이 이름들의 의미는 책의 "명칭"에 나와 있습니다.
여기서 주의할 것은, 예를 들어 AX 레지스터는 AH 와 AL 두개를 동
시에 지칭하는 말입니다. 그리고 따로 따로 부르려면 "AH 야! " " AL 야 !"
하고 부릅니다.
이런 경우는 흔하게 있습니다. 예를 들어 강도 따위를 만나면 "손들
어" 하고 외치지요. 이런 때 보통은 두손을 동시에 듭니다. 구체적으로 주문
할 수도 있을 것입니다. "오른손만 들어", "왼손만 들어"...
여기서 의미를 살펴보면,
1. AH 는 ( Accumulator + high) 의 첫글자를 따서 만든 이름이고,
2. AL 는 ( Accumulator + low) 의 첫글자를 따서 만든 이름입니다.
AH 가 위치로 보아 왼쪽에 있어야 한다는 건 이미 알 것입니다. 돈
의 크기도 1234 원이 있다고 치면 12 | 34 로 나눠 왼쪽이 (1천2백) 으로서
(3십4원)보다 큰 단위(HIgh) 라는걸 알 것입니다.
여기서 또 알아야 할 것은 오나가나 들리는 "크기"에 관한 문제입니
다. 사실 여태 까지 C 에서 얘기해 왔던 "1 바이트, 2 바이트 " 따위의 크기
는 전부 지금 얘기하고 있는 CPU의 "레지스터 크기"에 맞춰 발생했던 문제들
입니다. 그러니까 지금 우리는 가장 근본적인 부분을 공부하고 있는 셈입니
다. 정확히 정리해 보면,
AX --> 2 바이트 ( int 와 같은 크기)
AH --> 1 바이트 ( char 와 같은 크기)
AL --> 1 바이트 ( // )
286 CPU 에서는 이와 같이 한번에 취급할 수 있는 가장 큰 단위가 AX 같이 2
바이트(16비트) 이기 때문에 16 비트 CPU 라고 부릅니다.
이에 비해 [23쪽] 386 CPU의 레지스터는 다음과 같은 구조를 가지지요
(똑같은 예를 봅니다)
EAX --> 4 바이트 ( long 과 같은 크기) (Extended AX )
AX --> 2 바이트 ( int 와 같은 크기)
AH --> 1 바이트 ( char 와 같은 크기)
AL --> 1 바이트 ( // )
즉 동시에 4 바이트 (32비트)를 처리(연산, 이동 따위) 할 수가 있
기 때문에 우리는 32 비트 컴퓨터라고 부릅니다.
잠깐 사족을 달면, 컴퓨터 세계에서는 한 바이트는 보통의 경우 무
조건 네모 박스 하나로 그린다고 얘기한 적이 있습니다. [20쪽])의 그림은
이 법칙을 잘 따르고 있습니다. 그러나[21쪽]의 그림은 약간 잘 못 되 있는
것을 알 수 있습니다. 즉 여기서는 2 바이트를 네모 박스 하나에 그리고
있는데 이건 [20쪽] 그림과 연계된 그림이라 이렇게 예외적으로 그린 것이라고
봐도 좋습니다.
이제 각 레지스터의 기능을 잠깐 얘기하면, 이 레지스터들은 말 그
대로 "일반적"으로 쓰는 레지스터이기 때문에 쓰는데 별 제약은 없으나, 가
능한 이름이 의미하는 용도로 쓰는 것이 바람직합니다. 따라서 아래의 설명
은 정확한 설명이라기 보다, "그렇게 쓰는 게 좋다..."는 의미로 이해를 해
야 할 것입니다.
1. AX : 연산할 데이터들을 저장하거나, 기타 여러 가지 경우에 사용
2. BX : 베이스 캠프 로서, 어떤 기준점(base)에 대한 데이터를 저장
3. CX : 순환문 등에서 count (i = 0,1,2,3,4...) 데이터로 이용
4. DX : 연산을 할 데이터의 주소를 저장
-----------------------------------------------------------------------
3> 세그먼트 레지스터 4개 ( CS, DS, SS, ES )
-----------------------------------------------------------------------
세그먼트(segment) 에 대해서 얘기한 적이있는데, 그림에서 보다시
피 4개가 있습니다.
먼저 크기는 2 바이트로서 C 에서의 int와 같은 크기입니다. 따라서
0 부터 64K 까지를 가질 수 있습니다.( 16 비트 : 2 의 16승 --> 2의 6승 K
--> 64 K)
그리고 각 세그먼트 레지스터의 역할을 구별해 보면,
CS : 메모리 안에서 프로그램의 "명령어(code)"들이 모여 있는 곳
(segment)의 처음 번지수를 가리키는 베이스캠프 역할.
DS : 메모리 안에서 프로그램의 "데이터"이 모여 있는 곳(segment)의 처
음 번지수를 가리키는 베이스 캠프 역할.
SS : 메모리 안의 스택영역의 시작 주소 지정
ES : 데이터 가 많을 경우 제 2의 데이터 세그먼트의 역할.
-----------------------------------------------------------------------
4> 기타 레지스터 ( SP, BP, SI, DI, IP )
-----------------------------------------------------------------------
나머지 레지스터의 기능은 다음과 같습니다. 그러나 지금은 그 역할
을 이해하려고 노력할 필요는 없고, 다만 IP (Instruction Point)는 눈여겨
볼 필요가 있습니다.
SP : 메모리 상의 현재 스택을 가리키고 있습니다.
BP : 위의 SP 와 같이 스택의 번지수를 가리키는 역할 등을 합니다.
SI : 데이터들을 옮길 때 시작 번지를 가리키는 용도로 주로 쓰임
DI : 데이터들을 옮길 때 끝 번지를 가리키는 용도로 주로 쓰임
IP : 실행할 명령어를 가리키는 역할.
IP에 대해서 조금더 설명해 보면, 이 레지스터는 우리가 맘대로 값을 넣는
용도로는 사용할 수 없고, 프로그램의 흐름에 따라 자동적으로 값이 변하는
것입니다. 즉, 우리가 짠 프로그램의 명령어를 순서대로 가리키면서 자동적
으로 값이 변해 나가는 것입니다.
-----------------------------------------------------------------------
5> 플래그 ( Flag ) 레지스터
-----------------------------------------------------------------------
플래그 레지스터는 그림에서 보다시피 2 바이트 크기를 가지고 있는
데, 비트 단위로 각각의 역할이 있습니다.
이것들도 연산이 이루어 질 때마다, 값이 자동적으로 바뀌는 것이
있습니다. 지금 단계에서 우리가 관심을 가져야 할 것은 "zero flag" "sign
flag" "carry flag" 정도입니다. 이것들은 연산이 이루어 질 때마다 수시로
값이 바뀌지요. 가장 기초적인 것으로서 우리가 C 에서 a = 100 - 100; 같은
연산을 했다면, zero bit가 "자동적"으로 1 로 바뀝니다.
C 에서 if( a > 0) 같은 문장은 쉽게 이해가 가지만,if(100) 같은
문을 이상하게 생각한 사람이 있었을 것입니다. 이것은 지금 얘기하는 비트
들이 자동적으로 바뀌면서 "특정한" 상태를 나타내기 때문에, 그 결과로 판
단을 할 수 있습니다.
잠깐 부연 설명을 하면, 플래그(flag) 라는 것은 알다시피 깃발을
얘기하는데, 여기서는 해적선에 나부끼는 깃발이나, 중앙청 앞의 태극기 같
은 것을 연상해 봐야 아무 소용없습니다. 정확한 개념은, 기차역이나 비행장
에서 조수들이 흔드는 깃발입니다. 즉 파란 깃발을 흔들면 "안전하다" 빨간
깃발을 흔들면 "서라 오지 마라" 따위의 신호를 나타내는 것입니다.
비행기 운전사들은 멀리서도 이 깃발이 "팍팍" 바뀌는 것을 보고 현
재 활주로의 "상태"를 감지하듯이, CPU 에서도 이 플래그 레지스터들이 "팍
팍" 바뀌는 것을 보면, 지금 이뤄지고 있는 연산의 "상태"를 알 수 있는 것
입니다.
간단한 예를 들면 int 는 최고 0xffff 까지 가질 수 있는데, 다음과
같이 i = 0xffff + 0x0001 연산을 하면 당연히 한계를 넘지요. 그러면
overflow flag 가 당장 "넘쳤다" 라는 의미로 자동적으로 1로 바뀌는 겁니
다.
***********************************************************************
<2> IBM-PC 에서 주소 만드는 법
***********************************************************************
지금 까지 우리는 메모리에서 값을 읽어 오고, 또 값도 쓰고 하는
연습을 많이 해 왔습니다. 그러나 이 과정을 좀더 자세히 살펴보면 우리가
생각 하는 것만큼 간단한 일은 아닙니다. 게다가 80286, 80386 따위의 intel
회사의 CPU들은 더 불편한 과정을 거쳐야 합니다. 좀더 자세하게 예를 들면
이렇지요.
불 자동차 중에 "고가 사다리차" 라는게 있습니다. 아시다시피 불
이 나면 사다리를 쭉 뻗어서 사람을 구출하는 것입니다. 지금 아파트 10층에
서 사람 하나가 살려 달라고 하는데, 여기서 간단한 문제를 하나 내보지요.
<문제> 1. 사다리 차는 최고 8 층까지 닿는다.
2. 소방수의 개인 사다리는 4 층까지 늘릴 수 있다.
이제 소방수가 사다리 차의 꼭대기에서 사람 구출 작전을 펴는데,
사다리차 + 개인 사다리 --> 10층까지 닿을 수 있는 모든 방법은 ?
<답> 8층 + 2층 --> 10층
7층 + 3층 --> 10층
6층 + 4층 --> 10층
국민학교 몇 학년때 이런 문제가 나오는지 기억이 안 나는데, 지금부터 우리
는 이런 연산을 해야 합니다.
내가 위에서 불편하다고 얘기했는데, 문제가 너무 쉬우니까 어떤 사
람들은 상관없다고 생각할지 모르겠으나, 위의 예에서 사다리 차가 만일 10
층까지 닿을 수 있는 신식 자동차라면 우리는 국민학교 산수조차 할 필요가
없는 것입니다. 문제는 거기에 있는 것입니다.
맥킨토시 에서 cpu로 사용하는 680xx 계열 cpu는 사다리차 혼자서
몇 층이고 올라갑니다. 그러나 우리가 쓰고 있는 IBM-PC의 80286, 386 따위
는 꼭 사다리차 + 개인 사다리의 연산을 해야 합니다. 이게 얼마나 번거로운
노릇입니까 ? 소방수가 올라갈 때마다 사다리차 운전사하고 약속을 해야 합
니다. "너는 7층까지만 펴라. 나머지는 내가 펴겠다." 이 같은 짓은 한마디
로 얘기해서 "무식"한 짓입니다. intel 에서 처음 8086 따위를 만들 때는 사
다리차 + 개인 사다리 개념이 얼마나 참신한 아이디어 였는지는 모르겠으나,
이제는 이런 방법을 바꿀 때가 되지 않았나 싶군요.
그러나 어쩔 수 없이 아직도 이런 방법을 쓰고 있는 이유는, 이른바
호환성 때문입니다. 기존에 이런 무식한 cpu를 쓰고 있는 사람이 많기 때문
에 획기적으로 바꾸지를 못하고 286,386,486 시리즈로 계속 나가고 있는 것
입니다.
소문에 의하면, 586에 해당하는 "펜티엄" 부터는 지금 680xx 계열의
cpu 처럼 사다리차 혼자서 다 올라 갈 수 있다니 반가운 이야기입니다.
전문적인 용어를 쓰면
사다리차 --> 베이스 캠프 (세그먼트(segment) 레지스터)
개인 사다리 --> offset ( 기타 레지스터 )
에 해당합니다.
CPU 에서 좀더 구체적으로 예를 들면 이렇습니다. 80286 CPU는 주소
를 가리킬 수 있는 전기 줄이 20 가닥이 나와 있습니다. 이건 곧 20 비트라
는 얘기인데, 크기에 관한 연습을 공개 강좌에서 다룬 적이 있습니다. 즉
10가닥(비트) --> 1 K 에 해당
20가닥(비트) --> 1 M 에 해당 (메가)
30가닥(비트) --> 1 G 에 해당 (기가)
한다고 했지요. 따라서 286은 1 M 까지의 메모리 주소를 가리킬 수 있는 능
력이 있습니다. 우리가 얼마전 까지만 해도 보통 1 M 의 메모리를 갖고 있었
던 이유가 바로 이것입니다.
1 M를 16진법으로 쓰면 0x00000 부터 0xfffff 까지로 표시되는데 이
것은 int 와 long 타입의 중간에 해당합니다. 즉
int 의 최고 크기 --> 0xffff ( 64 k )
1 메가 --> 0xfffff ( 1 M )
long 의 최고 크기 --> 0xffffffff ( 4 G)
따라서 1 M 를 가리키는 타입이 정확하게 없는 것입니다. 그래서 80286 에서
는 1 M 높이에 도달하기 위해 다음과 같은 사다리차 + 개인 사다리의 개념을
도입했습니다.
---------------------------------
사다리 차 : 개인 사다리
---------------------------------
1. CS : IP
2. SS : SP, BP
3. DS :
4. ES :
그런데 위에서 언급한 레지스터들은 전부 Int 타입의 크기를 갖고 있지요.즉
16 비트 짜리인데 이것 2개를 이용하여 20 비트의 주소를 만드는 과정은 정
말 지저분하게 [27쪽] 의 위쪽 그림과 같습니다.
이 숫자는 전부 16진법으로 쓴 것입니다. 즉 세그먼트는 0xffff 4개의
숫자를 갖는데 한 글자에 한 칸씩 그린 것입니다.
이런 연산은 CPU 내부에서 알아서 하지만, 사람이 완성된 주소를 알
아보려면 항상 종이에다 이 그림대로 계산을 해야 비로소 알 수 있지요. 직
접 정확한 값을 알려 주는 곳은 컴퓨터 내부에는 없습니다.
이게 이른바 사다리차 + 개인 사다리의 연산인데, 게다가 자리 단
위도 세그먼트는 4 비트만큼 "<--" 쪽으로 이동을 한 상태입니다. 주소 하
나 알아내기 위해서 조금 복잡하지요.
하지만, 우리가 IBM-PC를 쓰는 죄로 이런 번거로움은 스스로 감당해
야만 합니다.(맥킨토시에서는 이런 짓을 안함). 따라서 앞으로 우리는 주소
표기를 다음과 같이합니다.예를 들어 위의 그림을 이용하면,
세그먼트 : 0x1234
offset : 0x 1111
-------------------------
실제 주소 : 0x 13451
-----------<암기>----------
<표기법> 1234:1111
---------------------------
위에 보다시피 "표기법"과 "실제 주소" 사이에는 엄청난 차이가 있다는 걸
알아야 합니다. 이제 이런 모습을 디버거를 통해 직접 보기로 하지요.
***********************************************************************
<3> 디버거(debugger)를 이용하여 CPU를 건드려 보자
1> 디버거의 기능
2> CPU 의 레지스터를 조작하자.
3> 메모리를 조작하자.
***********************************************************************
1> 디버거의 기능
-----------------------------------------------------------------------
디버거(de + bugger)는 말 그대로 "벌레를 잡는 놈" 이라는 뜻입니
다. 즉, 프로그램을 작성하고 에러가 있으면 이 디버거를 통해서 잘못을 고
쳐 나가는 프로그램입니다.
여기서 말하는 잘못이란, 두말할 것도 없이 문법 상의 에러를 말하
는 게 아닙니다. 그런 건 컴파일러가 그냥 두지 않을 테니 거기서 해결을 하
고 , 디버거 상에서는 프로그램이 돌기는 도는데 결과가 정확히 안나온다든
가 하는 경우에 그 과정을 하나씩 추적해 가는 용도로 이용합니다. 그런 일
을 하려다 보니 디버거는 필수적으로 다음과 같은 일을 해야 합니다.
1. CPU 내부의 레지스터를 맘대로 조작할 수 있습니다.
2. 메모리 아무 곳에나 값을 쓰고 읽을 수 있습니다.
3. input, output 장치 아무 곳에나 값을 쓰고 읽을 수 있습니다.
3. 간단한 어셈블을 할 수 있습니다. ( 어셈블리어 --> 기계어로)
4. 디 어셈블을 할 수 있습니다. ( 기계어 --> 어셈블리어로)
이 기능은 한마디로 얘기해서 컴퓨터를 떡주무르듯이 만질 수 있다는 얘기지
요.이 중에서 우리는 현재 이 강좌의 내용에 도움이 되는 1,2 번 기능을 주
로 알아봅니다.
-----------------------------------------------------------------------
2> CPU 의 레지스터를 조작하자.
-----------------------------------------------------------------------
debugger는 보통 dos 밑에 있으므로 누구나 가지고 있을 것입니다.
위에서 설명한 레지스터들을 실제로 한번 조작해 봅니다
1) debug (enter)라고 치면, "-" 라는 프롬프트 가 나타난다
2) -? 를 치면 디버거의 모든 명령어를 보여 준다. 이 명령어는 갯수가 많지
않으므로, 한 30분만 써 보면 누구나 사용할 수가 있다.
3) -r 이란 명령어는 register의 첫글자로 현재 CPU 레지스터의 모든 것을
보여준다. 여기에 나와 있는 이름들과 [20쪽]의 그림
을 비교 확인해 보세요. 정확히 같다는 것을 알 것입니다.
4) - r ax 레지스터의 값을 변경하고 싶으면 아무 레지스터 이름이나 친다.
(현재는 ax를 변경)
5) AX 0000
:
그러면 위와 같이 현재 ax 값을 보여 주고,변경할 값을 쳐 넣으면 되는데,
변경 값은 다음과 같이 들어간다.
AH AL
; 12 --> AX 00 12 (ah, al동시에 변함)
; 1200 --> AX 12 00 ( // )
; 1234 --> AX 12 34 ( // )
6) - r 을 다시 쳐보면 바뀐 레지스터의 값을 볼 수 있을 것입니다.
7) - q 끝내고 나온다
디버거에서 레지스터를 조작하는 방법은 이와 같이 간단합니다.
<숙제> 다른 모든 레지스터를 이와 같이 바꿔 보고 확인해 보세요.
<숙제> 특히 세그먼트 레지스터인, CS,DS,SS,ES 의 값을 변경해 보세요.
-----------------------------------------------------------------------
3> 메모리를 조작하자.
-----------------------------------------------------------------------
디버거의 명령어 중에 메모리를 건드리는 명령어가 있습니다.
1) - d
이 명령어는 Dump의 첫글자로 "확 쏟아 붓는"다는 뜻입니다. 건설 현장에서
덤프 트럭이 흙을 쏟아 붓는 것과 똑같은 개념입니다. 128개씩 화면에 "확
확" 쏟아서 보여주지요. 여기서 주소가 1234 : 1234 형태로 나타나는 것을
보세요. 위에서 주소를 표기하는 법을 기억해야 합니다.
2) - d 300
특별히 보고 싶은 곳이 있으면 위와 같이 번지수를 명시해 주면 그곳을 보여
주는데, 여기서 주의 할 것은, 80xxx 계열의 CPU에서 주소를 찾으려면, 사다
리차 + 개인 사다리의 개념이 있어야 한다고 했습니다. 지금 적은 숫자는 개
인 사다리에 해당하는 offset 영역일 뿐이고, 사다리차에 해당하는 영역은
DS 레지스터의 값입니다. 그러므로 현재의 주소는 " DS : 300 "에 해당합니
다.
3) DS 값을 0 으로 바꾸고, -d 0 을 덤프해 봅니다 그러면 0000 : 0000 부
터 값들이 나타나는데, 이 숫자들이 그 유명한 인터럽트 벡터들입니다. 나
중에 중급 과정에서 자세하게 다루게 될 것입니다.
그리고 이 번지수가 메모리의 "실제 첫 번째 집"을 의미합니다. 여태까지 여
러분의 상상 속에만 있었던 메모리의 집입니다. 디버거를 이용하면 이렇게
손쉽게 메모리 값을 조작할 수가 있습니다. 물론 C 에서도 이런 짓이 가능합
니다. 앞으로는 이와 같이 컴퓨터의 내부를 구체적이고 실질적으로 느낄 수
있어야 합니다.
4) - e 100
이 명령어는 edit의 첫글자 입니다. 100번지의 내용을 바꾸고 싶으면 이와
같이 명령을 주고 "값을 쳐 넣는다". 여기서는 모든 숫자들이 "16진법"이라
는 걸 항상 기억 해야 합니다.
5) - d 100 을 다시 쳐보면 메모리에 바뀐 값이 보일 것입니다.
6) - f 100 200 11
f 는 fill 의 첫글자로 위의 e 처럼 한 글자 씩 바꾸는 것이 아니라 어떤 구
간(100번지부터 - 200번지까지)를 통째로 어떤 숫자를 채워 넣는 것입니다.
현재는"11" 을 채워 넣고 있습니다.
5) - d 100 을 다시 쳐보면 메모리에 바뀐 값이 보일 것입니다.
여기서 잠깐 시스템을 죽여 봅니다. 아직 얘기는 안했지만, 지금 우
리가 얘기하고 있는 메모리 의 특정한 부분에는 이미 DOS가 들어가서 열심히
일을 하고 있습니다. 위에 얘기한 0000 : 0000 부터 시작되는 인터럽트 벡터
도 dos의 한 부분입니다. 따라서 우리는 이런 부근에다 fill 명령어를 써서
아무 값이나 써 버리면, 당연히 시스템이 미치지요.
시스템을 죽일 줄 아는 사람만이 실제로 시스템을 안 죽이고 잘 쓰
는 법이므로 다음의 숙제를 성실히 해서 꼭 시스템을 죽이거나 미치게 해보
세요.
<숙제>
ds 를 0 으로 바꾼다. fill 명령어로 범위를 마음대로 잡고 아무 글자나 써
봅니다. 시스템이 안 죽으면 죽을 때까지 범위를 바꿔보세요. 여기서 당연히
범위는0 부터 0xffff 까지입니다(offset 이 2 바이트이므로). 성공을 빕니
다.
<숙제> 아래는 dos.h 안에 있는 데이터 구조입니다.지금 얘기하고 있는 레지
스터의 구조를 정의 한 것입니다.
struct WORDREGS {
unsigned int ax, bx, cx, dx, si, di, cflag, flags;
};
struct BYTEREGS {
unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};
union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};
struct SREGS {
unsigned int es;
unsigned int cs;
unsigned int ss;
unsigned int ds;
};
struct REGPACK {
unsigned r_ax, r_bx, r_cx, r_dx;
unsigned r_bp, r_si, r_di, r_ds, r_es, r_flags;
};
<문 1> 위에서 struct WORDREGS 의 메모리 구조를 그려 보세요
<문 2> 위에서 struct BYTEREGS 의 메모리 구조를 그려 보세요
<문 3> 위에서 union REGS의 메모리 구조를 그려 보세요
**************************< 끝마치며 >********************************
수고하셨습니다.
***********************************************************************