IT_Programming/Assembly

[전광성의 어셈블리어 이해하기] 어셈블리어를 배우기 위한 기본개념

JJun ™ 2007. 7. 2. 10:27
LONG

 

  • 이진수로 나타낸 부호없는 정수

    자, 이제 이진수를 이용하여 자료를 표현해 보자. 우선은 제일 쉽고 간단하면서도 흔한 부호없는 정수에 대해 생각해보자. 부호없다는 것은 ‘음이 아닌 정수’라는 뜻이다. 그럼 음수는?... 다음 단락에서 다룰 것이니 걱정마라.

    우선은 2진수를 어떻게 10진수로 변환하는지 알아보자. ㅁㅁㅁㅁ ㅁㅁㅁㅁ 이렇게 8비트의 이진수가 있다고 하자. 아까 비트에 번호붙였던 것이 기억나는가? 8비트니까 맨 왼쪽이 비트7, 맨 오른쪽이 비트 0이다. 10진수로 변환하려면

        비트7 * (2의7승) + 비트6 * (2의 6승) + 비트5 * (2의 5승) +
           비트6 * (2의 6승) + ... + 비트1 * (2의 1승) + 비트0 * (2의 0승)

    이렇게 하면 된다. 그런데 가만보자... 비트0이든 비트1이든 한 비트는 0 아니면 1이다. 그럼 조금 바꿔서 생각하면... 비트가 1인 자리수만 더해주면 된다. 0은 뭘 곱해도 0이 될테니까 덧셈에 아무런 도움을 주지 않을 것이다. 그렇다면 아예 (2의 □승)에 대한 표를 만들고 그것을 보고 변환하는 게 편할 것이다. 하지만 굳이 표를 그리진 않겠다. 왜냐하면 별 쓸모가 없기 때문이다.

    2진수는 너무 공간을 많이 차지해서 대부분 16진수로 변환해서 사용한다. 16진수는 또 무엇일까? 후에 설명하도록 하겠다. 일단은 진법을 변환하는 개념에 대해서만 알면 된다.

    이번엔 역으로 10진수를 2진수로 변환하는 방법을 알아보겠다. 방법을 직접 설명하기엔 너무 비효율적이므로 하나의 예를 들겠다. 37을 2진수로 표현해 보자.

    나눗셈 나머지
    37 / 2 18 1
    18 / 2 9 0
    9 / 2 4 1
    4 / 2 2 0
    2 / 2 1 0
    1 / 2 0 1
    <표 2 : 10진수를 2진수로 변환하기>

    위에서부터 한줄씩 내려가며 계산한 것이다. 한번 계산했을 때의 몫이 다음 계산에서 이용된다. 몫이 0이 될때까지 반복한 후, 나머지를 맨 아랫줄에서부터 맨 위로 읽으면 된다. 따라서 100101(2) 가 된다. (뒤에 (2)는 이진수라는 뜻이다.)

    다음은 저장 크기다. 저장크기라고? 몇 자리, 즉 몇 비트로 숫자를 표현하느냐에 따라 얼마나 큰 숫자를 저장할 수 있는지가 달라질 것이다. 당연히 많은 자릿수, 즉 많은 비트로 숫자를 표현하면 더 큰 숫자를 표현할 수 있다. 인텔 CPU에서 사용할 수 있는 부호없는 정수의 저장 크기는 다음 그림과 표에 정리해 놓았다.


    <그림 1 : 데이터형과 그 크기>

    저장 종류(Type) 사용하는 비트수 범위
    Unsigned byte
    8
    0~(2의8승 - 1)
    Unsigned word
    16
    0~(2의 16승 - 1)
    Unsigned doubleword
    32
    0~(2의 32승 - 1)
    Unsigned quadword
    64
    0~(2의 64승 - 1)
    <표 3 : 데이터형과 범위>

    조금 센스있는 분이라면, [2의 (사용하는 비트수)승] - 1은 해당 범위의 최대값이라는 것을 발견할 수 있을 것이다. 뒤에 왜 1을 빼는지는 범위가 0부터 시작한다는 데서 찾을 수 있을 것이다. 또 8비트가 1바이트라고 표에 나와 있으므로, 2바이트는 워드, 4바이트는 더블워드, 8바이트는 쿼드워드라는 것을 눈치채야한다.

  •  

  • 16진수 정수

    아까 알려주기로 했던 16진수에 대해 알아보자. 16진수는 0~9와 A~F까지의 16가지 문자를 이용하여 숫자를 표현하는 것이다. 각각 A는 10을, B는 11을, C는 12를, D는 13을, E는 14를, F는 15를 의미한다.

    10진수 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    16진수
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    A
    B
    C
    D
    E
    F
    <표 4 - 16진수표>

    16진수를 왜 쓰는지 생각해 보자. 대답은 간단하다. 16진수는 2진수보다 더 짧은 길이로 큰 수를 표현할 수 있기 때문이다. 그럼 왜 10진수도 11진수도 12진수도 아닌 딱 16진수일까? 그것은 바로 2의 4승이 16이기 때문이다. 이해가 가지 않는가? 그럼 다음 예를 보아라.

    A6(16진수) = 1010 0110 (2진수)

    2진수에서 가운데 공백을 넣은 것은 네글자씩 끊어서 보기 편하게 하려고 한 것이다. A는 10을 나타낸다고 아까 말했다. 2진수에서 상위 네 비트를 10진수로 바꿔보자. 10이 된다. 아까 A가 1010과 같다는 뜻이 된다.

    뭔가 눈치를 챘을 것이다. 2진수에서 네 비트는 16진수 한 자리와 대응 된다. 마찬가지로 6은 0110과 같다. 그러면 이제 16진수를 왜 쓰는지 알 수 있을 것이다. 2진수와의 변환이 간편하다는 점이다. 그냥 네 비트씩 끊어서 16진수로 바꾸면 된다. 왜 그런지는 각자 생각해 보기 바란다.

    여기서 간단한 팁 한가지를 알려 주겠다. 8421코드라는 변환 방법인데, 알고 있으면 정말 편하다. 즉 이진수 네 비트가 있다고 할 때 상위 비트부터 하위 비트까지 8421이 하나씩 대응되는 것이다. 이진수 1111은 8 + 4 + 2 + 1이다. 1001은 8 + 1이다. 8421을 언제나 머릿속에 넣어두어라. 이진수를 보고 16진수로 바꿀 때, 8421코드를 이용하여 각각의 네 비트를 10진수로 만든 후 16진수로 바꿔라. 이진수에서 16진수로 바꾸기가 편해질 것이다.

  •  

    ============================================================================================

     

  • 이진수로 나타낸 부호있는 정수

    컴퓨터는 음의 정수를 어떻게 표현하는가에 대해 알아보겠다. 컴퓨터는 -1을 만들기 위해 1에다가 2의 보수를 취한다. 2의 보수가 어떤 것인지는 다음 표를 보면 알 수 있다. 참고로 표에서 데이타의 크기는 1바이트이다. 또 비트반전은 1의 보수와 같은 말로서, 1은 0으로, 0은 1로 바꾸어주는 것을 의미한다.

    1
    0000 0001
    비트반전(1의보수)
    1111 1110
    더하기 1
    1111 1111
    결과
    1111 1111
    <표 5 : -1에 대한 2의 보수표현>

    이번엔 거꾸로 해보겠다.

    -1
    1111 1111
    비트반전(1의보수)
    0000 0000
    더하기1
    0000 0001
    결과
    0000 0001
    <표 6 : -1에 2의 보수 취하기>

    ‘비트반전후 더하기 1‘하는 것을 ’2의 보수를 취한다‘ 라고 한다. 2의 보수를 취한 후 다시 2의 보수를 취하면 자기 자신이 된다는 것을 알 수 있다.

    참고로, 최상위 비트가 1이면 음수고 0이면 양수가 된다. 즉 1111 1111은 음수고, 0111 1111은 양수이다. 2의 보수표현을 했을 때의 특징을 알아보자.

    크다
    -2
    1111 1111
    크다
     
    -3
    1111 1110
     
     
    -4
    1111 1101
     
     
    -5
    1111 1100
     
     
    -6
    1111 1011
     
     
    -7
    1111 1010
     
     
    -8
    1111 1001
     
     
    -9
    1111 1000
     
     
    -10
    1111 0111
     
    작다
    -11
    1111 0110
    작다
    <표 7 : 음수의 2의 보수표현>

    음수를 2의 보수표현으로 나타내면 숫자의 크기가 작아질수록, 실제 그 이진수의 크기는 작아짐을 알 수 있다. 따라서 이대로 가면 -128은 1000 0000이 될 것이라고 예측할 수 있다. 그것보다 한 숫자 작아지면 0111 1111이 되고, 이는 1바이트로 표현할 수 있는 최대값이 된다.

    저장 종류(Type) 사용하는 비트수 범위
    byte
    8
    -(2의 7승) ~ 2의 7승
    word
    16
    -(2의 15승) ~ 2의 15승
    doubleword
    32
    -(2의 31승) ~ 2의 31승 - 1
    quadword
    64
    -(2의 63승) ~ 2의 63승 - 1
    <표 8 : 데이터형과 범위>

    상식적으로, 최상위비트로는 부호부분을 나타내고 나머지 비트들로 숫자부분을 나타내는 것이 편하다고 생각할 수도 있다. 하지만, 위의 표를 보라. 2의 보수표현을 하면 음수에서 대소관계가 그대로 지켜진다. 2의 보수표현이 좋은 이유가 한 가지 더 있는데 이는 다음에서 알아본다.

  •  

  • 정수의 뺄셈

    컴퓨터는 ‘뺄셈’은 할 줄 모른다. 그럼 뺄셈을 어떻게 할까? 바로 앞에서 배운 2의 보수를 취하는 방법을 이용한다. 컴퓨터가 A-B를 계산해야 한다고 하자. 그러면 컴퓨터는 A + (-B)를 한다. 여기서 B에 -부호를 붙인다는 것은 2의 보수를 취한다는 것이다. 2의 보수표현방법의 강력한 장점중의 하나는 이 뺄셈에서 드러난다. A + (-B)로 함으로써 빼기 연산을 따로 만들 필요 없이, 음수표현 방법을 그대로 이용하여 계산할 수 있다는 것이다. 예를 들어보겠다.

    	a.		4		0000 0100
    	b.		1		0000 0001
    	c.		-1		1111 1111
    	a+c		3		0000 0011
    

    보다시피 a - b는 a + c와 같다. 마지막 단계에서 8비트를 넘어선 비트8(왼쪽에서부터 9번째 비트)에 넘어간 숫자는 어디갔을까? 컴퓨터는 지금 8비트(1바이트)형의 데이터에 대해 연산을 하고 있으므로, 이 범위를 벗어난 것은 그냥 버린다.

  •  

  • 문자의 표현

    컴퓨터는 0과 1밖에 모른다. 그런데 어떻게 문자를 표현할까? 문자를 표현하기 위해 아스키(ASCII)코드라는 것이 정의 되어있다. 128가지를 표현할 수 있으며, 각 코드는 숫자와 문자를 일대일 대응 시켜놓았다. 따라서 48에 대응되는 문자를 출력하라고 하면 미리 대응시켜놓았던 그 문자가 표시되도록 하는 방식으로 문자를 처리한다.

    표현 방법이 어떻든 간에 컴퓨터는 숫자로 이루어져 있다는 사실을 명심하라. 우리 눈에 보이는 a는 눈에만 문자로 보이지 사실은 65라는 숫자값이다. 다음은 자주쓰는 문자에 대한 아스키 코드값이다.

    문자 아스키코드값
    0
    48
    9
    57
    A
    65
    Z
    90
    a
    97
    z
    122
    <표 9 : 주요문자의 아스키코드값>

    0~9, A~Z, a~z은 각각 오름차순으로 아스키코드에 들어가 있다. 따라서 문자의 대소를 비교할 때(예를 들면, 오름차순 정렬) 이에 대응하는 아스키 코드 값으로 대소를 비교할 수 있다.

  •  

  • 이진 연산

    컴퓨터를 아무리 깊이 모른다고 해도 이진 연산 쯤은 알고 있을 것이다. 수학에서도 가장 기초적인 개념으로 나오니 말이다. 이진수에 대한 AND, OR, NOT연산에 대해서는 간단히 표를 보여주고 넘어가겠다. 여기서 F는 false(거짓, 0)을 의미하고 T는 true(참, 1)을 의미한다. X, Y는 이진 변수로서 1 또는 0의 값을 가질 수 있다.

    X Y X AND Y X OR Y NOT X NOT Y
    T
    T
    T
    T
    F
    F
    T
    F
    F
    T
    F
    T
    F
    T
    F
    T
    T
    F
    F
    F
    F
    F
    T
    T
    <표 10 : 이진연산표>

  • 마치는 글

    이번 회에서는 어셈블리어를 배우는데 있어 필수적인 기본 컴퓨터 '상식'들에 대해 공부해 보았다. 상식이라고 해서 크게 부담 가질 것 없다. 모를때 자꾸자꾸 다시 보다 보면 어느새 내 것이 되어있을테니까. 다음시간에는 CPU와 관련된 내용을 알아볼 것이다. 어셈블리어가 어떻게 CPU에 직접 접근하는지, 다음 강좌를 통해 알아보도록 하자!!

  • ARTICLE
  • 시작하기에 앞서...

    어셈블리어는 저급언어다. 원론적으로 이야기 하자면, 사람보다는 기계에 더 친한 언어이다. 이 언어는 대부분 하드웨어에 직접 명령을 내리는 형식을 갖추고 있고, 고급언어에서 신경 쓰지 않아도 되었던 것들에 대해서 일일이 신경 써 주어야 한다. 그렇기 때문에 기본 개념이 필요하다.

    중학생 시절, 내가 C언어 책을 사서 공부하는 것을 보고 나의 친형이 경쟁심에 더 어려운 것을 해보겠다며 어셈블리어 책을 샀던 것이 기억난다. 형은 앞에만 조금 읽다가 재미없다고 책을 덮어버린 적이 있었다. 어셈블리어를 제대로 배워보겠다는 생각은 가져보았으나, 재미가 없어서 포기하는 경우가 많다.

    어셈블리어를 배우다가 가장 장애가 되는 것은 ‘이런 것을 내가 왜 배울까?’ 하는 생각일 것이다. 어셈블리어를 배운다는 것은 단지 언어를 배울 뿐만 아니라, 기초적인 컴퓨터 구조의 원리를 익히는 과정이다. 정 지루하다면, 다른 프로그래밍 언어를 어셈블리어로 구현할 때 어떻게 해야 할지 상상해 가며 강좌를 읽어주기 바란다. 물론 하드웨어를 하는 분이시라면 굳이 그런 의문이 없을 테지만.

    본 회에서는 매우 기본적인 개념을 다룬다. 컴퓨터관련 자격증 필기시험을 한번이라도 보았다면, 쉽게쉽게 이해할 수 있을 것이다. 그렇지 않더라도, 상식선에서 해결될 내용이니 걱정할 필요 없다. 부담없이 강좌를 봐주길 바란다.

  •  

  • 어셈블리어의 세계에 온 것을 환영합니다!

     어셈블리어란 기계어를 영문자로 치환시킨 언어이다. 예를 들어 45라는 명령이 있는데 이 명령이 숫자의 대소를 비교한다고 치자. 그렇다면 45라는 명령을 cmp와 같이 comparison의 약자로 대신 사용하는 것이다. 기본적으로 기계어는 모두 숫자이기 때문에 코드를 볼 때 이해하기도 힘들 뿐더러, 숫자로 된 그 많은 기계어들을 일일이 매뉴얼을 참고해 가며 프로그램 작성하기도 힘이 든다. 이런 불편함을 해소하고자 어셈블리어가 탄생하게 되었다.

    어셈블리어와 고급언어의 구체적인 차이는 <표1>에 설명해 놓았다.

    프로그램 고급언어 어셈블리어
    한 플랫폼에서만 돌아가는 대규모의 응용프로그램
    규모가 큰 코드를 유지 및 보수하기 좋은 구조를 갖고있다.
    코드의 유지보수가 어려운 구조를 갖고 있으며, 개발에 많은 경험을 필요로 한다.
    하드웨어 장치 드라이버
    직접적인 하드웨어 접근이 힘들다.
    하드웨어로의 접근이 직접적이고 간단하므로, 유지보수가 편하다.
    여러 플랫폼에서 작동가능한 응용프로그램
    보통 호환성이 뛰어나서, 약간의 코드 수정만으로 다른 플랫폼에 이식 가능하다.
    각각의 플랫폼마다 다른 어셈블러로, 다른 문법으로 작성해야한다.
    직접적인 하드웨어 접근이 필요한 임베디드시스템과 컴퓨터게임
    하드웨어로의 접근이 매우 느려 수행속도에 문제가 있다.
    하드웨어에 직접적인 접근을 하기 때문에 수행속도가 빠르다.
    <표 1 : 어셈블리어와 고급언어의 차이점>

    위의 내용이 이해가 가지 않더라도 겁먹을 필요 없다. 필자가 C언어를 배울 때 포인터에서 막혀 책을 덮은 것이 한두번이 아니었다. 나는 포인터를 왜 쓰는지 너무나 궁금해서 게시판 여기저기를 돌아다니며 질문을 해보고 당시 나우누리에서 강좌를 쓰시던 분에게도 메일을 보내 봤지만 통쾌한 대답을 얻을 수 없었다. 그러다가 포기하는 심정으로 포인터 뒷부분으로 계속 진도를 나가다 보니 왜 쓰는지는 물론 어떻게 활용해야 할지도 알 수 있었다.

    공부를 하다가 중간에 모르는 것이 생기면 일단은 그곳에 물음표를 달아놓고 지나가면 된다. 더 진도를 나간 후 다시 보면 이해할 수 있는 경우가 대부분이기 때문이다.

  •  

  • 자료 표현 방법

    컴퓨터는 자료를 어떻게 표현할까? 우선 자료가 무엇인지 생각해 보자. 자료는 컴퓨터로 우리가 정보를 활용하기 위한 값이다. 이것은 어떤 수치값이 될 수도 있고, 숫자가 될 수도 있다. 이러한 자료중 연관된 것을 일정 형식으로 잘 모아서 놓는다면 그림에 대한 정보를 가질 수 있고, 한 학생에 대한 정보를 가질 수도 있다. 또, 어떤 3D객체를 나타내기위해 필요한 정보를 가질 수도 있을 것이다. 정보이기 이전에 자료가 있다. 이제 이 자료를 컴퓨터에서 어떻게 표현하는지 알아보자.

    컴퓨터가 자료를 어떻게 표현하는지를 알려면 우선 이진수를 빼놓을 수가 없다. ‘컴퓨터는 0과 1밖에 모른다’라는 말은 한번 쯤 들어 보았을 것이다. 그렇다. 정말로 컴퓨터는 0과 1밖에 모른다. 우리가 고급언어로 프로그래밍 할 때는 컴퓨터가 0과 1밖에 모른다는 것이 그다지 와 닿지 않을 수도 있다. 대부분의 고급 언어는 이진 연산은 제공해도, 이진수를 직접 상수로 사용할 수 없다.

    하지만 어셈블리어는 이진수를 직접적으로 제어할 수 있고, 이진수를 직접 상수로 사용할 수 있다. 그만큼 다른 언어보다 이진수를 가까이 하고, 이진수 차원의 제어를 필요로 하는 언어가 어셈블리어이다.

    10진수는 0~9까지의 열 가지 숫자를 이용하여 숫자를 표현한다. 반면 이진수는 0~1까지의 두 가지 숫자만을 이용하여 숫자를 표현하는 것이다. 이진수의 한 예를 보여주겠다.

     (15)            (0)
       1011001010011100 

    위에 괄호로 쓴 숫자는 무엇일까? 각각의 숫자에 번호를 매긴 것이다. 그 각각의 숫자 하나를 ‘비트(bit)'라고 한다. 위에 있는 이진수는 몇자리 숫자일까? 그렇다. 16자리 숫자이다. 그렇기 때문에 위의 이진수를 컴퓨터로 표현할 때는 16bit라고 한다. 16자리니까 16비트인 것이다.

    비트에 숫자를 매긴 것을 다시 보자. 15는 맨 왼쪽, 그러니까 제일 높은 자리수를 나타내고 ’비트15‘라고 부른다. 또 이 숫자에서 제일 높은 자리 숫자이기 때문에 '최상위 비트' (MSB: Most Significant Bit)라고 한다. 한글로 하면 ’최상위 비트‘이다. 0은 맨 오른쪽의, 그러니까 제일 낮은 자리수를 나타내고 ’비트0‘이라고 부른다. 또 이 숫자에서 제일 낮은 자리 숫자이기 때문에 '최하위 비트' (LSB: Least Significant Bit)라고 한다. 한글로 하면 ’최하위 비트‘이다.

    갑자기 많은 개념이 들어가서 헷갈리는가? 걱정말기 바란다. 나중에 나오면 다시 설명해 줄 것이다.

  •