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

홈페이지HOME

PHP

JavaScript

HTML

CSS

드롭다운메뉴

제로보드4

도   움   말

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

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

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

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

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

관주성경 TTS 일반파일 TTS

바이블로 Bible_ro 다운로드

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

[도움말 보기] 바로가기

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

asm_05.

(캐리 플래그)



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

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

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

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

우리는 외국 사람들과 대화하기 위하여, 그 외국 사람들 사이의 약속인 해당 외국어를

열심히 배웁니다.

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




필자의 부탁

어셈블리 연재를 시작한 후로 필자로서는 의외로 너무 쉽다고 감사하는 편지를

가끔 받고 있습니다. 쉽게 쓰는 것은 필자의 소신입니다. 그러나, 필자도 이제 프로그래밍을

배우는 사람입니다. 필자가 현재 여러 종류의 연재를 하고 있지만 다른 연재는 크게

부담이 되지 않는 반면, 어셈블리는 필자도 독학으로 배우면서 하는 것이라서 혹시

실수나 없을까 상당히 부담이 되는 것이 사실입니다. 필자가 프로그래밍의 초보이기

때문에 누구나 쉽게 쓰는 일에는 오히려 도움이 된다고도 생각할 수 있지만, 스스로도

완전히 이해하지 못하면서 쉽게 쓴다는 것은 있을 수 없는 일이기 때문에 경우에

따라서는 며칠 동안 끙끙거리기도 합니다.

필자를 도와 주십시오. 이 연재를 보시는 분들 중에는 프로그래밍을 공부한 지

오래 되어 특정 프로그래밍에 대해서는 나름대로 상당한 프로그램 습작까지 하신

분들도 있는 줄 압니다. 그런 분들은 약간의 시간을 내어 필자에게 과감한 충고 또는

방향 제시도 해 주시면 좋겠고, 또 디버그만으로 다룰 수 있을 만한 수백 바이트

이내의 작은 프로그램이 있으면 모아서 보내 주시기 바랍니다. 필자는 비싼 언어

패키지를 구입하지 못한 분들도 도스만으로 습작할 수 있는 디버그 프로그래밍 설명을

가능하면 계속할 생각입니다.

이 글을 보시는 분들 중에서 정말로 필자와 같은 초보자일지라도 주위에 굴러

다니는 작은 프로그램을 모아서 보내 주시는 일은 조금만 성의를 가지면 가능할 줄

믿고 부탁드립니다. 그리고 초보자라고 아무 생각이 없는 것은 아니므로, 생각되는

모든 의견과 조언을 수시로 보내 주시면 최대한 참고하겠습니다. // 질문은 받지 않음을 양해

필자를 도와 주시기 바랍니다. 함께 만들어 갑시다.




제 05 장  캐리 플래그

플래그(flag)란 기, 기를 올리다, 신호하다 등의 뜻이 있는 단어이다.

디버그상에서 레지스터(r <Enter>) 명령을 했을 때, 둘째 줄 오른쪽에 2

글자 코드의 조합으로 나타나는 8 개가 플래그이다.

각각의 플래그가 어떤 상태를 알려 주는 신호인지는 차츰 알게 된다.

이 장에서는 플래그라고 부르는 특정 상태 표시 레지스터 8개 중에서 캐리 플래그의

용도를 알아 보고, 캐리 플래그를 이용한 비트 단위의 회전도 살펴 본다.

이 장에서 설명하는 내용은 지금 단계로 그것을 이용하여 간단하게 실행할 수

있는 작은 프로그램을 짜기보다는, 앞으로의 프로그래밍을 위한 기반 지식을 쌓는

의미가 있기 때문에 약간은 따분하게 느낄 수도 있을 것이다.

그러나, 항상 재미만으로 진행할 수는 없다.

필자가 쉽게 이해되도록 구체적인 설명을 디버그 실행 화면을 곁들여 진행하려고

하니, 중요한 기초를 확실하게 다지고 넘어가도록 하자.




제 1 절  플래그 입문

플래그의 설정 상태만을 보려면 디버그상에서 다음과 같이 명령한다.


     - r f <Enter>

     NV UP EI PL NZ NA PO NC

     -


이하 이 절의 설명은 지금은 그냥 한 번 읽어 보고 넘어가자.

나중의 참고와 색인에는 도움이 될 것이다.

각 플래그의 설정/해제 상태를 대비하여 표시하면 다음과 같다.


     이름-넘침  방향  인터럽트 사인 제로  보조캐리  패리티

     캐리

     설정- OV DN EI  NG

    ZR  AC  PE

     CY

     해제- NV UP DI  PL

    NZ  NA  PO

     NC


따라서, 필자의 컴퓨터 화면에서 본 플래그 상태(NV UP EI PL NZ NA PO NC)의

각 항목을 하나씩 비교해 보면 인터럽트 플래그만 설정(EI)되고 나머지는 모두 해제된

상태였다는 사실을 확인할 수 있게 된다.

도스 매뉴얼에 나와 있는 각 플래그의 이름과 설정 해제 상태는 다음과 같다.


    --------------------------------------------------------------------------

    Flag name Set Clear

    --------------------------------------------------------------------------

    Overflowovnv

    Direction dn

    (decrement)up

    (increment)

    Interrupt ei

    (enabled)di

    (disabled)

    Signng

    (negativ)pl

    (positive)

    Zerozrnz

    Auxiliary Carry acna

    Paritypc

    (even) po

    (odd)

    Carry cync

    --------------------------------------------------------------------------


각 플래그의 본래 이름에 비추어 보면 그 플래그의 설정 또는 해제 상태를 표시하는

2 글자의 이름도 어렵지 않게 이해하게 될 것이다.

그리고, 필요에 따라 사용하다 보면 저절로 외워지기도 할 것이다.

지금 모든 의미를 알거나 외우려고 하는 것은 낭비가 될 뿐이다.

다음으로 넘어가자.



     ## 활용 팁


프로그래밍을 하려면 용어, 단위 등을 알아야 된다. 앞에서 다 설명한 것이라도

일일이 기억하지 못하는 경우가 있을 것이므로 정리해 보자.

바이트(크기 단위) 16진수

2자리 = 2진수  8자리

워  드(크기 단위) 16진수

4자리 = 2진수 16자리




제 2 절  캐리 플래그

비트라는 것은 2진수 1 자리를 가리키는 말이라는 것은 이미 알았다.

바이트 즉 2 자리의 16진수는 2진수로 환산하면 8 비트가 된다.

워드 즉 4 자리의 16진수는 2진수로 환산하면 16 비트가 된다.


1.  캐리 플래그

캐리 플래그는 1 비트의 2진수를 저장하는 플래그이다.

따라서 캐리 플래그에는 0 또는 1 중 한 숫자가 저장될 수 있을 것이다.

그러면 그 숫자는 어디서 넘어와 캐리 플래그에 저장되는가?

바이트 단위의 계산에서는 어떤 계산의 결과값이 8 비트가 넘는 수가 되었을 때

왼쪽으로 밀려난 1이라는 숫자가 캐리 플래그에 저장될 것이며, 워드 단위의 계산에서는

어떤 계산의 결과값이 16 비트가 넘는 수가 되었을 때 역시 왼쪽으로 밀려난 1이라는

숫자가 캐리 플래그에 저장될 것이다.


    1 00000000 (11111111 + 00000001)

    (바이트 단위에서 8비트를 넘친 한 비트 숫자가 캐리 플래그에 저장됨)

    1 00000000 00000000 (11111111 11111111 + 00000000 00000001)

    (워드 단위에서 16비트를 넘친 한 비트 숫자가 캐리 플래그에 저장됨)




     ## 활용 팁


캐리 플래그는 마지막으로 쫓겨난 한 비트만을 기억해 주는 임시저장소라고 생각하면

좀 쉽게 이해가 될지 모른다.


그런 경우에 캐리 플래그는 설정 상태가 되어 r <Enter> 또는 r f <Enter>

명령을 해 보면, 캐리 플래그는 cy로 보일 것이다.




2.  캐리 플래그와 워드 단위의 더하기

캐리 플래그에 대한 지금까지의 간단한 설명만으로 충분히 이해하기 어려울지

모르기 때문에, 디버그를 실행하여 좀 더 확실하게 알아 보기로 하자.

먼저 워드(16진수 4자리) 단위의 더하기로 캐리 플래그를 변경시켜 보자.


    ...> debug <Enter>

    - a <Enter>

    ????:0100 mov ax,ffff

    <Enter>

    ????:0103 mov bx,1

    <Enter>

    ????:0106 add ax,

    bx <Enter>

    ????:0108 int 20

    <Enter>

    ????:010A <Enter>

    -


레지스터 ax에 16진수 ffff라는 워드를 저장하고, 레지스터 bx에 16진수 0001이라는

워드를 저장한 후, 두 수를 합친 값을 ax 레지스터에 저장한다.

그 다음의 int 20은 초보자의 사고를 예방하기 위하여 넣어 둔 것이다.

이제 레지스터 상태를 한 번 보자.


    - r <Enter>

    AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE ..............

    .............. IP=0100 NV UP EI PL NZ NA PO NC

    ????:0100 B8FFFFMOV AX,FFFF


레지스터 ip가 지적하는 오프셋 100번지에 저장된 명령은 기계어로 B8FFFF이고

어셈블리어로는 MOV AX,FFFF라고 표시되어 있다.

한 명령어씩 추적 실행하기 위해 t 명령을 이용하기로 하자.

상태 플래그 8개 중 마지막을 보면 NC(No Carry)가 보인다.




디버그를 처음 시작하면 캐리 플래그는 항상 NC로 설정된다.


    - t <Enter>

    AX=FFFF BX=0000 CX=0000 DX=0000 SP=FFEE ..............


        ..............  IP=0103 NV UP EI PL NZ NA PO NC


    ????:0103 BB0100MOV BX,0001


오프셋 100번지의 mov ax,ffff가 실행된 결과 AX 레지스터의 값이 변했다.

그리고 다음에 실행할 오프셋 103번지의 명령을 보여 주는데, 우리가 어셈블리어로

16진수 0001을 입력한 것이 기계어로는 0100으로 나타나 있다.

워드 단위의 수를 입력하면 메모리에는 바이트 단위로 거꾸로 저장된다.


    - t <Enter>

    AX=FFFF BX=0001 CX=0000 DX=0000 SP=FFEE ..............

    ............................  IP=0106 NV UP EI PL NZ NA PO NC

    ????:0106 01D8ADD AX,BX


오프셋 103번지의 명령이 실행되어 bx 레지스터의 값도 변했다.

다음 명령은 두 레지스터의 값을 합치는 명령인데, 결과는 ax에 저장된다.

16진수 ffff와 0001을 합치면 10000이 된다. 그런데 ax 레지스터에는 워드 즉

16진수 4자리 밖에 저장할 수 없기 때문에, 다섯째 자리의 1은 사라진다.

결과를 보기 위해 이어지는 명령을 실행하자.


    - t <Enter>

    AX=0000 BX=0001 CX=0000 DX=0000 SP=FFEE ..............


        ..............  IP=0108

        NV UP EI PL NZ NA PO CY


    ????:0108 CD20INT 20

    -


역시 두 수를 합한 결과의 오른쪽 4자리 0000이 ax 레지스터에 나타나고 자릿수를

넘은 1은 사라졌다. 그런데 그와 동시에 지금까지 항상 NC로 보이던 캐리 플래그가

CY로 변한 것을 알 수 있다. ax 레지스터에서 자리가 모자라 쫓겨난 16진수 1이 캐리

플래그에 저장된 사실이 확인되었는가?






3.  캐리 플래그 해제

워드 단위의 더하기에서 16진수 다섯째 자리(2진수 17번째 자리)로 넘친 1 비트가

캐리 플래그에 저장되어 캐리 플래그가 CY로 변하는 사실을 확인했다.

이제 바이트 단위의 더하기에서도 플래그의 변경을 확인해 보기로 하자.

그런데 중간에 양념으로 잠깐 이해하고 넘어갈 내용이 있다.


    - rip <Enter>

    IP 0108

    : 100 <Enter>

    - a <Enter>

    ????:0108


레지스터값을 변경시키기 위한 <r 레지스터<Enter>> 명령에서 r과

레지스터 이름은 붙여 써도 무방하다. 이 화면을 보여 주는 이유가 있다.  어셈블(a)

명령에 있어서, 비록 ip 레지스터의 값을 100으로 수정해 준 후에라도 오프셋 번지를

지정하지 않고 a 명령을 하면 100번지부터 편집하는 것이 아니라 현재의 오프셋 번지(방금

마지막 실행이 끝나고 도착한 번지)부터 편집하게 된다는 사실을 잘 모르는 사용자에게

확인시켜 주기 위함이다.


    ????:0108 <Enter>

    - t <Enter>

    AX=FFFF BX=0001 CX=0000 DX=0000 SP=FFEE ..............

    ..............IP=0103

    NV UP EI PL NZ NA PO CY

    ????:0103 BB0100MOV BX,0001

    -


어셈블 명령이 아닌 트레이스(t) 명령을 실행하니 어떻게 되었는가?

오프셋 100번지부터 다시 실행이 되는 것을 확인할 수 있었다.






이런 사실을 한 번 읽어 두면 도움이 될 것이다.


    ip 레지스터 값은 다음에 실행될 명령어의 위치를 지정할 뿐이다. 어셈블을

    특정 번지부터 다시 하려면 <a 번지> 명령을 사용해야 된다.


    - a 100 <Enter>

    ????:0100


이 상태에서 어셈블을 하여 바이트 단위의 더하기를 해 볼 수는 있다.

그러나 사소한 문제 및 결정적인 문제가 있다.

우선 ax 레지스터에 ffff라는 값이 들어 있고 bx 레지스터에 0001이라는 값이

들어 있는데, 이것은 아무 문제도 될 것이 없지만 처음 시도할 때는 왠지 불편하고

마음에 걸릴 수도 있다. 그 문제는 간단하게 해결할 수 있다.


    ????:0100 <Enter>

    - rax <Enter>

    AX FFFF

    : 0 <Enter>

    - rbx <Enter>

    BX 0001

    : 0 <Enter>

    -


그보다는 심각한 문제가 하나 있는데, 캐리 플래그가 CY로 남아 있는 점이다.

앞에서는 우리가 16진수 4자리를 넘치게 하여 NC가 CY로 변하는 것을 확인할 수

있었는데, 이제는 우리가 16진수 2자리를 넘치게 하여 넘친 1비트가 캐리 플래그로

저장되더라도 이미 캐리 플래그가 CY로 보이는 상태에서 새롭게 1비트가 캐리 플래그로

저장되었다는 사실을 어떻게 확인할 수 있겠는가?

그 문제를 해결하기 위해 조금 있다가 배울 비트 회전을 잠깐 빌려 쓰자.

특정 번지부터 어셈블하려면 항상 <a 번지<Enter>> 명령을 사용하자.


    - a 100 <Enter>

    ????:0100 rcl bl,1 <Enter>

    ????:0102 <Enter>

    -





실행에 실수하지 않기 위해서도 먼저 ip 레지스터를 확인, 수정해 두어야 된다.

그리고 오프셋 100번지에 저장한 rcl 명령을 실행해 보자.


    - rip <Enter>

    IP 0103

    : 100 <Enter>

    - t <Enter>

    ............................................................. NC


나머지 화면은 생략해도 알 것이다. 캐리 플래그가 NC로 변한 사실만 확인하면

그것으로 성공이다. 사실은 rcl bx,1과 같이 어셈블해도 같은 결과가 나온다.

그 명령은 지정한 레지스터 값의 가장 왼쪽 1비트를 캐리 플래그로 보내는 명령인데,

워드와 바이트로 나누어 설명하면 이렇게 된다.


    BL00h 00000000b

    BX0000h 00000000

    00000000b


가장 왼쪽의 1비트 숫자는 0이다. 0이 캐리 플래그로 저장되었기 때문에 캐리

플래그가 해제되어 NC로 변한 것이다.

캐리 플래그는 나중에 자세히 설명하겠지만, 내친 김에 간단하게 정리해 두자.


    캐리 플래그에 0b(2진수 0)이 저장되면 해제되어 NC가 되고, 1b가 저장되면

    캐리 플래그가 설정되어 CY가 된다.


물론 캐리 플래그 해제라는 복잡한 과정을 무시하고, q 명령으로 디버그를 끝내었다가

다시 시작하면 캐리 플래그가 당연히 NC로 나타날 것이다.

그러나 약간의 수고를 하면서 캐리 플래그를 해제해 본 결과 얻은 것이 있으리라고

믿으며, 그 지식은 상당한 도움이 될 것이다.




4.  캐리 플래그와 바이트 단위의 더하기

이제 바이트 단위의 더하기로 캐리 플래그를 발생시켜 보자.


    - a 100 <Enter>

    ????:0100 mov al,ff <Enter>

    ????:0102 mov bl,1 <Enter>

    ????:0104 add al,bl <Enter>

    ????:0106 <Enter>

    - rip <Enter>

    IP ????

    : 100 <Enter>

    -


이제 t를 한 번씩 세 번만 누르면서 추적 실행해 보라. 세 번 이상은 실행하지

말기 바란다. 사용자가 입력하지 않은 엉뚱한 명령을 감행할 우려가 있으니까.

처음 실행했을 때 AX=00FF로 변하고, 두번째는 BX=0001로 변하며, 마지막으로

다시 AX=0000으로 변하면서 NC가 CY로 변한 사실이 확인되었는가?

화면 소개는 일일이 하지 않는다.

필요하면 앞에서 설명한 워드 단위의 더하기 화면을 참고하기 바란다.




제 3 절  비트 회전

우리가 어셈블리어로 프로그램을 짤 때는 16진수로 입력하지만, 원래 컴퓨터가

알아 보고 다루는 수는 2진수이다.

비트 회전이란 것도 2진수 1자리인 비트가 움직여 돈다는 뜻이다.

결국 비트 회전이란 워드 또는 바이트 단위의 레지스터 값을 2진수로 환산했을

때 그 가장 끝의 한 자리가 레지스터를 빠져 나갔다가 다시 반대편 자리로 들어오는

현상을 가리키는 말이라고 이해하면 된다.


1.  왼쪽 회전, 오른쪽 회전

가장 높은 자리(워드의 15비트 자리, 또는 바이트의 7비트 자리)의 1비트가 회전하면

우리가 보기에 왼쪽으로 움직인다고 생각하는 것이 쉽고, 가장 낮은 자리(0비트 자리)의

1비트가 외전하면 우리가 보기에 오른쪽으로 움직인다고 생각하는 것이 이해하기에

쉬울 것이다.

따라서 비트 회전을 왼쪽과 오른쪽으로 나누어 서로 다른 명령어를 사용한다.


    왼쪽으로 비트 회전 = rcl레지스터,수치

    왼쪽으로 비트 회전 = shl레지스터,수치

    오른쪽으로 비트 회전 = shr레지스터,수치


rcl은 Rotate Carry Left이고, shl은 Shift Left, shr은 Shift Right이다.

[레지스터]에는 비트 회전을 시킬 값을 담고 있는 레지스터 이름을 입력한다.

[수치] 자리에는 몇 비트를 회전시킬지를 입력한다. 다만 8088 프로세서에 있어서는

그 명령으로 두 비트 이상을 동시에 이동시킬 수 없기 때문에 rcl,1 명령만이 가능하며,

80286 이상에서는 rcl,2와 같은 명령도 사용이 가능하다.

8088 프로세서에서도 shl, shr 명령을 사용하면 여러 비트를 한꺼번에 회전시키는

것이 가능하다. 그 문제는 뒤에 가서 배우게 될 것이다.




2.  덧셈과 비트 회전

우리는 앞에서 덧셈을 했을 때 레지스터에서 넘친 1비트가 캐리 플래그에 저장되는

사실을 실습을 통하여 충분히 이해하였다.

그것과 비트 회전의 차이는 무엇인가를 먼저 알고 넘어가자.

덧셈을 한 과정과 결과를 그림으로 그려 보면 이렇게 된다.


    FFh + 1h = 11111111b + 1b = 1 00000000b = 1 00h


즉 16진수 ff에 1을 더했을 때 결과는 100이 되어 왼쪽 1(이것은 16진수로나 2진수로나

1임)이 캐리 플래그로 저장되었다는 사실을 알 수 있다.

만약 같은 16진수 ff를 1비트 왼쪽으로 회전시키면 어떻게 될까?


    FFh(←rcl) = 11111111b(←rcl) = 1 1111111?

    55h(←rcl) = 01010101b(←rcl) = 0 1010101?


비트 회전은 가장 왼쪽 또는 가장 오른쪽 자리의 1비트만 움직이는 것이 아니라

모든 자리의 숫자가 동시에 전체적으로 1비트만큼 움직이는 것이다.

따라서 1비트 왼쪽으로 회전시켰을 때는 왼쪽의 가장 높은 자리 1비트가 멀려나서

캐리 플래그로 가고, 나머지 7자리도 함께 왼쪽으로 이동한 결과 오른쪽 가장 낮은

자리 1비트가 비게 되는데 그 자리를 무언가로 메꾸게 될 것이다.

그래서 끝의 채워질 빈 자리에 어떤 수가 나타날지, 즉 0이 될지 1이 될지 모르기

때문에 ? 표시를 해 둔 것이다.

덧셈으로 인한 캐리 플래그의 변경과 비트 회전으로 인한 캐리 플래그의 설정/해제의

차이점으로 대략 다음과 같은 정도를 정리하고 넘어가자.


    1. 덧셈으로 넘친 1비트는 캐리 플래그를 설정할 뿐 해제하지 못한다.

    2. 비트 회전으로 저장된 1비트는 캐리 플래그를 설정하거나 해제한다.

    3. 덧셈으로는 오른쪽 1비트가 캐리 플래그로 저장되는 일은 없다.

    4. 비트 회전은 오른쪽으로 하면 오른쪽 1비트가 플래그에 저장된다.

    5. 덧셈으로 1비트가 넘치는 경우 레지스터 값은 00 또는 0000이 된다.

    6. 비트 회전을 한 결과 레지스터의 값은 어떻게도 변할 수 있다.


지금으로서는 이 정도 이해하면 만족해도 될 것이다.

비트 회전을 하였을 때 레지스터 값이 어떻게 다양하게 변하는지는 나중에 실습을

통해 구체적으로 이해하게 될 것이다.




3.  비트 이동을 회전이라고 부르는 이유

그러면, 1비트씩 왼쪽으로 이동시킬 때마다 비게 되는 오른쪽의 1비트는 어디에서

무슨 숫자를 가져다가 채우게 되는 것일까?

그 숫자는 바로 비트 이동을 하기 직전에 캐리 플래그에 들어 있었던 숫자이다.

따라서 왼쪽으로 비트 이동을 하는 경우, 캐리 플래그는 자기가 가지고 있던 숫자

1비트를 비트 이동하는 수의 오른쪽 빈 칸으로 넘겨 주고 그 수에서 왼쪽으로 밀려난

1비트 숫자를 받아서 캐리 플래그 자신에 채워 넣는 것이다.

이해를 돕기 위하여, 레지스터에 저장된 2진수와 플래그에 저장된 0(디버그를

처음 실행하면 항상 캐리 플래그는 0 즉 nc로 초기화됨)의 각 비트에 고유 번호를

붙여 보기로 한다. 바이트 단위의 bl 레지스터에는 8 비트 즉 8 자리의 2진수가 들어가며,

비트 단위의 플래그에는 1 비트 즉 1 자리의 2진수가 들어갈 수 있다.

다음의 그림은 AAh(10101010b)의 왼쪽 비트 회전을 알기 쉽게 보여준다.


    1  0  1  0

     1  0  1  0

     <----+

     (8)  (7)  (6)  (5)  (4)  (3)  (2)

     (1)  |

    |  0

    +---------------------------------------> (9)


일단 비트 회전이 시작되면 본래의 수 10101010b가 어떤 다른 수로 변하게 되지만,

(9) 자리에 있던 캐리 플래그의 원래 값이 첫 이동에서 (1)의 자리로 가는 것으로부터

시작하여 9 번 이동하면 원래의 자리 (9)로 되돌아 오게 된다.

따라서 바이트 단위의 작업에서 비트 회전이 9 번 실행되면, 레지스터에는 원래의

수가 다시 들어 앉게 되어 있는 법이다.

워드 단위의 작업에서는 비트 회전을 17 번 하면 원래 값이 회복된다.

비트 단위의 이동을 비트 회전(rotation)이라고 부르는 이유는 이동으로 레지스터에서

밀려나 캐리 플래그에 저장되었던 1비트 값이 다음 이동시에 꼬리를 물고 레지스터로

다시 들어오면서 원형의 구조를 만들기 때문이다.




4.  비트 회전 실습

이진수 10101010을 1비트씩 왼쪽으로 이동(회전)시킨다면, 차례로 1, 0, 1, 0,

1, 0, 1, 0 등이 캐리 플래그에 저장되어 cy, nc, cy, nc, cy, nc, cy, nc로 변하게

될 것이다. 그 사실을 직접 확인해 보기로 하자.

2진수로 10101010b는 16진수로 AAh가 된다.

먼저 디버그를 실행하고 bx 레지스터에 AAh를 입력해 보자.


     ...> debug <Enter>

     - r bx <Enter>

     BX 0000

     : aa <Enter>

     -


디버그상에서 우리가 입력하는 수는 16진수이지만, 디버그는 그것을 2진수로 번역하여

컴퓨터에게 알려 준다.

따라서 실제로는 bl 레지스터에 10101010b가 저장되어 있는 것이다.

바이트 또는 워드 단위의 어떤 수를 1비트씩 왼쪽으로 회전시키려면 왼쪽 캐리

회전(rotate carry left)이라는 뜻의 rcl 명령을 사용하면 된다.

이제 bl 레지스터에 저장된 수를 1비트씩 왼쪽으로 회전시켜 보자.


     - a 100 <Enter>

     ????:0100rcl bl,

    1<Enter>

     ????:0102 <Enter>

     -


이제 필요한 준비는 끝났다. 그러나, 실행을 할 때 약간의 주의가 필요하다.

우리는 어디까지나 이 명령을 한 번만 실행하고 나서는 즉시 ip 레지스터를 100h로

되돌려 두고 또 실행하는 식으로 진행해야 되기 때문이다.


     - t <Enter>

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

     .................................  CY

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

     - r ip <Enter>

     ip 0102

     : 100 <Enter>

     -





캐리 플래그가 cy로 변해 있음을 확인할 수 있다.

10101010b를 왼쪽으로 1 비트 이동(회전)한 결과 가장 왼쪽에 있던 숫자 1이 캐리

플래그로 저장되었기 때문에 캐리 플래그가 설정 상태로 변한 것이다. 물론 bl 레지스터의

값도 변하게 된다.  직접 실행하여 확인해 보기 바란다.

t<Enter>, rip<Enter>, 100<Enter> 명령을 반복하면서 bl 레지스터와

캐리 플래그의 변화를 그때마다 확인해 보면 될 것이다.



     ## 필자통신


사실 이 정도는 간단한 일이지만, 일반적으로 동일한 명령을 기계적으로 반복해야

된다면 짜증이 나게 마련이다. 그러면 대책을 세우자.


우리가 실수로 g 명령을 사용하지 않고 항상 t 명령만 사용한다면 극히 유치하지만

jmp 명령을 사용해서 쉽게 진행해 볼 수도 있다.


    ...>debug <Enter>

    - a <Enter>

    ????:0100 mov bl,aa <Enter>

    ????:0102 rcl,1 <Enter>

    ????:0104 jmp 0102 <Enter>

    ????:0106 <Enter>

    - t<Enter>

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


이제 t<Enter>만 차례로 누르면서 bl 레지스터와 캐리 플래그의 변화를

보라.

bl 레지스터의 변화는 2진수가 아니고 16진수로 보기 때문에 대단히 불규칙하게

변하는 모습을 보겠지만, 캐리 플래그는 2번씩 NC, CY가 교대로 나타난다.

만약 t 대신 g 명령을 했다면 무한 루프에 빠져 부팅을 다시 해야 된다.




습작을 위하여 loop 명령을 사용한 어셈블을 해 보자.


    - rip <Enter>

    IP ????

    : 100 <Enter>

    - a 100<Enter>

    ????:0100 mov bl,aa <Enter>

    ????:0102 mov cx,9 <Enter>

    ????:0105 rcl bl,1 <Enter>

    ????:0107 loop 0105 <Enter>

    ????:0109 int 20 <Enter>

    ????:010B <Enter>

    -


이 프로그램에서는 회수를 계산하기 위해 cx 레지스터에 먼저 0009를 저장해 두고

그 회수만큼 rcl 명령을 반복 실행하기 위해 loop 명령을 사용하였다.

앞에서와 같이 t<Enter>를 한 번씩 누르면서 그 때마다 나타나는 레지스터

상태 보고를 유심히 살펴 보면, bl, cx 레지스터와 캐리 플래그가 함께 변할 것이다.

캐리 플래그와 bl 레지스터의 변화는 앞에서 설명한 것과 같다.

그리고 cx 레지스터는 실행이 한 차례 거듭될 때마다 8, 7, 6, ... 차례로 1씩

줄어드는 사실을 확인할 수 있을 것이다.

서너 차례 반복 실행한 후에는 bl, cx 레지스터와 캐리 플래그의 변화에는 더

이상 눈길을 줄 가치를 느끼지 못하게 된다.

이제부터 t<Enter>를 계속하면서 나타나는 상태 보고의 끝줄을 주시하면서

다음에 실행될 명령으로 int 20이 나올 때까지만 진행하자.

다음에 int 20이 실행될 것이라는 보고를 받았는가?

그러면 딱 한 번만 더 t<Enter>를 눌러 주자.

이제 그만, 손가락을 키보드로부터 멀리 하고 다음 명령 내용과 그 명령이 저장되어

있는 메모리의 <세그먼트:오프셋> 번지를 확인해 보자.

엉뚱한 번지의 엉뚱한 명령이 나타나 있을 것이다.



     ## 주의


int 20 명령을 만나면 t<Enter>로 실행하지 말아야 된다.




왜 그런지를 알려면 아마 우리가 상당한 경지에 있어야 될 것이다.

그런 골치 아픈 문제는 접어 두고, 윈래 우리가 출발한 자리로 돌아가 보자.


    - rcs <Enter>

    CS #### * 엉뚱하게

    나타난 세그먼트 번지 *

    : ???? <Enter>* 이전에 우리가 살았던 세그먼트 번지

    *

    - rip <Enter>

    IP @@@@ * 엉뚱하게

    나타난 오프셋 번지 *

    : 100 <Enter>

    -


지긋지긋해서 다시 실행해 볼 마음이 없다면, 세그먼트와 오프셋을 원상으로 복구해

줄 필요도 없이 q<Enter>로 디버그를 끝내면 그만이다.

그러나, 약간의 인내를 가지고 지금까지 배운 내용의 복습을 겸하여 세그먼트와

오프셋을 복구하는 연습을 한 번 해 보고 끝내는 일도 유익할 것이다.

<세그먼트:오프셋> 번지를 복구했다면 이번에는 g 명령을 실행해 보자.


    - g <Enter>


    Program terminated normally

    -


간편하기는 하지만 과정의 변화를 하나도 확인할 수 없어서 유감이다.

레지스터(r) 명령을 해 보면 IP=0100으로 복구되어 있을 것이다.



     ## 필자통신


다 아는 사실을 두 번 세 번 반복해서 언급하므로 지루할지도 모른다. 그러나

어떤 사람에게는 그런 설명이 빠지면 어렵게 느껴질 수도 있으며 또 약간의 반복

설명은 학습 진도의 지름길이 될 수도 있다.


계속해서 t<Enter>를 몇 번 실행하여 캐리 플래그의 변화를 다시 음미하다가

이제 보기 싫으면 오프셋을 확인할 필요도 없이 g<Enter>를 눌러 보라.

역시 Program terminated normally라는 보고를 받게 될 것이다.

우리가 100번지 또는 이 프로그램이 실행되던 중간의 어느 번지에서라도 안심하고

g<Enter>로 명령할 수 있는 이유는 int 20h 명령이라는 방패막이가 있기 때문이다.

이 정도로 비트 회전 실습을 마치기로 하자.




5.  오른쪽 비트 회전

이론적으로 생각하면 레지스터와 캐리 플래그가 컨베이어 벨트와 같이 비트 단위의

숫자를 회전시킬 수 있는 순환 구조로 연결되어 있는 셈이다.

따라서 왼쪽 회전이 가능하면 오른쪽 회전도 가능할 것이다.

실제로 오른쪽으로 비트 회전을 시키려면 shr 명령을 사용하면 된다.

그 명령은 나중에 필요할 때 사용하면서 알아 보기로 하자.

ID:
PW:

     0 분
     4 분

자유게시판

건강백과 HOME

홈페이지 HOME

조   약     HOME

생활지혜 HOME

서식양식 HOME

법원 전산양식 검색

In Na zum

비공개 HOME

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

◁ 2002.9.1.~2021.4.11. ▷

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