티스토리 뷰

[전광성의 어셈블리어 이해하기:3회] 어셈블리언어 기초 (3)
저자: 전광성 |  날짜: 2005년 01월 04일  

/
1 .0 어셈블리언어 기초 (1)
2 .0 어셈블리언어 기초 (2)
0 어셈블리언어 기초 (3)
/
  • DUP 연산자

    연속된 여러 값들을 한꺼번에 초기화할 수 있게 해주는 연산자이다. 아까 한 데이터 레이블에 뒤이어 연속적으로 자료를 정의했던 것을 상기시켜보라. 만약 연속된 자료가 1000개 필요하다면 0을 1000개 써야 하므로 매우 귀찮을 것이다. 하지만 DUP연산자를 사용한다면 다음과같이 쓸 수 있다.

    BYTE 1000 DUP(0) ; 20 bytes, 모두 다 0이다. BYTE 4 DUP("ABC") ; 12 bytes: "ABCABCABCABC" 위와 같이 사용한다. DUP앞에 쓰는 숫자는 '몇개'를 복사할 것인지 이고, 괄호 안의 숫자는 초기값이다. '괄호 안의 것'이 DUP앞에 써있는 '숫자' 만큼 복사된다. 쉽게 말해서 어셈블리어가 코드를 복사해 준다고 생각하면 쉬울 것이다.

  • 리틀엔디안 오더(Little Endian Order)

    위의 용어는 메모리에 각 바이트가 저장되는 순서를 의미한다. 앞장에서 우리는 데이터를 비트를 쭉 늘어놓았을 때, 맨 왼쪽이 최상위비트, 맨 오른쪽이 최하위비트라고 배웠다. 마찬가지로 16비트, 즉 2바이트를 늘어놓았을 때에도 왼쪽에 있는 바이트는 상위 바이트, 오른쪽에 있는 바이트는 하위 바이트라고 할 수 있다.

    리틀 엔디안 오더는 "하위 바이트가 하위 주소에 저장되는 방식"이다. 주소에 상위와 하위가 있다고? 상위라는 것은 단지 메모리 주소를 나타내는 숫자가 크다는 뜻이므로 헷갈리지 않기 바란다. 다음 그림을 참고하면 더욱 이해하기 쉬울 것이다.

    <그림 1 : 리틀 엔디안 오더 / 빅 엔디안 오더>

    왼쪽이 리틀 엔디안 오더이고, 오른쪽이 빅 엔디안 오더이다. 빅 엔디안 오더란, 리틀 엔디안 오더의 반대 개념으로서 "하위 바이트가 상위 주소에 저장되는 방식"이다. IA-32는 리틀 엔디안 오더를 사용하고 있다. 단, 레지스터 메모리에는 적용되지 않는 개념이니 주의하기 바란다.

  • 등호 디렉티브(Equal-Sign Directive)

    C언어에서 #define을 쓰는 것과 같은 효과를 낸다. 다음을 보아라. COUNT = 500 mov al, COUNT COUNT = 500이라는 것은 앞으로 COUNT라고 쓰면 그것이 500과 같은 효과를 낸다는 뜻이다. C언어에서 #define COUNT 500 라고 쓴 것과 같은 효과를 낸다. mov라는 인스트럭션은 나중에 배우게 될 것이지만 간단히 설명하면, C에서 대입연산자와 같다고 보면 된다. C언어에서 al = COUNT; 라고 쓴것과 비슷하다. 자료를 전송(move)하는 것인데, al레지스터에 COUNT에 해당되는 값을 넣게 될 것이다.

  • 간단한 예제 - 세 수를 더하는 프로그램
    TITLE Add and Subtract (AddSub.asm) ; This program adds and subtracts 32-bit integers. INCLUDE Irvine32.inc .data val1 DWORD 10000h val2 DWORD 40000h val3 DWORD 20000h finalVal DWORD ? .code main PROC mov eax,val1 ; EAX = 10000h add eax,val2 ; EAX = 50000h sub eax,val3 ; EAX = 30000h mov finalVal, eax ; 결과를 finalVal에 저장한다.(30000h) call DumpRegs exit main ENDP END main

  • 출력화면
    <그림 2 : 출력화면>

  • 분석

    위의 프로그램이 하는 일은 우선 eax에 10000h(16진수로 10000)을 넣고, eax에 들어있는 값에 40000h를 더한 후 20000h를 빼는 것이다. 그리고 나서 레지스터 메모리에 있는 내용을 화면에 출력시킨 후 프로그램을 종료한다. 한줄한줄 천천히 보자.

    먼저, 맨 위에 TITLE부터 설명하겠다. TITLE은 디렉티브이며, 큰 의미는 없고, 단지 이름이 타이틀이기 때문에 소스코드에는 아무런 영향을 안미치며, 해당 줄에 쓰는 것들(Add and Subtract....)은 모두 주석처리가 되는 것이다. 있어도 되고 없어도 되는 부분이지만 만약 없다면 프로그램을 읽기가 매우 힘들 것이다.

    다음은 ;로 시작하는 부분인데 지난번에 주석이라고 배웠다.
    INCLUDE Irvine32.inc은 C에 비유하자면 #include <irvine32.inc>와 같다. 필자가 참고도서로 언급한 책에서 제공되는 라이브러리를 사용하기 위해서는 이와같이 써야한다. 또한 링크 할 때도 irvine32.lib를 붙여주어야 한다. 혹시 필요한 독자가 있다면 deltakam@hanmail.net로 연락주기 바란다. 필요한 라이브러리와 어셈블러를 보내드리겠다.

    .data라는 부분이 나오는데, .data는 데이터 세그먼트의 시작 부분을 나타내는 디렉티브이다. 본 프로그램이 실행될 때 메모리의 데이터 영역에 올라가게 될 내용을 이곳에 적게 된다. 본 예제에서는 네가지 DWORD(더블워드)의 변수를 정의하여 놓았다.

    .code라는 부분역시 디렉티브이고, 코드 세그먼트의 시작 부분을 나타낸다. 본 프로그램이 실행될 때 메모리의 코드 영역에 올라가게 될 내용을 이곳에 적으며, 실질적인 프로그램 제어 등이 이곳에서 이루어진다.
    main PROC라는 것은 이름이 main인 프로시져의 정의가 이곳부터 작성될 것이라는 것을 알린다. C에서 함수의 헤더를 정의 앞에 적어주는 것에 비유해서 이해할 수 있다.

    mov는 아까도 잠깐 설명했지만, 왼쪽에 있는 변수에 오른쪽에 있는 값을 저장하라는 인스트럭션이다. 코드의 첫 문장이 지났다면 이제 주석에서 보이는 대로 EAX에 10000h가 들어가게 될 것이다.

    add는 왼쪽에 있는 변수의 값에 오른쪽에 있는 변수의 값을 더하라는 뜻이다. sub또한 마찬가지이다.

    call DumpRegs는 irvine32라이브러리에 포함되어있는 프로시져 DumpRegs를 호출하는 것이다. 역할은 레지스터 메모리에 있는 내용을 화면에 출력시켜준다.

    main ENDP는 이름이 main인 프로시져의 정의가 이곳까지라는 것을 나타낸다.
    자세한 것은 나중에 다시 설명해 줄테니 일단은 이렇게 생긴 것이라고 이해를 해두기 바란다.

  • 마치는 글

    이번 회에서는 자세히 알지는 못하더라도, 개략적으로 어셈블리어가 어떻게 이루어져 있는지를 공부해 보았다. 디테일한 부분이 집착하지 않길 바라며, 혹시 레지스터 메모리가 헷갈린다 싶으면, 지난회를 다시 보기 바란다. 다음 회에서는 본격적으로 하나하나 인스트럭션과 유용한 디렉티브를 공부해 볼 것이다. 고급언어와의 연계를 생각하면서 강좌를 읽는다면 흥미를 유발할 수 있을 것이다. 그럼 다음 회에 건강한 모습으로 다시 뵐수 있길 빈다.


  • 댓글
    안내
    궁금한 점을 댓글로 남겨주시면 답변해 드립니다.