태초의 프로그래밍 언어 어셈블리

assembly, 8086, x86

메모리 읽고 쓰기

데이터를 레지스터에 넣어봤습니다. 그런데 데이터가 여러개라면 어떻게 해야될까요? 주소록을 만들거나 수백명 학생들의 학점 관리를 해야하는데 몇개뿐인 레지스터를 가지고 처리할 수 없겠지요. 그래서 메모리에 데이터를 쓰고 읽고 해야합니다.

보통의 프로그래밍 언어에서는 변수를 하나의 이름으로 생각합니다. C에서는 int a; 와 같이 a라는 이름으로 변수를 지정합니다. 그런데 컴퓨터에게는 변수란게 없습니다. 변수는 사람이 기억하기 쉽도록 이름을 지어놓은 것입니다. 변수란 사실은 메모리의 특정한 위치를 말합니다. C에서는 포인터라는 개념을 배우는데요 이게 메모리 주소를 말합니다. 어셈블리 언어에서는 변수없이 포인터로만 데이터를 사용할 수 있어야합니다. 어셈블러에서는 변수 이름을 만들 수 있도록 해주는데 사실은 눈속임입니다. 그냥 특정 메모리 주소를 변수 이름으로 바꿀 뿐입니다. 

다시한번 말씀드리겠습니다. 변수는 눈속임입니다. 컴퓨터는 이름을 모릅니다. a가 뭔지 모릅니다. 컴퓨터가 이해할 수 있는 것은 주소입니다. 주소는 숫자이니까 이해할 수 있습니다. (왜 수가 첫번째 글이 되었는지 납득이 되시나요? 모든게 수입니다!!)

실습을 해볼까요? 쓸데없이 복잡합니다만 다 이해가 안되도 상관없습니다. 메모리 주소를 표현하는 방법만 생각하세요.

org 100h
mov ax, 0b800h
mov ds, ax
mov cl, 'A'
mov ch, 11011111b
mov bx, 15eh
mov [bx], cx
ret

 

메모장을 실행해서 이 코드를 입력하고 var.txt 라는 이름으로 저장한 후 emu8086.exe var.txt를 실행합니다.

그리고 에물레이터 화면의 밑부분에 있는 screen이라는 버튼을 누릅니다. 그럼 빈 화면의 윈도우가 나타나지요. 그리고 single step 버튼으로 프로그램을 ret까지 실행해봅니다. screen 화면에 A라는 핑크색 글자가 나타났나요?

소스를 설명하겠습니다.

처음에 org 100h는 죄송하지만 설명하지 않겠습니다. org 100h은 그냥 프로그램 처음에 무조건 넣는 걸로 하겠습니다. 굳이 간단하게 설명하자면 에물레이터를 처음 실행하면 ip가 100h인데 그렇게 프로그램이 100h 위치에서 실행한다는 것을 의미합니다. 왜 100h가 필요한지 왜 다른 값이 아니라 100h인지 등등 설명할게 많은데 사실 알아도 지금은 전혀 쓸모없는 지식입니다. 8086에서만 해당되는 내용이고 요즘 프로세서와는 상관없는 내용이므로 그냥 그렇게 쓰겠습니다.

그 다음이 0b800h라는 주소를 ds에 저장합니다. 0b800h라는 값을 곧바로 ds 레지스터같은 세그먼트 레지스터에 곧바로 저장할 수는 없습니다. 8086 프로세서의 하드웨어적인 제약사항입니다. 그냥 프로세서가 그렇게 못하도록 만들어진 것입니다. 그래서 값을 바로 쓸 수 있는 범용 레지스터에 먼저 저장한 후에 레지스터의 값을 ds에 복사한 것입니다.

그리고 ds가 또 나타나는 지점은 mov ds:[bx], cx입니다. 여기의 ds:[bx]라는 표현이 바로 메모리의 위치를 나타내는 표현입니다. 이전 글에서 메모리 주소는 세그먼트 주소와 범용 레지스터를 결합해서 나타낸다고 말씀드렸습니다. ds에는 0b800h 값이 있고 bx에는 15eh 값이 있으므로 ds:[bx]는 0b8000h + 15eh라는 주소를 말합니다. 그럼 [] 표시는 뭘까요? mov bx, cx는 bx 레지스터에 cx레지스터의 값을 복사하라는 명령입니다. bx에 메모리 주소가 있고 bx에 저장된 메모리 위치에 cx 값을 넣으라는 명령을 내리고 싶을 때는 bx에 []를 붙입니다. 그래서 결국 mov [bx], cx 혹은 mov ds:[bx], cx 가 됩니다. ds는 생략이 가능합니다. 프로세서가 알아서 메모리 주소를 계산할 때 ds를 읽습니다.(주1) mov [bx], cx로 바꿔서 실행해보세요. 결과는 같습니다.

그리고 cl에 'A'를 씁니다. 이건 화면에 출력할 문자입니다. '1'을 써도 되고 'a'를 써도 됩니다. 작은 따옴표는 그 문자의 아스키코드를 말하는데 아스키코드라는 것을 아신다면 이해하시면 되고 아니라면 그냥 'A'는 A라는 문자 자체를 의미한다고 생각하시면 됩니다.

ch에는 이상한 값을 쓰는데 이것은 그냥 바탕은 핑크색 글자는 흰색이라는 것을 의미합니다.

bx는 화면에서 어느 위치를 말합니다. 혹시 옛날 386AT 컴퓨터가 기억나시나요? 흑백 화면이나 녹색 화면일때도 있었고 브라운관 모니터였지요. 그때 화면은 지금의 윈도우처럼 그래픽이 출력되는 화면이 아니었습니다. 가로 80글자 세로 25글자만 출력할수 있었습니다. 그게 바로 지금 보시는 screen 화면입니다. 옛날의 화면 출력을 에물레이트해준 것이지요.

옛날 화면에 하나의 문자를 출력할때는 2바이트의 값을 써야합니다. 화면 한 줄이 80개의 문자를 출력할 수 있으니까 한 줄당 160바이트입니다. 350은 몇번째 줄일까요? 첫번째 줄은 0~158, 두번째 줄은 160~318, 세번째 줄이 320~ 이므로 350이라는 값은 세번째 줄에 표시한다는 것입니다.

세번째 줄에서 몇번째 칸일까요? 350-320은 30인데 한 문자당 2바이트입니다. 30은 15번째 위치를 말합니다.

이해가 안되고 어렵다고 생각하시는게 당연합니다. 얼마나 많은 사람들이 C언어의 포인터 개념을 이해하지 못해서 컴퓨터 공학을 포기하고 전자/전기 공학으로 전공을 바꾸는지 아신다면 위안이 되실겁니다. 태어나서 이런 식으로 수학을 사용해본 일이 없으니 당연한 일입니다. 그냥 ds:[bx]만 써넣으면 재미가 없을것 같아서 스크린에 글자 출력하는 소스도 넣어봤습니다. 이해가 안되시면 그냥 넘기세요. ds:[bx]만 알면 됩니다.

우리가 여기에서 배워야할 것은 화면에 몇번째 위치냐가 아니고 메모리의 특정 위치를 지정하는 방법입니다. 다시한번 말씀드리면 ds:bx가 메모리 주소이고 레지스터 값을 읽는게 아니라 레지스터 값을 메모리 주소로 인식해서 메모리에 접근하라는 표현이 ds:[bx]입니다. 

마지막에 있는 ret 명령어는 프로그램을 끝내는 명령입니다.

 


주1: 메모리 주소가 저장된 레지스터라니 뭔가가 생각나지 않으세요? bx 레지스터가 바로 C언어에서 포인터의 역할을 하는 것입니다. 포인터는 그냥 읽으면 정수값이지요. 그런데 *를 붙이면 그 값을 메모리 주소로 인식해서 메모리에 접근하지요. C에서의 * 연산자가 어셈블리 언어에서 []가 되었습니다. 정확하게는 반대로 []가 C언어에서 *로 계승된 것입니다. 그거 아세요? C언어는 어셈블리 언어보다는 조금 쉬우면서 비슷하게 강력하고 자유로운 언어를 만들기위해서 생겨났습니다. 그래서 앞으로 어셈블리 언어를 공부하다보면 C언어가 다르게 보일 것입니다. 인간 컴파일러가 되서 C언어 코드를 보면 어떤 어셈블리 명령어에 해당되는지가 보일 것입니다. 매트릭스의 네오가 되는 것이지요.

댓글

댓글 본문
작성자
비밀번호
  1. 강우진
    mov bx, 15eh 의 경우, 16진수로 15E 값을 bx 레지스터에 복사하라는 말입니다.
    mov [bx], cx 의 경우, cx의 값을 bx에 저장된 메모리 위치에 넣으라는 말입니다.
    bx가 0x15E 위치에 있으니 그 곳에 cx 의 값을 넣으라는 말 같습니다.
    대화보기
    • gurugio
      예 주소가 15eh이고 [15eh]는 그 주소에 있는 16비트 값이 됩니다.
      대화보기
      • 음..
        그니까
        mov bx, 15eh
        mov [bx], cx
        에서 위에꺼 bx주소에 15eh대입한거에서
        bx의 값을 cx로 값으로 바꾸는건가요?
      • gurugio
        위에는 주소값이고요 아래는 그 주소에서 값을 읽으라는 의미입니다.
        대화보기
        • 궁금한게요
          mov bx, 15eh
          mov [bx], cx
          이때 왜 위에껀[]안쓰고 밑에것만 쓰나요?
        • TeacherK
          org 100h
          mov ax, 0b800h
          mov ds, ax
          mov cl, 048h
          mov ch, 01001111b
          mov bx, 160
          mov [bx], cx
          mov cl, 01000101b
          mov ch, 01001111b
          mov bx, 162
          mov [bx], cx
          add cl, 7
          add bx, 2
          mov [bx], cx
          add bx, 2
          mov [bx], cx
          add cl, 3
          add bx, 2
          mov [bx], cx
          ret
          저도 따라하긴 하는데 뭔진 잘 모르겠어요...
          ds:bx에 값을 넣으면 왜 화면에 출력되는 건지...

          열심히 따라해 보겠습니다...
        • 참치통조림
          좋은 강의 감사합니다.

          org 100h

          mov ax, 0b800h
          mov ds, ax

          mov cl, 'H'
          mov ch, 11011111b
          mov bx, 160d
          mov [bx], cx

          mov cl, 'e'
          mov bx, 162d
          mov [bx], cx

          mov cl, 'l'
          mov bx, 164d
          mov [bx], cx

          mov bx, 166d
          mov [bx], cx

          mov cl, 'o'
          mov bx, 168d
          mov [bx], cx

          mov cl, '!'
          mov bx, 170d
          mov [bx], cx

          ret
        • starlee3
          ia32 IA16 instruction set (번역판도없고 다영문이니 쩝)~!!혼자 삽질(이해)할려고하니
          microProcessor로 가네요 방향이~!!..하여튼 답변감사하고요 !! 뭐 ~같이 생각해보고 분석하는 재미죠.ㅋ

          아는사람도 별로없고 관심도 없는데 ,그래도 오픈튜도리얼에서 많이 어셈블 배우고있어서 참 좋은것같습니다. ..
        • gurugio
          제가 ia-16을 잘 몰라서 무얼 말씀하시는지는 모르겠습니다만
          ax값이 바뀌지는 않겠지요.
          ALU는 연산을 하는 유닛이니 다른 메모리관련 유닛에서
          데이터를 가지고 있다가 버스를 통해서 메모리로 전송할것 같습니다.
          대화보기
          • starlee3
            갑자기 글을 읽다고 궁금해서 질문 합니다!ㅋ

            org 100h
            mov ax,0700h
            mov ds,ax
            mov bx, 010fh


            mov word ptr [bx], 1
            ret


            위 어셈블에서


            mov word ptr [bx], 1

            기계어 코드로 하면

            C7(1100 0111) 07(00 000 111) 1(0000 0001)

            인데요

            iA-16에서보면

            07에 앞 00은 변위없는 111은 [bx] 엑세스 의미인것같은데
            중간에 000은 AX레지스터 지정 조작에 의미로 알고있습니다.

            그럼 결국 DS:[bx]값 번지에 1을 넣을경우 일단 000(AX)레지스터에 값을 쓰고 난 후에
            메모리로 넣으라는 의미인가요??



            질문에 요지는 1흐름이 CPU에서

            IR C7(1100 0111) 07(00 000 111) 1(0000 0001)
            에 있다가

            C7 07은 디코더에 들어가서 CPU에게 명령을 내리고 나머지 부분은
            ---> ALU -->AX있다가--->
            메모리값으로 입력된다는 의미인가요?

            아니면 그냥 ---> AX에 있다가 메모리로 간다는 의미인가요?
          • gurugio
            밑에 있는 변수 챕터를 읽어보시면 해결될 질문같습니다.
            한번 읽어보시고 또 질문해주세요.
            대화보기
            • starlee3
              예제를 읽고 작성해 봤슴니다!

              1)
              code segment
              assume cs:code,ds:data
              mov ax,data
              mov ds,ax

              mov bx,offset aaa


              code ends

              data segment
              aaa db ?

              data ends
              end


              2)
              code segment
              assume cs:code,ds:data
              mov ax,data
              mov ds,ax

              mov bx,offset aaa
              mov ah,'k'
              mov byte ptr [bx],ah


              code ends

              data segment
              aaa db ?

              data ends
              end

              질문1)c에서
              1)이면 전역변수 chr korea; 선언이고? 그러게 생각하면 변수 선언은 포인트 뿐 하는것 아무것도없네요.
              2)이면 전역변수 chr korea; korea='k'; 선언인가요?

              질문2) db ?는 변수에 값이 기존이 있던값들이 들어있다는 말인데
              db 어떻게 00 초기화할수없나요?? 명령어형식이.?
            • gurugio
              b800h를 표기할 때 b가 16진수의 b라는 것을 나타내기 위해 0을 붙여줘서 0b800h가 됩니다.
              0이 레지스터에 들어가는 것이 아닙니다.
              대화보기
              • starlee3
                예를 들어서 mov al,8888h 하면 오류 같은데용??
                mov ax, 0b800h 이것은 오류 아닌가요? 헛갈리네용.!?
              • gurugio
                예 실행이 된 것입니다. 그렇게 끝까지 실행된게 중요한게 아니라
                그 과정에서 레지스터 값들이 어떻게 변하는지가 중요합니다. 그게 본문 내용입니다.

                자바는 잘 모르겠습니다만 C++에서 클래스를 만들면
                클래스라는건 그냥 표현일 뿐이고 최종적으로는 변수만 남습니다.
                즉 Person per; per.a = 10; 이렇게하면 per.a라는 변수만 남는것이지
                객체라는 것은 없어집니다.
                대화보기
                • starlee3
                  Assembly코드를 복사해서 txt파일만들어 실행을 했더니

                  PROGRAM HAS RETURNED CONTROL
                  TO THE OPERATING SYSTEM

                  요렇게 나오네요 이러면 실행이 된것인가요??

                  질문2)

                  pubiic classs Person {
                  public int age;
                  public float height;
                  }
                  person abc =new person();
                  자바 클래스 문장에서

                  public int age 는
                  public float height 는

                  mov dword ptr ss:[ebp-4],0
                  mov dowrd ptr ss:[ebp-8],0 이렇게 표현되나요?

                  변수는 대충 메트릭스눈으로 보이는데, Person 클라스 는 전체 어떻게 표현되나요?
                  Person클라스는 어떻게 표현이 되는지?
                  메트릭스눈으로 안보여용~!!ㅋㅋ?
                • gurugio
                  예 전역변수를 다루는 예제입니다.
                  어떻게 실행이 안되세요? 어셈블이 안되세요? 아니면 주소값이 잘못된 건가요?
                  지금 제가 다시 실행해봐도 실행은 잘됩니다.
                  대화보기
                  • starlee3
                    예제를 복사해서 실행은 안되는데, 개념이 DS에 주소를 넣고 BX에 offset 주소를 넣고

                    DS랑 bx주소로 기반으로 연산해서 물리 번지를 생성해서 포인트하는 메모리주소에 Cx내용을 넣으라는 말인가요? C에 전역변수 개념인가요?
                  버전 관리
                  gurugio
                  현재 버전
                  선택 버전
                  graphittie 자세히 보기