크리에이티브 커먼즈 라이센스

홈페이지HOME

PHP

JavaScript

HTML

CSS

드롭다운메뉴

제로보드4

도   움   말

백지 건강강좌/자가임상체험

물박사(자가면역질환...)^미러

전동명(천연물질사전)^미러

竹田 장승옥(블로그)^글목록

계산환산(계산기)^ 단위변환

관주성경 TTS 일반파일 TTS

바이블로 Bible_ro 다운로드

다운로드>폰에 복사
>파일선택...설치됩니다.

[도움말 보기] 바로가기

개선 요구, 충고는
아래 관리자 연락
전화/메일 부탁 드립니다.
최대한 빨리 처리하고
업데이트 올리겠습니다.

이 글은 1994. 8.월초(?)경부터 하이텔에 올렸던 자료이다.

하이텔에 들어가 보니 일부 없어진 것이 있는데, 다행히 내 컴퓨터에서 찾았다.

asm_04. (어셈블 입문)

프로그래밍 언어도 하나의 언어입니다.

언어란 하나의 약속입니다.

우리가 약속을 모를 때 우리는 전혀 무능한 사람입니다.

그러나 일단 약속을 알고 나면 우리는 유능한 사람이 됩니다.

우리는 외국 사람들과 대화하기 위하여, 그 외국 사람들 사이의 약속인 해당 외국어를 열심히 배웁니다.

프로그래밍 언어를 배우는 것은 확실히 그보다 쉽습니다.

제 04 장  어셈블(Assemble) 입문

우리가 기계어 코드를 일일이 입력하는 것은 매우 힘든 일이다.

예전에는 그렇게 해야 되었지만, 지금은 그럴 필요가 없다.

우리가 아스키 문자로 명령을 입력하면, 어셈블러라는 프로그램이 그 명령을 기계어 코드로 번역해 주기 때문에 우리는 신경쓸 일이 없다.

앞에서 디버그의 사칙연산 등을 하면서 기계어 코드를 외우지 말라고 했다.

우리는 명령을 아스키 문자로 입력하면 그만이기 때문이다.

이 장에서 우리는 어셈블 명령으로 프로그램을 만들 뿐 아니라, 그 프로그램을 디스크에 저장하여 디버그 없이도 실행되는 독립된 프로그램을 만들 것이다.

제 1 절  어셈블, 역어셈블

아스키 문자를 기계어 코드로 번역하는 작업을 어셈블이라고 한다.

그 반대로 기계어 코드를 아스키 문자로 표시해 주는 일은 역어셈블이다.

1.  U 명령

우리가 기계어 코드로 입력한 명령을 역어셈블하여 확인해 보자.

역어셈블(Unassemble) 명령은 u <번지> 로 한다.

    ## 필자통신

이 설명은 앞 장의 실습에서 이어지는 것이다.  앞 장에서 우리는 오프셋 0100번지로부터 int 21h, int 20h를 각 입력해 두었다.

디버그를 끝내었을 것이다.  이미 배운 방법으로 100번지부터 시작하여 그 두 명령을 입력한 후에 다음 실습을 진행하면 된다.

     - u 100

     0BDB:0100 CD21         INT     21

     0BDB:0102 CD20         INT     20

     ...................................

     -

만약, 직전에 q 명령으로 디버그를 끝내고 도스로 나갔다가 debug 명령으로 다시 디버그를 시작했다면 화면은 위와 달리 나타날 것이다.

그렇다면, 앞에서 설명한 e 100 명령을 먼저 수행하고 보아야 된다.

역어셈블 명령은 베이직의 List 명령과 비슷하다.

................................... 표시한 부분에 보이는 명령들은 다른 프로그램이 메모리에 남긴 것이다.

2.  A 명령

우리가 입력하는 아스키 문자를 어셈블러 프로그램이 알아서 기계어 코드로 번역하여 메모리에 받아 들이도록 만들려면 a <번지> 명령을 사용한다.

어셈블(assemble)의 머릿글자를 딴 명령이다.

만약 디버그를 다시 시작했다면, 위에서 e 100 명령을 재실행한 데 이어서 r ax , r dx 명령도 재실행하여 값을 맞추고 진행해야 될 것이다.

앞에서 우리는 ax 레지스터에 0200을 입력하고, 또 dx 레지스터에 0041을 입력해 두었으므로 그와 같이 다시 입력해 두면 될 것이다.

입력 방법이 기억나지 않으면, 앞 장을 다시 복습하기 바란다.

명령을 입력할 필요가 없는 메모리 번지에서는 그냥 하면 된다.

준비가 끝났으면, 다음 그림과 같이 어셈블을 해 보자.

     - a 100

     0BDB:0100 int 21

     0BDB:0102 int 21

     0BDB:0104 int 20

     0BDB:0106

     ...................................

     - g

     AA

     Program terminated normally

     -

우리는 ah 레지스터에 출력 명령을, dl 레지스터에 영문자 A를 저장해 두었다.

그런데, 이번에는 int 21h 함수를 2 번 호출했기 때문에 같은 문자 A를 2 번 연달아 출력한 것이다.  그리고는 int 20h 함수를 만나 프로그램이 끝났다.

조금씩 자신감이 생길 것이다.

제 2 절  레지스터 편집 명령

우리는 아까 레지스터의 값을 변경하기 위해 r <레지스터> 명령을 했다.

그러나, 그 방법을 디버그를 실행하기 전에는 사용할 수 없는 명령이다.

프로그램은 그것이 완성된 후에는 다른 프로그램의 힘을 의지하지 않고 독립적으로 실행될 필요가 있다.

그러기 위해서는 우리가 만드는 프로그램 내에서 8088의 레지스터 값을 변경시킬 수 있는 어떤 명령을 사용할 필요가 있다.

1.  MOV 명령

레지스터에 데이터를 저장하는 명령은 "mov <사본>,<원본>"로 한다.

원본 위치에 들어 있는 데이터를 복사하여 사본 위치에 저장하라는 뜻이다.

원본과 사본의 크기는 동일한 것이면 워드와 워드, 또는 바이트와 바이트 중 어느 것이라도 될 수 있으며, 원본은 그 데이터가 들어 있는 레지스터 이름이 될 수도 있지만 직접 데이터 자신이 될 수도 있다.

말로 하면 어렵게 들리지만, 실습해 보면 간단하다.

레지스터의 값을 초기화하기 위해 디버그를 다시 시작하자.

     - q

     ...>debug

     - a 100

     ????:0100 mov dl,99

     ????:0102 mov ah,dl

     ????:0104

     -

첫줄은 99h라는 데이터를 dl 레지스터에 저장하라는 명령이다.

둘째 줄은 dl 레지스트의 값 99를 ah 레지스터에 복사해서 저장하라는 명령이다.

그 두 명령이 실행되면 결국 dl, ah 두 레지스터에는 99라는 데이터가 저장된다.

그 과정을 눈으로 확인하기 위해 t(trace) 명령으로 한 명령씩 실행해 보자.

영어로 trace는 흔적, 발자취라는 뜻이므로 프로그램의 오류를 검사하기 위해서 역어셈블만으로 실수를 발견하기 어려울 때 이용되는 명령이다.

    - t

     AX=0000 BX=0000 CX=0000 DX=0099 .................

     .............................. IP=0102 .................

     ????:0102 88D4         MOV     AH,DL

     - t

     AX=9900 BX=0000 CX=0000 DX=0099 .................

     .............................. IP=0104 .................

     ????:0104 .....     ......     ......

     -

한 명령을 실행했을 때 dx 레지스터값이 0099로 변했으므로, 우리가 dL 레지스터에 99를 저장하라고 한 명령이 정상적으로 수행되었음을 알 수 있다.

다음에는 ax 레지스터값이 9900으로 변했는데, 이것은 dL 레지스터의 값 99를 복사하여 ah 레지스터에 저장해 준 결과이다.

프로그램이 우리가 지시한 대로 정확하게 실행되었음을 알 수 있다.

2.  문자 지정 출력 프로그램

앞 장에서 우리는 디버그상에서 레지스터 값을 직접 변경하여 A라는 영문 글자를 출력해 보았다.  이제는 우리가 만든 프로그램 안에서 레지스터 값을 변경하여 동일한 결과를 얻도록 프로그램을 만들어 보기로 하자.

그렇게 해 두어야 이미 말한 것처럼 ah, dL 레지스터의 값이 어떤 이유로 바뀌어 있었더라도 우리의 프로그램이 우리가 원하는 결과를 만들어 준다.

     - a 100

     ????:0100 mov  ah,02

     ????:0102 mov  dl,41

     ????:0104 int  21

     ????:0106 int  20

     ????:0108

     -

이제 위 프로그램을 실행해 보기로 하자.

     - g

     A

     Program terminated normally

     - r ip

     ip 0100

     :

이미 아는 바와 같이 실제 입력시에는 16진수를 표시하는 h를 붙이면 안 된다.

실제로 두드려 보면 위와 같이 나올 것이다.

이해가 되지 않으면, 이전의 원고를 다시 읽어 보기 바란다.

마지막에 r ip 명령을 해 본 결과, 프로그램이 int 20h 함수를 만나면 끝나면서 ip 레지스터 값이 0100으로 다시 초기화된다는 사실을 알 수 있다.

이것은 우리와 같은 초보 프로그래머를 편안하게 만들어 주는 것이다.

기억해 둘 가치가 충분하다고 생각한다.

    ## 활용 팁

단지 r 명령을 하면 전체 레지스터의 상황을 보여 준다.  그러나 r 명령에 특정 레지스터 이름을 붙여 명령하면 그 레지스터에 저장되어 있는 기존의 값을 보여 주며 우리는 그 값을 수정할 수도 있다.

제 3 절  프로그램 저장

우리가 만든 프로그램을 나중에 사용하기 위해서는 지스크에 저장해야 된다.

지금 프로그램은 메모리에만 있으므로, 전원을 끄면 즉시 사라져 버린다.

디스크에 저장해 둔 프로그램을 나중에 실행하려면 이름이 있어야 될 것이다.

그러므로, 저장하기 전에 먼저 이름부터 지어 주기로 하자.

1.  프로그램 작명

이론적으로만 생각하면, 프로그램에 이름이 없어도 저장할 수는 있을 것이다.

그러나 디버그는 이름이 없는 프로그램은 저장해 주지 않는다.

프로그램의 이름을 지어 주려면 n <파일명> 명령으로 통한다.

     - n out_A.com

     -

명령이나 파일명 등은 대소문자를 가리지 않고 입력해도 무관하다.

2.  프로그램 크기 입력

이름만 지어 주었다고 곧바로 저장해서는 안 된다.

저장할 때 메모리의 100h 번지로부터 시작하여 몇 바이트 크기까지를 프로그램으로 저장할 것인지를 계산하여 디버그에게 알려 주어야 된다.

디버그는 bx:cx 레지스터의 값을 보아서 프로그램의 크기를 인식한다.

따라서 우리는 우리가 만든 이름으로 저장할 프로그램의 크기를 그 두 레지스터 안에 입력해 주고 나서야 프로그램을 정상적으로 저장할 수 있는 셈이다.

    ## 활용 팁

프로그램의 크기를 지정하는 용도로 2 개의 레지스터를 배정해 둔 이유는 크기가 65536(ffffh) 이상 되는 프로그램까지 저장할 수 있도록 하기 위함이라는 사실은 쉽게 이해할 수 있을 것이다.

먼저, 우리가 저장할 프로그램의 크기를 계산해 보자.

앞에서 우리는 100h로부터 프로그램의 명령을 입력하기 시작하여, 108h에 가서는 추가 입력을 하지 않고 끝내었다.  따라서 108h - 100h = 8h가 된다.

프로그램의 크기가 작으므로, 프로그램의 크기를 입력하기 위하여 bx 레지스터는 사용할 필요도 없게 되었다.

따라서 cx 레지스터의 값을 8h로 변경해 주면 될 것이다.

     - r cx

     cx 0000

     : 8

     -

    ## 주의

만약 bx 레지스터에 0000이 아닌 다른 값이 저장되어 있다면, r bx 와 0 를 차례로 입력하여 그 값을 0000으로 만들어 주어야 된다.

3.  프로그램 저장

프로그램을 디스크에 저장하려면 쓰기(write)를 뜻하는 w 명령으로 한다.

이미 이름도 지정하였고, 크기도 알려 주었다.

따라서 Write 명령 뒤에 아무 옵션이나 파라미터도 붙일 필요가 없다.

     - w

     Writing 00008 bytes

     -

디버그는 요즘 인기가 있는 구이(gui) 프로그램과는 거리가 멀다.

그렇게 친절한 프로그램이 결코 아니라는 말이다.

저장하라고 했더니 쓰다 달다 아무 표정도 없다.

아쉬운 것은 우리가 아니겠는가?

정말로 저장이 되었는지, 도스로 빠져 나가서 확인해 보자.

     - q

     ...>dir out_a.com


     OUT_A    COM    8  3-28-94  2:22a

            1 file(s)               8 bytes

                    34125678 bytes free

     ...>

무뚝뚝한 디버그이지만 자기 할 일은 정확하게 해 두었다.

이제 우리가 만든 프로그램을 도스상에서 실행해 보자.

...>out_a

A

...>

디버그상에서 실행할 때와 달리 "Program termin..." 메시지는 나오지 않는다.

제 4 절  문자열 출력

우리는 하나의 문자 A의 아스키 코드값을 직접 dl 레지스터에 저장해 두었다가 int 21h 함수 번호 ah=02h로 그 문자를 출력하는 프로그램을 만들어 보았다.

만약 둘 이상의 문자로 구성된 문장 즉 문자열을 출력하려면 어떻게 할까?

1.  똑똑한 초보자의 제안

그 방법은 별 것 아니다.

메모리 100h로부터 시작하여 dl 레지스터에 어떤 아스키 코드값을 입력하는 명령, int 21h 명령, 코드값 입력 명령, int 21h 명령, ... 순서로 적어 주면 된다.

그리고 필요한 문자의 출력이 끝난 후에는 int 20h 명령을 사용하는 것이다.

물론 이렇게 해도 프로그램은 만들어지고, 정상적으로 실행될 것이다.

그러나 이것은 얼마나 피곤한 작업일 될 것인가?

2.  INT 21h 함수 번호 09h

int 21h의 함수 번호 02h는 하나의 문자를 화면에 출력해 주었다.

그와 달리 int 21h의 함수 번호 09h는 이어지는 문자열을 계속해서 화면에 출력해 주다가, 달러 기호($)를 만나면 출력을 멈춘다.  $는 출력하지 않는다.

그 기능을 이용하여 프로그램을 만들면 간단해진다.

1) 출력할 내용 저장

먼저 출력할 내용이 되는 문자열을 메모리의 200h 번지로부터 저장해 두자.

     - e 200

     ????:0200 ??.48    ??.65           ??. 24

     -

위와 같은 방법으로 아래 문자열을 차례로 입력하자.

     H  e  l   l  o  ,  A  s  s  e  m  b  l  e  !  $

     48 65 6c 6c 6f 2c  41 73 73 65 6d 62 6c 65 21 24

아스키 코드표를 찾아 보면 위의 값을 얻을 수 있을 것이다.

실제 입력은 다음과 같이 해 주면 된다.

    48 65 6c 6c 6f 2c 41 73 73 65 6d 62 6c 65 21 24

입력을 마쳤으면, u 200 명령으로 확인해 보는 것은 좋은 일이다.

2) 프로그램 입력

방금 우리가 입력한 내용은 출력할 문자열 즉 문자 데이터베이스이다.

따라서 u 200 명령으로 보이는 화면에는 db란 문자가 계속 나올 것이다.

이제 그 문자열을 출력해 주는 int 21h 함수 번호 09h를 프로그램으로 만들자.

- a 100

     ????:0100 mov  ah,09

     ????:0102 mov  dx,0200

     ????:0105 int  21

     ????:0107 int  20

     ????:0109

     -

위의 입력 과정에 특히 주의할 점은 ah를 ax로 해도 무방하지만, dx를 dl로 해서는 안 된다는 사실이다.

3.  문자열 출력 프로그램

이제 문자열 출력 프로그램을 저장해 보자.

저장하기 전에 g 명령으로 실행해 보는 것도 좋다.

혹시 디버그상에서 다른 조작을 했다면 실행하기 전에 r ip 명령으로 오프셋 번지를 0100으로 맞추어 두어야 될 것이다.

혹시 t 명령 등을 실행하여 세그먼트 번지까지 변경되었다면, r cs 명령으로 세그먼트 번지도 원래 번지로 바꾸어 맞추어야 된다.

세그먼트나 으프셋 번지를 수정한 후에는 반드시 r 명령으로 확인하자.

    ## 필자통신

디버그를 처음 시작했을 때는 세그먼트 레지스터가 어떤 번지이든 무관하지만, 디버그 안에서 프로그램을 만든 후 세그면트 레지스터를 변경하여 실행하면 당연히 그 프로그램이 실행되지 않을 것이다.

모든 것이 정상이라면, 파일명을 짓고, 파일 크기를 bx:cx 레지스터에 입력한 후에 저장하면 된다.

프로그램의 시작은 0100h에서 했는데 문자열 데이터를 저장하는 구역이 0211h 직전에 끝났기 때문에, 파일 크기는 0212h - 0100h = 111h가 될 것이다.

     - n s.com

     - r cx

     CX 0000

     : 111

     - w

     Writing 111 bytes

     - q

     ...>

도스상에서 dir.com 명령을 하면 s.com 111 bytes가 보일 것이다.

도스상에서 프로그램을 실행해 보자.

     ...> s

     Hello,Assemble!

     ...>

만약 디버그를 끝내기 전에 디버그상에서 실행했다면 어떻게 되었을까?

     - g

     Hello,Assemble!

     Program terminated normally

     -

제 5 절  프로그램 수정, 응용

어떻게 프로그램을 만들기는 만들었는데, Hello,와 Assemble! 사이에 빈칸 하나를 넣어 주었으면 보기가 더 나았을 것이데 하는 아쉬움이 생긴다.

프로그램을 불러서 수정해 보기로 하자.

1.  디버그 실행과 동시에 프로그램 호출

디스크에 이미 저장되어 있는 어떤 프로그램을 호출하여 편집하는 방법이 있다.

도스상에서 debug <파일명> 명령을 사용하면 된다.

     ...> debug s.com

     -

그러면 s.com 파일이 메모리로 읽혀져 편집 가능한 상태가 된다.

u 명령으로 입력되어 있는 명령어를 확인해 보자.

디버그를 처음 실행한 후에 u <번지> 명령에서 파라미터 <번지>를 생략하면 0100h로부터 역어셈블해서 보여 주게 된다.

     - u

     ????:0100 B409         mov     ah,09

     ????:0102 BA0002       mov     dx,0200

     ????:0105 CD21         int     21

     ????:0107 CD20         int     20

     ...................................

     -

2. 출력할 문자열 수정

수정할 내용은 출력할 문자열 중간에 공백문자 하나를 삽입하는 것이다.

     H  e  l   l  o  , A  s  s  e  m  b  l  e  !  $

     48 65 6c 6c 6f 2c 41 73 73 65 6d 62 6c 65 21 24

쉼표(코드 2c) 다음에 빈칸(코드 20) 하나를 넣어 주면 된다.

     - e 200

     ????:0200 48.   2c.    41.20       73.41

     ????:02??        24.21 ??.24

     -

즉, 쉼표 코드 2c까지는 나오는 대로 스페이스바를 눌러 지나간다.

그 다음 A 코드 41이 나오면 그 자리에 빈칸 코드 20을 입력한다.

그 다음부터는 차례로 바로 앞의 코드값을 베껴 입력해 주면 될 것이다.

이것으로 출력할 문자열의 수정은 모두 끝났다.

3.  파일 크기 다시 지정

명령은 그대로 두고 출력할 문자열도 수정했으니 이제 끝난 셈이다.

그러나, 그대로 저장하면 안 된다.

출력할 문자열의 전체 크기가 늘어났으므로, 파일 크기도 변했기 때문이다.

파일 크기를 저장하는 bx:cx 레지스터의 값을 수정해 주어야 된다.

역시 파일 크기가 16진수 4 자리를 넘지 않으므로, cx 값만 수정하면 된다.

원래의 파일 크기는 111 바이트였다.

그런데, 빈칸 문자 20h가 삽입되어 1 바이트 크기가 늘었다.

따라서 수정하여 저장할 파일의 크기는 112 바이트가 될 것이다.

     - r cx

     cx 0111

     : 112

     -

    ## 필자통신

이 프로그램의 경우에는 파일 크기를 수정해 주지 않아도 별 이상이 생기지 않는다. 아마도 그 이유는 원래 프로그램 크기를 계산할 때 마지막 달러 기호($) 코드까지 포함하여 계산했기 때문에, 수정 후 그 부분이 잘려 나가도 프로그램의 정상적인 실행에는 아무 지장이 생기지 않은 것이리라. 그러나 언제나 그렇지는 않다. 항상 기본적인 절차를 빠뜨리지 않고 작업하는 것은 매우 중요한 일이다.

4.  파일 재저장

파일 이름은 변경할 필요가 없다.

그러므로 이제 곧장 저장하면 될 것이다.

저장하고 도스로 빠져 나가자.

     - w

     Writing 112 bytes

     - q

     ...>

그리고 수정한 프로그램을 실행해 보자.

     ...> s

     Hello, Assemble!

     ...>

5.  응용

아스키 코드값을 일일이 외우려고 할 필요는 없다.

그러나 복습으로 자신이 원하는 문자열을 출력하는 프로그램을 만들어 보자.

두 줄 이상에 걸친 문자열을 표시할 수도 있을 것이다.

그래픽 분위기를 내기 위해 선문자 코드값을 사용해 보는 것도 좋다.

다양하게 프로그램을 만들다 보면, 코드값은 저절로 외워져 있을 것이다.

다시 다 잊어 버려도 무방하다.

필요할 때 코드표를 보면서 작업하면 그만이기 때문이다.

필자는 되도록 알기 쉽게 실습 화면을 일일이 제시하고 있다.

그러나 다양한 실습은 이 글을 보는 사람의 몫이다.

    == 응용 문제 ==

int 21h 함수에서 코드값 0Ah는 커서를 아랫줄로 내려 놓는 줄바꿈 문자이다.

또 같은 함수에서 코드값 0Dh는 커서를 현재 줄 첫칸으로 옮겨 준다.

위의 두 문자를 이용하여 다음과 같은 화면 출력을 하는 프로그램을 짜라.

(문제 1)

Hello, Assemble!

                 Hello, Assemble!

(문제 2)

Hello, Assemble!

Hello, Assemble!

## 힌트 ##

동일한 문자열을 출력하기 위해서는 출력할 문자열 데이터베이스를 손댈 필요는 없으며, int 21h 명령을 두 번 써 주면 그만이다. 프로그램을 수정한 후에는 저장하기 전에 프로그램 파일 크기도 수정하여 입력해 주어야 실수가 없음에 주의하라.

ID:
PW:

     0 분
     1 분

자유게시판

건강백과 HOME

홈페이지 HOME

조   약     HOME

생활지혜 HOME

서식양식 HOME

법원 전산양식 검색

In Na zum

비공개 HOME

백과넷 포탈 : 건강/법률(메인)/홈피/서식/조약/생활지혜

◁ 2002.9.1.~2018.8.16. ▷

관리자 연락(저작권 의심 신고) : 김병희 010-6204-4973 k8z7@hanmail.net