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

홈페이지HOME

PHP

JavaScript

HTML

CSS

드롭다운메뉴

제로보드4

도   움   말

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

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

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

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

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

관주성경 TTS 일반파일 TTS

바이블로 Bible_ro 다운로드

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

[도움말 보기] 바로가기

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


asm_72.

제 3 절  데이타를 두는 방법과 전송방법


     11 이형문 buju8t 12/17 1481

    10 데이타를 두는 방법과 전송방법입니다.







이 장에서는 프로그램 중에 데이터를 두어서, 그 데이터를 레지스터에 전송하는

방법을 알아 보자. 이 장에서는 2개의 프로그램을 만들어 실습할 것인데 먼저는 하나의

세그먼트로 CS와 DS를 정의하고, 나중에는 그 둘을 각 이름이 다른 별도의 세그먼트에

정의하는 프로그램을 만들게 될 것이다.


     ## 필자통신

    asm_70. 이후의 원고는 당장 무언가 만들어 흥미를 돋구는 방식으로 설명이

    진행되지는 않으며, 다소 따분하더라도 어셈블리에 대하여 기초적인 이해를 확실하게

    다져 나가는 것임을 알고 느긋하게 노력하자.

    그리고 이 장의 프로그램을 디버그로 어떻게 만들 수 있는지는 각자 생각하여

    실습해 보기 바란다. 어셈블러 프로그램이 없는 독자라면 당연히 디버그 프로그램으로

    변환하여 실습해 보아야 될 것이며, 그런 노력조차 하지 않고 단지 읽기만 하면

    별 얻는 것이 없을지 모른다. 해 보다가 막히면 바로 메일을 주기 바란다. 한편

    어셈블리 프로그램이 있더라도 디버그 프로그램으로 실습해 보는 것은 다소 도움이

    될 것이다.







1. 프로그램 소스

다음에 소개하는 프로그램은 X4V라는 문자를 메모리에 저장해 두고 그 내용을

그대로 화면에 출력하는 프로그램이다.

줄 수가 좀 많아서 복잡하게 보이지만, 이미 알고 있는 내용을 제외하고 새롭게

공부해야 될 부분을 추려 보면 복잡할 것이 하나도 없다.

분석은 조금 있다가 하기로 하고, 우선 전체적인 내용을 살펴 보자.


     MAIN SEGMENT

    ASSUME CS:MAIN,DS:MAIN

    ;

    MOV AX,CS

    MOV DS,AX

    MOV DL,XXX

    MOV AH,2

    INT 21H

    MOV CX,YYY

    MOV DL,CH

    MOV AH,2

    INT 21H

    MOV DL,CL

    MOV AH,2

    INT 21H

    ;

    MOV AH,4CH

    INT 21H

    ;

    XXX DB 'X'

    YYY DW 3456H

    ;

    MAIN  ENDS

    END







2. SEGMENT를 정의하는 ASSUME 의사명령

먼저 첫 부분에 나오는 assume 의사명령의 오먕이 조금 달라졌다.


     MAIN SEGMENT

    ASSUME CS:MAIN,DS:MAIN


첫 줄에서 MAIN이라는 이름의 세그먼트가 시작됨을 선언하고, 둘째 줄에서는 코드

세그먼트(CS)와 데이터 세그먼트(DS)가 MAIN이라는 이름의 세그먼트에 연결되어 있다는

사실을 선언하였다.

8086의 명령에서는 특별한 사항이 없는 한, 데이터는 데이터 세그먼트 내에 있는

것으로 해석되므로 데이터 세그먼트가 어디에 있는가를 지정해야 된다.

위와 같이 데이터가 MAIN 이라는 SEGMENT 에 있는 경우에는 DS:MAIN이라는 지시를

해 준다. 데이터가 다른 세그먼트에 있는 경우에는 역시 그 다른 세그먼트의 이름을

지정해야 되는데 그 문제에 대해서는 다음에 설명한다.






3. 세그먼트 번지를 일치시킴

우리는 assume 의사명령을 이용하여 main이라는 하나의 세그먼트를 코드 세그먼트로도

사용하고 데이터 세그먼트로도 사용하겠다고 선언(정의)하였다.

그러나 그 정의는 단지 어셈블러에 대하여 우리의 뜻을 알리는 지시일 뿐, 실제로

코드 세그먼트의 값과 데이터 세그먼트의 값이 일치한다는 보장은 되지 못하므로,

그 두 세그먼트의 메모리 번지를 일치시켜 주어야 된다.


     ## 주의

    데이타가 있는 프로그램에서는 반드시 DS 레지스터를 설정해 주어야 된다.

    즉, 데이터를 사용하는 프로그램에서는 반드시 데이터 세그먼트의 이름을 ASSUME

    문장으로 선언함과 동시에 MOV 명령을 사용하여 DS 레지스터의 값을 설정해 주어야

    된다.


따라서 코드 세그먼트 번지를 표시하는 CS 레지스터의 값을 데이터 세그먼트 번지를

가리키는 DS 레이스터에 복사(전송)해 주면 될 것이다.

OP코드 mov를 사용하면 제 2 오펴랜드의 값을 제 1 오퍼랜드로 전송할 수 있다.


    OP코드제 1 오퍼랜드,제 2 오퍼랜드


따라서 다음과 같은 명령을 사용하면 되지 않느냐는 생각이 들 것이다.


    mov ds, cs


그러나 이 명령은 잘못 된 것으로 에러가 생긴다.

왜냐하면, 범용 레지스터 사이에서는 직접 데이터의 전송이 가능하고, 또 범용

레지스터와 세그먼트 레지스터 사이에서도 데이터를 전송할 수 있지만, 두 개의 세그먼트

레지스터 사이에서 직접 데이터를 주고 받을 수는 없기 때문이다.

따라서 이 프로그램에서는 다음과 같은 방법으로 범용 레지스터를 통하여 코드

세그먼트 레지스터의 값을 데이터 세그먼트 레지스터로 복사하였다.


    MOV AX,CS

    MOV DS,AX


그 외에도, 세그먼트 레지스터에 직접 수치나 변수를 대입할 수 없다.

따라서 다음과 같은 명령도 잘못된 것이다.


    MOV DS,12334H







4. 변수 값을 전송하여 출력

이 프로그램이 앞 장에서 보았던 프로그램과 다른 중요한 점은 변수를 정의하고

그 값을 레지스터로 전송하는 문장이라고 할 수 있다.

알고 보면 간단하지만 줄 수가 많으므로 편의상 번호를 붙여서 설명한다.


     1. MOV DL,XXX

     2. MOV AH,2

     3. INT 21H

     4. MOV CX,YYY

     5. MOV DL,CH

     6. MOV AH,2

     7. INT 21H

     8. MOV DL,CL

     9. MOV AH,2

    10. INT 21H

    11. ;

    12. MOV AH,4CH

    13. INT 21H

    14. ;

    15. XXX DB 'X'

    16. YYY DW 3456H


첫째 줄과 넷째 줄의 내용이 좀 새로울 것이다.


    MOV DL, XXX

    MOV CX, YYY

    레지스터변수


이 명령 형식에는 제 2 오퍼랜드에 변수 이름이 왔는데, 그 변수에 대한 정의는

끝의 15, 16줄에 각 나타나 있는 것을 발견하였을 것이다.






즉 각 변수에 저장된 값을 DL, CX 각 레지스터로 전송하는 명령이 된다.

변수의 정의는 조금 있다가 따로 자세히 알아 보기로 하자.

변수를 정의한 그 두 줄을 제외하고 그 앞까지만 보면 줄 수는 많아도 이미 알고

있는 문자 출력 명령이 3번 반복되어 실행되는 단순한 구조이다.

먼저 1줄에서 XXX 변수의 값을 DL 레지스터에 전송하여 3줄에서 출력하고, 이어

4줄에서 YYY 변수의 값을 일단 CX 레지스터에 저장한 후 그것을 상위 및 하위 바이트(CH와

CL)로 나누어 5줄에서는 상위 바이트를 전송하여 7줄에서 출력하였으며, 끝으로 8줄에서는

하위 바이트를 전송하여 10줄에서 출력하였다.

이 정도의 구조 분석으로 일단 만족하고, 실제 출력은 항을 바꾸어 살펴 보자.






5. 변수의 정의

지금까지 설명한 3개의 문자 출력 명령들과 끝 부분의 변수 정의 명령 중간에는

다음과 같은 내용이 삽입되어 있다.


    MOV AH,4CH

    INT 21H


그 내용은 프로그램을 끝내고 도스로 복귀하는 명령임을 알고 있을 것이다.

이제 변수를 정의한 두 즐의 명령에 대하여 살펴 보기로 하자.


    XXX  DB

    'X'

    YYY  DW

     3456H

    변수 이름  변수의 형 데이터의

    초기치


변수를 정의할 때는 이와 같이 변수의 이름, 변수의 형(크기), 변수에 대입하여

저장할 데이터의 초기치를 입력해 주면 된다. 변수의 크기를 표시하는 형을 지정하는

명령(DEFINE 디텍티브)에는 다음과 같이 다섯 종류가 있다.


    DB ---- 바이트 정의

    DW ---- 워드(2바이트) 정의

    DD ---- 더블 워드(4바이트) 정의

    DQ ---- 쿼드 워드(8바이트) 정의

    DT ---- 10바이트 정의


각 디렉티브 이름의 첫 글자는 DATA의 D를 공통으로 사용하며, 그 뒤에는 바이트

워드 더블 쿼드 및 텐(Ten)의 첫 글자를 따서 이름을 지은 것으로 보인다.

변수에 대입하여 저장할 데이터의 초기치로는 상수(수치) 또는 인용부호로 둘러

싸인 문자(열)등을 입력해 주면 된다. 이와 같이 정의해 둔 변수의 이름은 어셈블리

중에서 수치와 똑같이 사용할 수 있다. 예를 들면 이 프로그램에서와 마찬가지로

범용 레지스터에 전송할 값으로 변수의 이름을 사용할 수 있는 것이다.


     ## 주의

    당연한 일이지만, 변수의 이름으로 그 변수에 저장된 값을 범용 레지스터에

    전송하려면 변수의 형에 따른 값의 크기와 전송받을 레지스터의 크기가 워드는

    워드끼리 바이트는 바이트끼리 일치되어야 한다.







이제 이 프로그램이 어떻게 X4V라는 문자열을 출력하는지 정리해 보자.


     1. MOV DL,XXX

     2. MOV AH,2

     3. INT 21H

    15. XXX DB 'X'


첫 출력은 바이트 데이터(DB) 'X'가 15줄에서 변수 XXX에 저장되었다가 1줄에서

DL 레지스터로 복사(전송)되어 2줄을 참조한 3줄 인터럽트로 화면에 찍힌다.


     4. MOV CX,YYY

    16. YYY DW 3456H


다음으로 16줄에서 워드 데이터(DW) 3456h가 변수 YYY에 저장되었다가 4줄에서

중간 역과 같은 CX 레지스터로 일단 복사 전송된다.


     5. MOV DL,CH

     6. MOV AH,2

     7. INT 21H


그리하여, 먼저 CX 레지스터의 상위 바이트(CH) 레지스터 값 34h가 5줄에서 DL

레지스터로 전송되어 6줄을 참조한 7줄 인터럽트로 화면에 출력된다.

당연히 34h에 대응하는 아스키 문자 4가 화면에 찍힐 것이다.

여기까지 진행되면 모니터에는 X4라는 문자열이 나타난다.


     8. MOV DL,CL

     9. MOV AH,2

    10. INT 21H


마지막으로 CX 레지스터의 하위 바이트(CL) 레지스터 값 56h가 8줄에서 DL 레지스터로

전송되어 9줄을 참조한 10줄 인터럽트로 화면에 출력된다.

당연히 56h에 대응하는 아스키 문자 V가 화면에 찍힐 것이다.

여기까지 진행되면 모니터에는 X4V라는 문자열이 완전히 다 출력된다.







     ## 발전 참고

    이들 명령(MOV DL,XXX 및 MOV CX,YYY)의 어셈블 리스트를 보면 8A 16 0020

    R과 같이 끝에 R이 붙어 있는데 이것은 "상대 번지" 지정방식임을

    나타낸다. 문자를 출력한 다음에 복귀 개행해야 되지만 여기에서는 도스(OS)가

    자동적으로 처리해 주기 때문에 생략했다.


여기에서 디버그에만 익숙안 우리는 한 가지 의문을 가질 수 있을 것이다.

문자 출력 명령은 소스 파일의 앞에 있고, 변수 정의는 소스 파일의 뒤에 나오는데

어떻게 면수 정의가 먼저 처리되고 그 값이 레지스터로 전송될 수 있는가 하는 궁금증이

바로 그것이다. 그러나 명령줄 순서와 무관하게 정상으로 프로그램이 만들어지는

것은 전적으로 어셈블리가 알아서 해 주기 때문이다.

그 문제는 우리가 어셈블리를 정식으로 공부할 때 다시 알아 보기로 하자.


    MAIN  ENDS

    END


소스 파일의 마지막 두 즐에서, 첫 줄은 MAIN 세그먼트의 끝을 표시하고 둘째

줄은 프로그램의 끝을 표시한다는 사싱을 우리는 이미 앞에서 알았다.

또한 END 명령줄 이후에는 어떤 내용이 있어도 무시된다는 사실도 기억한다.






6. 데이터를 별도 세그먼트에 저장

우리는 앞에서 CS 데이터와 DS 데이터를 하나의 세그먼트에 저장하였다.

그와 달리 각 데이타를 여러 개의  SEGMENT에 두는 방법도 있다.

코드 세그먼트와 데이터 세그먼트를 별도로 설정하는 프로그램을 만들어 보자.


     1. MAIN  SEGMENT

     2. ASSUME CS:MAIN

     DS:DATA

     3. ;

     4. MOV AX,DATA

     5. MOV DS,AX

     6. MOV BX,TTT

     7. MOV DL,BH

     8. MOV AH,2

     9. INT 21H

    10. MOV DL,BL

    11. MOV AH,2

    12. INT 21H

    13. ;

    14. MOV AH,4CH

    15. INT 21H

    16. MAIN  ENDS

    17. ;

    18. DATA  SEGMENT

    19. TTT DW  'AB'

    20. DATA  ENDS

    21. END







이 프로그램의 구조는 다음과 같이 되어 있다.


     1. MAIN  SEGMENT

     2. ASSUME CS:MAIN

     DS:DATA

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

    16. MAIN  ENDS

    18. DATA  SEGMENT

    19. ..................

    20. DATA  ENDS

    21. END


즉 먼저 MAIN이라는 이름의 코드 세그먼트의 시작(segment)과 끝(ends)이 나오고,

그 다음에 DATA라는 이름의 데이터 세그먼트의 시작(segment)과 끝(ends)이 이어지며,

마지막으로 프로그램의 끝을 알리는 END가 있다.

이 프로그램에는 두 개의 세그먼트가 존재하고 있다. 그래서 다음과 같이 코드

세그먼트가 MAIN이라는 이름의 세그먼트에, 데이터 세그먼트가 DATA라는 이름의 세그먼트에

있다고 간주하고 명령을 작성하라고 지정하였다.


    ASSUME  CS:MAIN ,DS:DATA


여기에서 한 가지 지금까지 무심코 써 왔지만 특별히 언급하지 않았던 원칙 한

가지를 정리하고 넘어가는 것이 좋겠다.

이 프로그램과 같이 코드 세그먼트와 데이트 세그먼트를 따로 정의하는 경우에도

assume 문장은 코드 세그먼트 정의의 첫 부분에 나타났다.

그 사실은 프로그램의 주된 흐름이 코드 세그먼트에 입력된 명령의 순서에 따라서

진행된다고 하는 점을 암시해 주고 있다.

따라서, 각 세그먼트의 이름을 사용자가 임의로 지정할 수 있음에도 불구하고

대부분의 프로그램에서 코드 세그먼트의 이름을 MAIN이라고 짓는 것이다.

다음과 같이 기억해 두기로 하자.







    프로그램의 주 세그먼트는 코드 세그먼트이다. 그리고, 프로그램 내에서 사용하게

    되는 각 세그먼트의 이름은 코드 세그먼트의 첫 부분에서 assume 문장으로 선언해

    준다.


이 프로그램의 MAIN SEGMENT에서 assume 문장 바로 뒤에 나오는 두 줄의 내용을

옮겨 두고 살펴 보기로 하자.


     4. MOV AX,DATA

     5. MOV DS,AX


이 두 명령은 데이터 세그먼트 레지스터의 값을 초기 설정하는 부분이다.

이 모양은 이전의 프로그램에서 본 것과 동일하며 다만 4줄에서 전송하는 초기

데이터가 CS 대신 DATA가 된 것만이 다르다. 이전의 프로그램에서는 DS와 CS가 동일한

세그먼트에 있었으므로 CS 값을 DS에 전송하면 되었다. 그러나 이번에는 DS와 CS가

서로 다른 세그먼트에 있으므로 DS 레지스터에는 CS와 다른 값이 설정되야 된다.

그래서 데이터 세그먼트의 이름 DATA를 전송해 준 것이다.

데이터 세그먼트의 값은 어셈블하는 시점(프로그램을 작성할 때)에 이미 정해지는

것이 아니라, 그 프로그램이 실행되기 위하여 메모리 상에  로드된 후에 비로소

처음으로 설정된다. 따라서 소스 프로그램에서는 데이터 세그먼트의 시작 번지를

절대 번지로 지정해 둘 수가 없다.

그래서 이 경우 세그먼트 이름을 사용하여 DS 레지스터에 값을 지정해 둔다.

이와 같이 해 두면 ,어셈블러 링크가 세그먼트 이름이 쓰여진 부분을 상대적인

세그먼트 베이스 값으로서 할당해 준다.







     ## 필자통신

    세그먼트 번지를 표시하는 세그먼트 레지스터의 값으로 절대 주소를 지정할

    수 없고 상대적인 세그먼트 베이스 값을 할당한다는 말은 지금으로서는 무슨

    소린지 몰라도 된다. 뒤에 가서 상세한 설명이 나온다. 다만 프로그램 소스에서는

    세그먼트 번지를 수치로 지정하지 않고 이름으로 지정해 두어야 된다는 사실만

    확실하게 기억하고 넘어가자.


이 프로그램에서는 4줄의 MOV AX,DATA 명령으로 DATA라는 이름의 세그먼트 베이스

값이 AX에 전송한 다음, 바로 이어서 5줄의 mov ds,ax 명령으로 같은 값을 DS 레지스터로

복사해 주었다.

이렇게 번거롭게 중간 다리를 걸쳐 전송하는 이유는 세그먼트 레지스터에 직접적으로는

수치 등의 데이터를 전송할 수 없고, 단지 범용 레지스터에 저장되어 있는 값만을

세그먼트 레지스터로 전송할 수 있기 때문이다.

복습 겸해서 소스 6줄의 내용을 한 번 살펴 보고 넘어가자.


     6. MOV BX,TTT


이 명령은 변수 TTT에 저장된 값을 BX 레지스터로 전송해 준다.

이전의 프로그램에서 이미 사용했던 것이므로 길게 설명하지 않는다.

소스 7줄 이후 main 세그먼트 끝까지의 내용은 일단 BX에 전송된 값을 상위/하위

바이트로 나누어 DL 레지스터로 차례로 전송하여 출력하는 것이 전부이다.

물론 마지막에는 프로그램을 종료하고 도스로 나가기 위해 int 21h, ah=4ch라는

시스템 호출 인터럽트 함수를 이용하고 있다.

이제 남은 부분은 데이터 세그먼트 정의 부분이다.






DATA SEGMENT의 시작 줄과 끝(END) 줄은 이미 설명하였으므로 실제로 설명하지

않고 남은 부분은 다음 한 줄 뿐인 셈이다.


    19. TTT DW  'AB'


TTT라는 이름의 변수에 워드 데이터(DW)인 'AB'를 지정해 주었다. 결국 문자 AB에

대응하는 아스키 값 4142h를 변수 TTT의 값으로 초기화해 준 것이다.

이미 설명한 바와 같이 그 변수의 값이 BX 레지스터로 전송된 후 둘로 나뉘어

차례로 DL 레지스터로 재전송되고 출력된 것이다.

마지막으로 두어 가지 보충으로 정리할 사실들이 있다.


     ## 필자통신

    숙달된 사용자, 감을 잡은 사용자에게는 밥을 먹고 물을 마시는 것처럼 너무나도

    당연한 일들이 초보자에게는 어렵기 마련이다. 초보자를 위하여 약간이라도 헷갈릴

    수 있는 부분은 최대한 보충 설명을 한다.


먼저, 프로그램의 끝을 알리는 END 명령줄은 코드 세그먼트가 끝난 바로 다음에

나온 것이 아니라 모든 세그먼트가 끝난 뒤에 입력되어 있다.

앞에서 이미 지적한 바, END 문장 다음에 어떤 내용이 있더라도 어셈블리는 그것을

무시한다고 한 말을 기억하면 쉽게 이해가 될 것이다.

다음으로 DB, DW 등의 데이터 형을 선언하는 용어는 명령(OP코드)이지 오퍼랜드가

아니라는 사실을 분명하게 알아 두어야 된다.

착각하여 무의식적으로 DW,'AB'와 같이 쉼표(,)로 구분하면 안 된다.


     ## 활용 팁

    프로그램 소스에서 세로로 정렬되어 있는 위치를 유심히 보면 혹시 일으킬

    수 있는 착각과 혼란을 다소간 예방할 수 있을 것이다. TTT라는 변수의 이름은

    코드 세그먼트, 데이터 세그먼트 등 세그먼트 이름과 같은 위치에 있으며 DW

    명령은 MOV 등의 명령과 같은 위치에 있다.




ID:
PW:

     0 분
     3 분

자유게시판

건강백과 HOME

홈페이지 HOME

조   약     HOME

생활지혜 HOME

서식양식 HOME

법원 전산양식 검색

In Na zum

비공개 HOME

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

◁ 2002.9.1.~2018.10.16. ▷

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