어셈블리

어셈블리 강좌2

RSMaster 2019. 7. 9. 19:50

제4장 데이터 전송 명령
--------------------------------------------------------------------------------
MOV 명령과 문자 출력
데이터의 입출력과 전송 명령에 대해서 해설합니다.
*. 레지스터에 수치를 대입한다.
*. 레지스터와 레지스터 사이에서 데이터를 전송한다.
*.레지스터와 메모리 사이에서 데이터를 전송한다.

화면에 " AB "를 표시하는 프로그램
MAIN    SEGMENT             ; 세그먼트를 알리는 의사 명령
        ASSUME  CS:MAIN     ;
;
        MOV     DL,41H      ; 아스키코드 41H ' A  ' 자이다.
        MOV     AH,2
        INT     21H
        MOV     DL, 'B'
        MOV     BL,2
        MOV     AH, BL
        INT     21H
;                            ; 단순히 줄을 띄우기 위해 삽입된 설명문
        MOV     AH,4CH       ; 프로그램의 끝냄
        INT     21H
;
MAIN    ENDS
        END

자기가 작성한 소스 프로그램을 그대로 보고 싶으면 리스트 파일인. LST를 살펴
보는 것이 좋다. 의사 명령은 직접 기계어로 번역되지 않지만 , 어셈블 작업의 흐름을
정할 때에 중요한 역할을 해 줍니다.
여기서 MAIN 은 어떤 이름이든지 상관없다.
ASSUME  CS:MAIN
이라는 의사 명령은 어셈블러가 어셈블을 할때 코드 세그먼트(CS:)를 참조하라는 명령
이 있으면 MAIN이라는 이름의 세그먼트를 참조하라는 선언을 하는 문장입니다.
ASSUME 문장은 4개의 세그먼트(CS, DS, SS, ES)와 세그먼트 이름을 대응시키는  선언문 입
니다.
명령은 반드시 CS:(코드 세그먼트 )에
END 문으로 어셈블러는 끝난다. END 문으로 시작 번지를 지정할 수가 있다.


어셈블러 프로그램의 기본형
AMIN    SEGMENT
        ASSUME  CS:MAIN
       ..........
        본 문
       ..........
MAIN    ENDS
        END


설명문 (comment,  주석 문)을 쓰는 법
;
은 설명문 행입니다. ; 이다음부터 쓰인 문자는 설명문입니다.


8086의 레지스터(register)
--------------------------------------------------------------------------------
범용 레지스터 AX, BX, CX, DX는 8 비트로 나누어 사용할 수 있다.
범용 레지스터 SI, DI, BP, SP는 16 비트로서 밖에 사용할 수 없다.

어셈블러에서는 특별히 표시하지 않는 한 수치는 10진수로서 취급됩니다.
16진수를 사용할 때는 숫자의 뒤에 H(Hexa decimal)를 붙여서 표시합니다.
수치가 알파벳으로 시작할 때는 " 0 "을 붙여 변수 이름과 혼동을 피한다.

MOV     DL,  41H         ; DL  <----- 41H      41H를 DL에 대입하라.
   +--- |    | ----------+
   |    +----+           |
 행선지(DESTINATION), 출원지(SOURCE)

시스템 호출과 입출력은   INT  21H <---- 인터럽트 (interrupt-끼어들기) 명령은
강제로 CPU가 하던 일을 중지시키고 끼어들기

MOV     DL, '1'      ; 문자를 인용부호로 에워싼 것을 오른쪽에 쓴 경우에는
                      그 문자에 대응하는 아스키코드가 쓰인 것으로 간주됩니다.
                      1 은 아스키코드값 31H로 대치됩니다.

프로그램을 끝마치는 방법
MOV     AH,4CH     ; MS-DOS의 SYSTEM CALL 인 4CH 번째의 루틴
INT     21H        ; 프로그램을 마치고 OS 레벨로 돌아간다.


데이터를 두는 방법(1)
--------------------------------------------------------------------------------
프로그램 중에 데이터를 두고 , 그 데이터를 레지스터에 전송하는 방법을 설명
변수 이름 선언 법 :
XXX     DB      'X'       ; DB는 define byte
YYY     DW      3456H     ; DW는 define word
|        |        ---------> 변수에 들어가는 초기치
|        +----------------> 변수의 형
+-----------------------> 변수 이름
DB..... 바이트의 정의
DW..... 워드(2바이트) 정의
DD..... 더블 워드(4바이트) 정의
DQ..... 쿼트 워드(8바이트) 정의
DT..... 10 바이트 정의
*. 사용법  +----------+--------+-----------+
          | 변수 이름 |   DB   |   식      |
          +----------+--------+-----------+

세그먼트를 정의하는 ASSUME 의사 명령
MAIN    SEGMENT
        ASSUME  CS:MAIN, DS:MAIN
MAIN :     세그먼트 개시를 선언
CS:MAIN    코드 세그먼트가 MAIN이라는 이름의 세그먼트에 연결되어있다는 것
DS:MAIN    데이터 세그먼트가 MAIN이라는 이름의 세그먼트에 연결되어 있다는 것

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

명령도 데이터도 둘 다 MAIN이라는 이름의 세그먼트 내에 있으므로
ASSUME  CS:MAIN, DS:MAIN

그러나 이것은 어셈블러에 대한 지시이다
데이터를 처리하는 명령으로는 번역되지 않는다
세그먼트를 초기 설정(initialize) 하기 위해서는
MOV     AX, CS
MOV     DS, AX
이와 같이하여 , AX 레지스터를 경유하여 DS에  CS 의값을 전송하여
2 개의 세그먼트를 일치시키지 않으면 안 됩니다.
 이것은 어셈블러의 정해진 문구입니다.
여기서
MOV     DS, CS
라고 할 수는 없습니다. 세그먼트 레지스터(CS, DS, SS, ES)는 범용 레지스터들로 밖에는
데이터를 전송하는 것이 허용되어 있지 않기 때문입니다.
세그먼트 레지스터에 직접 숫자나 변수를 대입할 수는 없습니다.
어셈블 리스트에서
8A 16 0020 R
R....이라는 문구는 상대 번지(relative address) 지정방식임을 나타내고 있습니다.


데이터를 두는 방법(2)
--------------------------------------------------------------------------------
여러 개의 세그먼트에 두는 법
MAIN    SEGMENT  ---+
        ......      |
MAIN    ENDS     ---+
DATA    SEGMENT  ---+
        .....       |
DATA    ENDS     ---+ 이와 같은 두 개의 세그먼트가 존재하게 설계한다.

ASSUME  CS:MAIN, DS:DATA
데이터를 참조하는 명령이 있는 경우에는 데이터는 DATA라는 이름의 세그먼트에 있다
고 간주하고 명령을 작성하라는 지시입니다.

MOV     AX, DATA
MOV     DS, AX
데이터의 세그먼트의 값을 초기 설정하는 부분입니다.

프로그램을 시작할 때 데이터 세그먼트의 지정 법만 잘 익혀두면 본분 중에서는 데이터
가 어느 세그먼트 내에 있는가  신경 쓰지 않고 , 프로그램을 작성할 수 있습니다.


번지의 간접 지정법(1)
--------------------------------------------------------------------------------
바이트형 데이터는 연속하여 정의할 수 있다.
DB를 사용하여 데이터를 정의하는 경우에 ' ABC ' 와 같이 연속하여 몇 문자라도
데이터를 정의할 수가 있습니다.
XXX     DB      'ABC'      ------+ 모두 같다.
XXX     DB      'A', 'B', 'C'      |
XXX     DB      41H,42H,43H   ---+
        |
        +----> DW, DD, DQ, DT와 같은 다른 변수형의 데이터도 나열할 수는 있습니다.
그러나 수치로써는 가능하지만 문자열로써 주어지는 경우는 한 번에 2 문자 씨의 문
자열밖에 줄 수가 없다.
AAA     DD      'AB', 'CD', 'EF'는 허용이 되지만
AAA     DD      'ABCD', 'EFGH'는 허용이 안된다.

DB의 경우에만이 특별하고 3 문자 이상의 문자열의 나열을
'A', 'B', 'C'로 하는 대신에     'ABC'로 할 수 있다.

자, 그럼 어떻게 XXX라는 변수 이름의 장소에 서 나열되어있는 데이터를 꺼내어 쓸 수가
있는가
MOV     AL, XXX
라고 하면 XXX의 장소에 나열된 문자열의 제일 처음 의 것인  'A'=41H 가 AL 레지스
터에 전송됩니다.(XXX라고 하는 이름의 장소에 있는 데이터를 AL레지스터에 전송하라)

변수가 자리 잡고 있는 번지를 꺼내는 오프셋(OFFSET 명령):
MOV     BX, offset XXX
                  |      변수 이름이 붙여진 번지 자체의 값을 BX 레지스터에 전송하
                  +----->는 명령입니다.
OFFSET :  변수 이름이 붙여진 데이터가 있는 번지를 꺼내는 연산자.
오프셋 번지 : 세그먼트를 기준으로 한 번지

MOV     BL, XXX ; BL과  XXX는 8 비트 이므로 가능
MOV     BX, XXX ; BX는 16비트 레지스터, XXX는 8비트 레지스터이므로 에러

[  ]를 사용한 간접 번지 지정방식:
어떤 번지의 내용을 꺼낼 때에는 [번지 ]와 같이 [  ]를 붙인다.
MOV     DL, [1FH] ; 1FH 번지에 있는 데이터를 DL 레지스터로 전송하라

BX 레지스터 내에 변수 XXX의 처음 데이터가 DL 레지스터로 전송됩니다.
그다음은 이것을 표시합니다.
2 번째 데이터는 선두 번지 +1 번지에 저장되어 있으므로, 여기서는 BX + 1 번지의
내용을 꺼내면 되는 것입니다. 같은 방법으로 BX+2, BX+3.......
MOV     DL, [BX+1]
[  ] 내의 값이 나타내는 번지에
저장되어 있는 내용을 꺼내는 것을 지시하고 있습니다.
이와 같은 지정법을 간접 지정방식(indirect addressing )이라고 부릅니다.
MOV     AX, [1234H]
와 같은 지정법도 간접 번지 지정방식의 일종으로서의
직접 번지 지정방식(direct addressing mode)이라고 부릅니다
MAIN    SEGMAIN                ;  *. 데이터를 세그먼트 내에두는 경우
        ASSUME  CS:CODE, DS:DATA

        MOV     AX, DATA
        MOV     DS, AX
        +-----------+
        | 본  문    |
        +-----------+
MAIN    ENDS

DATA    SEGMENT
XXX     DB      'ABC'
DATA    ENDS
        END

번지의 간접 지정법(2)
--------------------------------------------------------------------------------
간접 지정에 사용할 수 있는 레지스터는 4개뿐이다
BX, BP, SI, DI
왜 그런가 하는 것은 8086 설계자가 정해놓은 일이다.

[BX+DI]
[BX+SI+1]
와 같은 이들끼리의 조합 지정이 가능합니다
예) [BX+SI+4]
BX=1000H
SI=1234H  인 경우
1000H + 1234H + 4H = 2238H 이 된다.

간접 지정 조합법의 규칙:
+----+       +-------+       +--------------+
| BX |       |  SI   |       |  16비트 숫자 |
| BP |   +   |  DI   |    +  |  8비트 숫자  |
|없다|       |  없다 |       |  없다        |
+----+       +-------+       +--------------+
  [BP]는 단독으로 사용할 수가 없습니다.
단순히 기계적 제약에서 오는 것입니다 사용하고 싶다면   [BP+0]으로 합니다.
MOV     DL, [BX+SI]
; BX에는 변수의 시작 번지 , SI에는 3을 대입,
따라서 DL 에는 변수의 선두로부터 4 번째 바이트의 데이터가 DL 레지스터에  전송한
다.   *. SI= 0부터 선두를 가리킨다.

예제) MOV5.ASM
메모리에서 저장된 문자열" ABCDEFG" 중 네 번째, 다섯 번째 문자 DE를 출력
MAIN    SEGMENT
        ASSDUME CS:MAIN, DS:DATA
;
        MOV     AX, DATA
        MOV     DS, AX
        MOV     BX, OFFSET AAA
        MOV     SI,3
        MOV     DL, [BX+SI]
        MOV     AH,2
        INT     21H
        MOV     DL, [BX+SI+1]
        MOV     AH,2
        INT     21H
;
MAIN    ENDS
;
DATA    SEGMENT
AAA     DB      'ABCDEFG'
;
DATA    ENDS
        END
*. 간접 지정에 사용하는 레지스터에    BP  레지스터가 포함되는 경우에는 ,
   스택 세그먼트(SS:)에 데이터가 있는 것으로서 해석된다.
 (  보통은 BP 레지스터를 사용한 간접 지정법은 안 하는 것이 무난할 것입니다. )


간접 번지 지정방식의 사용법
--------------------------------------------------------------------------------
CODE    SEGMENT
        ASSUME  CS:CODE, DS:DATA
;
        MOV     AX, DATA          ; DS를 설정
        MOV     DS, AX
;
        MOV     BX, OFFSET AAA    ; AAA의 번지 값을 BX에 대입
        MOV     AX, 'AB'          ; 문자 하나는 8비트
        MOV     [BX], AX          ; BX 가 가리키는 AAA 변수에 'AB'를 넣는다
        MOV     CX, AAA
        MOV     DL, CH            ; DL에 A를 넣는다
        MOV     AH,2       ----+
        INT     21H        ----+ 문자 A를 보인다.
        MOV     DL, CL            ; DL에 B를 넣는다.
        MOV     AH,2       ----+ 문자 B를 보인다.
        INT     21H        ----+
        MOV     AH,4CH
        INT     21H              ; 종료하고 OS 로돌아간다.
;
CODE    ENDS
;
DATA    SEGMENT
AAA     DW                     ; AAA라는 변수를 위해서 워드 영역을 확보하라
DATA    ENDS
        END

AAA     DW?  는   '? ' 는 숫자는 아무것이라도 좋다는 의미입니다.

이밖에 사용법으로는
MOV     [BX+SI+5],1234H
MOV     AAA, 'AB'
라는 사용법이 가능합니다.

MOV     [BX], [SI+3]
그러나  이와 같은 , 오퍼랜드 양쪽 다 간접 지정으로 할 수는 없습니다.

MOV     BX, [0008] -----> 8 번지의 내용을 꺼내온다 라는 간접 지정방식
레지스터를 사용하지 않고 수치만으로 번지를 지정하는 이러한 방법을 직접 번지 지정
(direct addressing)이라고 말합니다.
또한, MASM에서는 이와 같은 직접 번지 지정방식을 어셈블러 속에 쓸 수가 없습니다.
그것은 메모리 번지는 링커에  의해 동적(dynamic)으로 활당되기때문에 , 고정된  번지 
지정방식을 사용할 수 없다고 가정되기 때문이라고 생각됩니다.

EQU 의사 명령
--------------------------------------------------------------------------------
상수를 정의하는 EQU 의사 명령
MAIN    SEGMENT
        ASSUME  CS:MAIN
CHAR1   EQU     'A'    ;'A' = 41H 가 정의됩니다 --+
CHAR2   =       42H    ;  = 는 재정의가 가능       |
DISP    EQU     2      ;  EQU는 재정의가 불가능, --+상수는 어셈블 할 때 치환
;
        MOV     DL, CHAR1
        MOV     AH, DISP
        INT     21H
        MOV     DL, CHAR2
        MOV     AH, DISP
        INT     21H
        MOV     AH,4CH
        INT     21H
;
MAIN    ENDS
        END


EQU 의사 명령에 의한 상수의 정의와 DB 등에 의한 변수의 정의와의 차이는 :
EQU에 의해서 선언된 상수 - 어셈블 할 때 직접 숫자로 치환
DB 등에 의해서 선언된 변수 - 데이터가 저장되어 있는 번지로서 치환
예)
MOV CHAR1, DL  ----->  불가능
'='에 의해서 정의된 숫자를 다시 정의할 때는 , 다시 '='를 사용해서 정의한다.
어셈블러는 시작 순서대로 어셈블을 해나가면서 가장 최근에 정의된 숫자를 그 상수
의 숫자로써 사용합니다.
따라서 다음과 같이 됩니다.
CHAR1   =       41H
        MOV     DL, CHAR1
CHAR1   =       56H
        MOV     DL, CHAR1
결과 :
=       0041
0000    B2      41
=       0056
0002    B2      56


데이터의 형과 PTR 연산자
--------------------------------------------------------------------------------
데이터의 형(type):
바이트, 워드(2바이트), 더블 워드(4바이트)
데이터의 형은 레지스터의 크기와 같다고 간주된다.

주의 )
오퍼랜드에 레지스터를 포함하지 않은 경우 크기의 지정이 필요
예) 한쪽이 간접 번지 지정 , 또 한쪽이 숫자의 경우입니다.

MOV     [BX],12H
여기에서 BX의 값이 10H라고 합시다. 그런데 여기서는
1) 10H 번지에 바이트 데이터 12H를 저 정할 것인지,
2) 10H 번지와 11 번지에 워드 데이터 0012H를 저장하는 것인지 알 수가 없습니다.

*. 바이트 데이터의 경우                       *. 워드 데이터의 경우
번지  |        |        |         |          번지 |         |         |       |
      +--------+        +---------+               +---------+         +-------+
 10H  | 55     |  12H   |  12     |           10H |   55    | 0012H   |  12   |
      +--------+------> +---------+               +---------+-------> +-------+
 11H  | 66     |        |  66     |           11H |   66    |         |  00   |
      +--------+        +---------|               +---------+         +-------+
      |        |        |         |               |         |         |       |
12H를 바이트 데이터로써 저장한 경우에는 11H 번지의 내용은 사라지지 않고 남지만
12H 를  워드 데이터로써 저장한 경우에는  11H의 내용은 지워져 버립니다.

 

PTR 연사자의 사용
--------------------------------------------------------------------------------
데이터의 형을 명확하게 하기 위하여
MOV     BYTE PTR [BX],12H  ; PTR 은 POINTER의 약자
MOV     WORD PTR [BX],12H
이와 같이 전송되는 측에 BYTE 또는 WORD를 지정합니다.
이때 PTR이라는 오버라이트 (overwrite) 연산자와 함께 사용하도록 되어 있습니다.
변수로 선언되어 있는 형이 DB 이든 DW 이든  BYTE , WORD 양쪽 다 사용할 수가 있을
니다.

MOV 명령과 번지 지정방식의 정리
---------------------------------
ADDRESING MODE:
*. 즉치 방식(immediate mode)
AAA     EQU     1234H
        MOV     AX, AAA  ;메모리의 바이트수가 레지스터 바이트 이내일 것
 CS, DS, ES, SS 및 IP, FL 레지스터에 직접 수치를 전송할 수는 없습니다.

*. 직접 방식(레지스터 번지 지정 방식)
레지스터의 내용을 직접 전송하는 방식
MOV     DS, AX
MOV     CL, BH   ; 양쪽의 레지스터의 크기가 일치하는 8비트 혹은 16비트 여야 한다.
세그먼트 레지스터 간의 전송은 할 수가 없다 . IP ,FL 레지스터는 사용할수가 없고 ,
CS 레지스터로의 값을 전송은 할수 없습니다.

*. 간접 방식(메모리 번지 지정 방식)
전송하는 값이 저장되어 있는 번지를 지정- 방법 2가지
1) BX, BP, SI, DI의 4 가지 레지스터와 숫자를  조합시킨다.
MOV     AX, [BX+DI+4]
2) 데이터를 변수로서 정의하고 , 그 변수 이름을 사용하여 지정하는 경우
MOV     AX, AAA ; 숫자가 있는 번지에 붙여진 이름을 사용하여 간접 지정을 하는 것

간접 방식에서의 번지 지정법:
+-  BX  -+   +-  SI  -+   +-   8비트 숫자  -+
|   BP   | + |   DI   | + |   16비트 숫자   |
+- 없음 -+   +- 없음 -+   +-    없 음      -+

위에서 허용되지 않는 조합 방법
1) 8비트 숫자만을 사용하는 경우( 번지는 16비트가 아니면 지정할 수 없다 )
 그러나  MOV   AX, [1234H]와 같은 직접 번지 지정 방식은 사용할 수 없다.
 직접 메모리 번지를 지정하여 간접 방식을 사용하고 싶을 때는 -
 MOV     BX,1234H
 MOV     AX, [BX]    ; 와 같이 하지 않으면 안 됩니다.
2) [BP]를 사용할 수 없다.
 [BP]를 사용하고 싶을 때에는 [BP + 0 ]를 하면 된다

간접 지정할 때의 주의 사항 :
1) 명령은 모두 코드 세그먼트에 있다고 본다
2) 데이터는 데이터 세그먼트 내에 있다고 가정된다.
3) BP를 포함하는 간접 지정에서는 데이터는 스택 세그먼트 내에 있다고 가정된다.
4) 프로그램의 처음에서 데이터 세그먼트의 초기 설정이 필요
  MOV   AX, DATA
  MOV   DS, AX    ; DATA를 데이터 세그먼트에 맞춘다.

  MOV   AX, CS
  MOV   DS, AX    ; 데이터 세그먼트를 코드 세그먼트와 맞춘다.

그런데 어떻게 해서라도 데이터 세그먼트 이외의 세그먼트로부터 데이터를 가져오고
싶다는 경우 세그먼트 오버라이트 프리픽스(segment overwrite prefix)를 설정, 그 명
령에 한해서 지정한 세그먼트의 지정한 번지로부터 데이터를 갖고 오거나, 가지고 갈
수 있습니다.
예)
MOV     AX, ES:[BX]
MOV     CS:[DI+2], CX
세그먼트 오버라이트 프리픽스는 다음의 4가지입니다.
CS:,DS:,SS:,ES:

 


MOV 명령으로 전송 가능한 조합
--------------------------------------------------------------------------------
MOV     AX, CS
MOV     DS, AX
등 과 같은 형태로 DS   <---- CS를 한 이유는 , 세그먼트 레지스터간의 전송이 허용
되지 않기 때문입니다.
또한 ,세그먼트 레지스터에는 직접 숫자를 대입하는 것이 허용되어 있지 않습니다.
IP, FL 레지스터는 MOV 명령에서 데이터 전송을 할 수 없는 것으로 되어 있습니다.
CS 레지스터에의 데이터의 전송은 허용되지 않습니다.
CS 레지스터는 읽어내기만 가능합니다.

'어셈블리' 카테고리의 다른 글

어셈블리 강좌5  (0) 2019.07.09
어셈블리 강좌4  (0) 2019.07.09
어셈블리 강좌3  (0) 2019.07.09
어셈블리 강좌1  (0) 2019.07.09
[SoftIce] 초보를 위한 명령어 이해하기  (0) 2019.07.09