-
[컴시설] 어셈자료정리필요2 2007. 10. 17. 15:43
1-4 어셈블리 언어
지 금까지 프로그래밍을 하기 위한 전반적인 기본 구조 및 운영체제에 대해서 설명했습니다. 이제 운영체제 위에서 프로그래밍을 할때 컴퓨터가 가장 이해하기 쉬운 언어에 대해서 설명하겠습니다. CPU는 메모리에 있는 실행코드 대로 연산을 하고 연산을 한 내용을 그대로 다시 메모리에 로드합니다. 실행코드는 실제로 숫자로 표시되어 있고 이 숫자에 의해서 CPU는 처리를 합니다. 우리가 원하는 실행코드를 바로 숫자코드로 만든다면 그 코드는 CPU에서 바로 실행을 시킬수가 있습니다. 그러나 사람은 숫자만 보면 머리가 아픕니다. 그래서 머리가 조금 덜 아프자라는 의미에서 숫자 대신 아주 간단한 명령어를 사용했습니다. 이것이 어셈블 입니다. 한국어로 표현하자면 기계어라고 합니다. 이 어셈블 언어를 이용하여 프로그래밍하는 것은 무엇인가를 본 항목에서 설명합니다. 어셈블언어는 사실 거히 사용하지는 않지만 그래도 어셈블이 무엇인지는 알고 나야 C언어로 넘어가는데 어려움이 없습니다. 이제 어셈블 언어에 대해서 여행을 해보겠습니다.
1-4-1 어셈블리 언어의 개요
지금 까지 CPU는 메모리에 있는 데이터를 로드하여 연산하고 다시 메모리로 이동한다고 설명하였습니다. 1-2-6 항목에서 설명한 영문 요약 문을 이곳에서 다시 이용하겠습니다.
move 5 r1
move 6 r2
add r3
move r3 10
위의 내용은 5번지에 있는 데이터를 r1이라는 레지스터에 넣고, 6번지에 있는 데이터를 r2라는 레지스터에 넣고 r1과 r2에 있는 데이터를 더해서 r3에 넣고 그것을 다시 10번지로 넣으라는 명령을 요약했습니다.
실 제 실행 코드는 숫자로 되어 있습니다. 간단하게 표현한다면 첫 번째 코드는 연산 명령이고 두 번째 와 세 번째 코드는 메모리나 레지스터를 가르킵니다. 위의 "move 5 r1"에서 move 라는 연상 명령이 숫자 코드로 1번이라고 한다면 “1 5 r1"으로 바뀌게 됩니다. 위와 같은 방법으로 위의 코드를 바꾸게 되면 다음과 같습니다.
1 5 r1
1 6 r2
add r3
1 r3 10
위의 코드에서 같은 방법으로 “add" 가 명령어 코드 2번이고 r1,r2,r3 가 각각 -1,-2,-3 이라면 위의 명령요약문은 다음과 같이 바뀌게 됩니다.
1 5 -1
1 6 -2
2 -3
1 -3 10
이 숫자 코드들이 CPU에서 실행하는 실행코드 입니다. "move" 나 "add"로 설정되어 있는 처음의 영문 요약 문은 어셈블리 언어라고 합니다. 그리고 그것을 실행 코드로 바꾸어 만든 것을 컴파일이라고 합니다. 어셈블리 언어를 실행코드로 만드는 것은 매우 간단합니다. "move", "add" 라는 간단한 명령어를 해당 실행코드로 바꾸어 주기만 하면 되고 그리고 레지스터에 해당하는 번호를 해당 실행 코드로 바꾸어 주기만 하면 됩니다.
초 기 프로그래밍에서는 이런 어셈블리 언어를 이용해수 코딩을 많이 했습니다. 필자 또한 15년전 어셈블리 언어를 주로 사용하여 프로그래밍 하였습니다. 어셈블리 언어는 기계어와 가깝기 때문에 일반 프로그래머들도 소스를 보고 어떤 내용인지 이해하기가 어렵고 버그를잡기 또한 매우 어렵습니다. 요즘은 사실 어셈블리 언어를 이용하여 프로그래밍 하는 경우가 별로 없을 정도로 어셈블리 사용은 줄었습니다. 그러나 어셈블리언어와 컴퓨터 구조 및 운영체제의 가장 간단한 기초도 알지 못할 경우 그위의 고급언어를 이용하여 프로그래밍 할때 무엇인가 막히는 어려움이 있습니다.
본장의 마지막 항목에서는 어셈블리 언어를 소개하고자 합니다. 어셈블리 언어로 프로그래밍 하는 방법을 가르치겠다는 것이 아니라 어셈블리 언어의 기본은 이해하자는 취지입니다.
본책에서는 MS-DOS에서 사용했던 어셈블리 언어를 기반으로 설명하겠습니다.
앞 의 어셈블리 예제에서 move는 필자가 여러분에게 이해를 돕기 위해서 사용했고, 실제 어셈블리 언어에서는 move를 mov로 사용합니다. mov 명령어는 필요한 번지나 레지스터가 두개 필요합니다. 첫 번째 항목은 데이터가 있는 곳이고 두 번째 항목은 그 데이터를 이동할 번지나 레지스터 입니다. “mov 1 r1"에서 "1"과 "r1" 두개가 필요하다는 것입니다. 일단 레지스터도 번지로 가정하겠습니다. mov 명령어 같은 것은 두개의 번지를 필요하는 명령어입니다. 이런 명령어를 ”2 번지 명령어“ 라고 합니다. ”add" 명령어는 필요한 번지가 하나 입니다. 이런 명령어들을 “1번지 명령어” 라고 합니다. 다음에 계속적으로 설명하겠지만 번지가 필요없는 명령어 들이 있습니다. 이런 명령어를 “0번지 명령어” 라고 합니다.
어셈블러의 기본 형식은 다음과 같습니다.
[라벨] : [명령어] 번지1,번지2 ; 이곳에는 주석
[라 벨]은 현재 행의 이름을 표시하는 것입니다. 그 행을 기억하고자 할때는 이름을 붙여 주지만 행을 기억할 필요가 없을 경우에는 이름을 붙이지 않습니다. [명령어] 부분은 "mov" 나 “add" 등이며 번지1,번지2 든 명령어가 필요한 데이터가 들어 있는 번지를 의미합니다.(레지스터도 번지로 간주합니다)
“;” 코드 다음에는 그냥 일반 문자열로 기록합니다. 이부분은 어셈블러가 무시합니다. 다만 코드를 보고 어떤 내용이 들어 있는지 프로그램을 이해하기 위해서 설명문을 기록하는 것입니다. 이렇게 프로그램 코드 에 설명을 붙이는 것을 주석이라고 합니다.
1-4-2 CPU의 레지스터들
지금까지 CPU에는 특정 값을 저장하는 방, 즉 레지스터가 있다고 설명했습니다. 또한 현재 프로그램의 코드가 몇 번째까지 실행되었고 몇 번째가 실행되어야 하는가를 저장하는 카운터 레지스터가 필요하다고 하였습니다.
우리가 많이쓰는 Intel Pentium 프로세서는 이런 여러 정보를 저장하기 위한 다양한 레지스터들이 있습니다. 이런 레지스터들에 대해서 설명을 하고자 합니다.
1-4-2-1 데이터 레지스터
데 이터 레지스터는 지금까지 많이 설명한 데이터를 임시로 저장하는 레지스터들입니다. 앞에서 r1,r2,r3 로 표현되었던 것들이 데이터 레지스터 입니다. Intel Pentium 프로세서는 그림 1-16과 같이 4개의 레지스터가 있습니다.
그림 1-16 데이터 레지스터
데 이터 레지스터는 A,B,C,D 4개가 있다고 보시면 간단합니다. 이 4개가 각각 32비트로 설정되어 있습니다. 이 레지스터는 32비트,16 비트,8비트로 나누어서 다양하게 사용할수 있습니다. A 레지스터에서 8비트로 데이터를 저장할때는 Low,High의 약자를 이용하여 AH, AL로 두개를 동시에 사용할수 있습니다. 16비트로 사용하고자 할경우에는 AH와 AL를 합친 영역을 사용하는데 이것을 AX로 표현합니다. 그리고 32비트 전체를 사용한다고 할 경우 앞에 E를 붙여서 EAX로 표현합니다. 이와 같은 방법은 AX,BX,CX,DX, 그리고 EAX,EBX,ECX,EDX 등으로 표현을 할 수가 있습니다. EAX를 이용할것인가 AL를 이용할것인가는 프로그래머가 선택합니다. 사용하고자 하는 숫자의 크기에 따라서 사용방을 조절할 수가 있는 것입니다. 예를 들어서 255 보다 작은 수를 사용한다고 할 경우 AL 레지스터 한개만 사용하여 저장이 가능합니다.
지 금부터는 실제 어셈블리어를 설명합니다. 앞에서는 컴퓨터 구조를 우선으로 설명하기 위해서 어셈블리어를 개략적으로 사용하였습니다. 본 항목에서는 정확한 어셈블리어를 설명하고자 합니다. 실제 메모리 주소는 “[메모리주소]” 형태로 표현 됩니다. 다음은 100번지에 있는 데이터를 AX에 저장하는 예입니다.
mov AX [100]
다 음에서 좀더 자세히 설명하겠습니다만 [100] 이라는 의미는 메모리의 실제 주소가 아니라 데이터가 있는 위치에서부터 100번째에 있는 주소를 의미합니다. 위의 예는 100번지에 있는 데이터를 AX에 저장하는 형태 입니다. 32비트 OS 일 경우 [100] 번지부터 32비트 데이터를 가지고 올수 있습니다. AX를 사용했기 때문에 100번지부터 두바이트 (16비트)의 데이터를 가지고 와서 AX 레지스터에 저장할 수가 있습니다. 만일 32비트의 데이터를 로드하고자 한다면 다음과 같이 하면 됩니다.
mov EAX [100]
같은 의미로 8비트 데이터를 로드하고자 할때는 다음과 같이 할수 있습니다.
mov AH [100]
메 모리에 있는 데이터를 몇바이트 가져 올것인가에 따라서 레지스터의 크기가 달라지고 그에 따른 데이터 저장도 달라 지게 됩니다. 여기서 중점적으로 기억하실 것은 메모리에 있는 데이터를 어떤 크기를 가지고 와서 계산할것인가 입니다. 그에 따라 레지스터 사용도 달라 지기 때문입니다.
1-4-2-2 포인터 레지스터
포인터 레지스터는 현재 사용되고 있는 데이터 포인터를 가르킬때 사용하는 레지스터입니다. 그림 1-17은 포인터 레지스터를 보여줍니다.
]
그림 1-17 포인터 레지스터
포 인터 레지스터도 32비트 입니다. 리얼모드에서는 16비트로 프로텍트 모드에서는 32비트로 사용하는게 일반적이며, 리얼모드 32비트 어드레스를 사용할때는 32비트를 사용합니다. 16비트일 경우 SP 라고 하면 스택포인터(Stack Pointer) 이고 BP 라고 하면 베이스 포인터(Base Pointer) 입니다. 32비트일 경우 앞에 'E'를 붙여서 ESP,EBP 로 명명합니다.
이 레지스터들이 어떤 기능을 하는가? 그림 1-18에서는 포인터 레지스터의 기능을 간단하게 보여줍니다. 데이터를 메모리에 기록하고자 할때 어느 위치부터 기록할것인가 기준점을 주어야 합니다. 그렇지 않다면 데이터의 위치를 찾는데 문제가 발생하기 때문입니다. 그림 1-18처럼 데이터를 처음 설정할 기준점을 메모리 어드레스로 설정하였을때 이 메모리 주소를 BP가 가지게 됩니다. 이상태에서 SP 또한 BP 와 같은 메모리 주소를 가집니다. 이상태에서 데이터가 하나 들어가게 되면 BP는 변화되지 않고 SP만 변화 됩니다. 그림 1-18에서 처음 데이터가 '200'으로 설정된 상태에서 SP가 변화 된 것을 보여줍니다. 이때 또 다시 ‘300’ 이란 데이터가 들어오면 SP는 300의 위치를 가르치기 위해서 메모리 주소
그림 1-18. 스택 포인터와 베이스 포인터
가 변화 됩니다. 이런식으로 데이터의 설정 시작과 그부터 들어오는 데이터의 메모리 위치를 가르쳐 주게 됩니다. 스택이란 쉽게 말하면 위에만 열려 있는 박스형태를 의미 합니다. 이 박스에 맞게 데이터를 넣으면 그 박스에 차곡 차곡 차게 됩니다. 그림 1-18처럼 데이터를 ‘200’,‘300’,‘400’ 등이 차들어가는 것을 “PUSH" 한다고 합니다. 이렇게 되면 SP 포인터로 최근에 넣은 데이터 주소를 가르치게 됩니다. 이상태에서 데이터를 꺼내게 되면 SP 포인터에 있는 데이터부터 꺼내게 됩니다. 즉 ‘400’,‘300’,‘200’ 순으로 꺼내게 됩니다. 이렇게 꺼내는 것을 "POP" 이라고 합니다. "POP"가 되면 SP는 다시 이전 포인터로 이동하게 됩니다.
1-4-2-3 인덱스 레지스터
인덱스 레지스터는 여러개의 메모리 블록을 한꺼번에 이동하거나 가르칠때 사용됩니다. 일반적으로 번지를 간접 지정하는 레지스터라고 합니다. 그림 1-19는 인덱스 레지스터에 대한 그림 입니다.
그림 1-19 인덱스 레지스터
인 덱스 레지스터는 16비트일 경우 SI,DI 로 명명하고, 32비트일 경우 ESI,EDI 로 명명합니다. SI는 Source Index의 약자이며 DI 는 Destination Index의 약자입니다. 이 두개의 레스터에 메모리 주소를 설정하고 나면 해당 메모리를 이동시키거나 복사하는 명령으로 데이터를 이동 및 복사를 할 수가 있습니다. 그림 1-20은 인덱스 레지스터를 이용하여 데이터를 복사하는 내용을 설명한 것입니다.
그림 1-20 인덱스 레지스터 사용
SI 는 복사하고자 하는 데이터블럭의 시작점을 가르키게 됩니다. 그리고 이 데이터 블록을 이동하고자 하는 메모리주소를 DI에 설정시키고 해당 위치로 “몇바이트 복사하라” 라는 명령을 주게 되면 SI부터 시작해서 해당 바이트까지 복사하여 DI부터 시작되는 위치에 이동하게 됩니다. 인덱스 레지스터는 매모리의 복사 및 블록 데이터의 메모리를 참조할 때 많이 사용되고 있습니다.
1-4-2-4 인스트럭션 포인터 와 플래그 레지스터
인 스트럭션 포인터 (IP) 와 플래그 레지스터 (FL) 는 모두 16비트입니다. 인스트럭션 포인터 현재 실행코드의 어느 위치를 실행하고 있는 가를 설정하는 래지스터 입니다. 그림 1-21은 인스트럭션 포인터 래지스터의 기능을 설명합니다.
그림 1-21 인스터럭션 포인터
CPU 가 어떨 프로그램을 실행하는데 그 프로그램이 그림 1-21처럼 100번지부터 있다고 하였을 경우 초기에는 IP 값은 0으로 설정됩니다. 그리고 나서 한개의 명령을 수행하면 그후 IP는 한개씩 증가 됩니다. 3번의 실행을 하게 되면 IP는 3을 가르키게 됩니다. IP 포인터란 바로 현재 프로그램에서 몇 번째 실행 코드를 실행했는가의 정보를 저장하는 레지스터입니다.
플 래그 래지스터는 비교 및 쉬프트 등등의 연산후에 발생되는 결과를 저장하는 래지스터입니다. 만일 비교해서 두개가 같다고 할 경우 플래그 래지스터의 특정비트 값을 1로 설정하게 만듭니다. 이렇게 해서 두개의 비교결과를 저장할 수가 있습니다. 플래그 래지스터의 사용은 1-4-5의 흐름제어에서 다시 설명하도록 하겠습니다.
1-4-3 세그먼트의 개념
세 그먼트의 개념을 이해하기 이전에 좀 딴이야기를 하겠습니다. 제친구가 잠실주공 아파트에 살고 있습니다. 그친구 집에 방문하게 되었습니다. 그 아파트 단지는 정말 미로와 같더군요. 어쨌든 친구 집이 305호라고 해서 열심히 가서 찾았는데 집에 도착하니까 그집이 아니더라구요. 분명 105동 305호라고 했는데 동이 잘못된 것 같았습니다. 전화를 해보아도 연락이 안돼어서 101동부터 110동까지의 모든 305호 벨을 다눌러 보았습니다. 그래서 109동이라는 것을 알게 되었습니다. 이후 부터는 제가 아파트 몇호라고 하면 꼭 동을 정확하게 물어 본답니다. 그런데 요새는 동도 없는 아파트가 있더라구요. 아파트 하나가 50층 이상이 되는 고층이고 거기에 편의점, 스포츠센터 등등 없는게 없더라구요.
“신식 아파트는 완전히 고층 아파트입니다. 그리고 한동밖에 없는 형태입니다” 라고 하더군요. 동도 없이 댓다리 고층 아파트가 요즘 유행한다고 하더군요.
세 그먼트의 개념은 사실 신식 아파트 형태가 아니라 고전 아파트 형태의 개념을 말합니다. 메모리가 여러개의 동으로 구성되어 있고 그 동 안에 번지가 따로 구성되어 있다는 것입니다. 305번지라고 해서 알수 있는게 아니고 10번째 세그먼트 블록의 305번지라고 해야 알수 있다는 것입니다. 아파트의 동수를 세그먼트라고 할수 있고 호수를 옵셋번지라고 볼수 있습니다.
리 얼모드 프로그램은 이런 세그먼트와 옵셋을 이용하여 주소를 사용하나 프로텍트 모드의 프로그램에서는 이런 방식을 사용하지 않습니다. 쉽게 말씀드려 메모리 전체를 하나의 고층 아파트로 생각하기 때문에 호수로 바로 찾을수 있듯이 실제 메모리 번지로 바로 데이터를 얻을수 있습니다. 사실 이부분도 후에 설명하겠지만 가상메모리라는 개념으로 매우 방대하고 거대하게 움직이고 있습니다.
C 를 배운다는 것이 꼭 PC에서 프로그래밍을 하겠다는 것은 아닐것입니다. 8086 계열의 작은 CPU를 탑재한 전자 제품에서 프로그래밍도 C로 합니다. 이번 항목은 리얼모드에서 Intel 8086 계열에서 작은 메모리로 프로그램을 처리할 때 사용되는 세그먼트와 옵셋에 대한 설명을 합니다.
그림 1-22는 세그먼트와 옵셋에 대한 내용를 설명한 것입니다.
그림 1-22 세그먼트와 옵셋
그 림 1-22에서 보면 세그먼트는 1000개씩 나누어져 있고 가각의 세그먼트를 여러개의 옵셋으로 나누었습니다. 각세그먼트의 002번지는 회색으로 칠해져 있습니다. 002 번지라고 해서 다 같은 메모리를 가지고 있지 않습니다. 어느 세그먼트에 002 번지인가를 알아야 합니다. 8086 계열의 16비트 프로그램에서는 메모리를 이렇게 세그먼트와 옵셋을 이용해서 실제 번지를 찾아갑니다. 예를 들어서 첫 번째 세그먼트 1000번지에서 002 번지를 찾아간다면 결국 1002 번지를 찾아가게 되는 것입니다.
8086 계열에서는 세그먼트 한개를 64KB로 나누었습니다. 그리고 프로그램에서 내부적으로 데이터를 사용할 때 64KB 만사용할수 있게 한개의 세그먼트를 할당합니다. 결국 프로그램 내부에서는 64KB 한개의 매모리 영역만 사용하게 된다는 것입니다. 따라서 프로그램 내부에서는 세그먼트는 신경쓰지 않고 옵셋 번지만을 가지고 움직입니다.
8086 계열 16비트 CPU에서는 아무리 메모리가 많아도 1M 바이트밖에는 사용하지 못하도록 되어 있습니다. 1M 바이트를 주소화 한다면 총 20 비트가 필요합니다. 한번에 데이터를 로드할수 있는 16비트 보다는 크기 때문에 메모리를 세그먼트 와 옵셋 두개로 사용합니다. 세그먼트와 옵셋 모두 16비트입니다. 이 두개를 4비트 비껴서 덧셈하는 방법으로 실제 메모리를 구합니다. 4비트란 16진수로 1자리만큼이 됩니다. 16진수로는 1자리 이기 때문에 메모리 주소를 16진수로 표현하는 것이 좋습니다. 16진수는 1-9,A,B,C,D,E,F,10 으로 표현되는 수를 말합니다. 16진수 일 경우 편의상 끝에 'H'를 기록하겠습니다.
3000H 세그먼트에서 2340H 옵셋이라고 한다면 실제 메모리는 다음과 같습니다.
3000H
+ 2340H
-----------------
32340H
위의 의미는 3000H의 세그먼트 시작으로부터 2340H 옵셋이라는 의미와 같습니다.
프 로그램은 두개의 메모리 위치를 가지고 시작됩니다. 데이터를 저장하는 메모리위치 그리고 실행파일의 코드가 있는 메모리 위치 입니다. 이 두개의 위치란 결국 세그먼트 번지를 의미합니다. CPU안에는 4개의 세그먼트 주소를 저장하는 레지스터가 있습니다.
그림 1-23는 4개의 세그먼트를 보여줍니다.
그림 1-23 세그먼트 레지스터
CS 는 코드 세그먼트 입니다. 이 레지스터에는 현재 프로그램의 시작 세그먼트 주소가 저장되게 됩니다. DS 는 데이터 세그먼트라고 합니다. 이곳에는 프로그램이 필요한 데이터 세그먼트 주소가 저장되게 됩니다. 스택 세그먼트란 새로운 데이터가 필요하여 생성되었을때 생성되는 데이터가 로드되는 세그먼트 주소를 저장합니다. 익스트라 세그먼트는 데이터를 메모리에서 복사할 때 복사하는 대상 메모리의 세그먼트 주소가 저장됩니다.
이제 지금까지 설명한 내용을 종합해 보겠습니다.
프 로그램이 실행되면 제일먼저 CS (코드 세그먼트)에 실행코드의 세그먼트 주소가 설정됩니다. 그리고 IP(인스트럭션 포인터)는 0으로 초기화 됩니다. 이때 데이터가 있는 세그먼트 주소는 DS(데이터 세그먼트)에 설정됩니다. 새로운 메모리를 할당하기 위한 세그먼트 주소는 SS(스택 세그먼트에 설정되고) SP는 스텍세그먼트이 첫 번째 주소를 가르키게 됩니다.그리고 BP(베이스포인터)는 DS 세그먼트의 0번지를 가르키게 됩니다.
첫번째 코드가 실행되면 IP 는 증가되고 이때 필요한 메모리를 설정하면 SS의 SP에 메모리를 할당하고 SP 는 그다음 메모리로 증가 됩니다.
세 그먼트 레지스터는 프로그램이 실행에 필요한 실행코드, 데이터블럭, 새로 설정하는 메모리 의 세그먼트를 가르키게 되고, SP,BP,SI,DI 등은 현재 세그먼트에서 필요한 메모리 주소를 가르키게 됩니다. 따라서 세그먼트 레지스터와 포인터 레지스터는 쌍으로 세그먼트와 옵셋으로 메모리를 가르키는데 사용됩니다.
1-4-4 기본 프로그램
본 항목에서는 어셈블리 언어의 기본을 설명하겟습니다. “C 언어를 배우는데 왜 갑자기 어셈블리어냐?” 라고 물어 보실수 있을겁니다. C언어를 배우기 이전에 어셈블리어의 기본을 배우지 않으면 C언어 처음부터 막히게 됩니다. 본장에서 어셈블리 언어의 모든 것을 다루겠다는 것은 아닙니다. 실제로 어셈블리언어가 많이 쓰이지도 않습니다. 그러나 기본의 틀을 가지고 있어야 하기 때문에 이 면을 이용하여 설명합니다.
먼저 아무것도 실행되지 않는 간단한 프로그램을 만들어 보겠습니다. 워드패드나 또는 메모장 같은 에디터를 이용하여 다음의 내용을 기록 합니다.
;어셈블러 기본 프로그램입니다.
MAIN SEGMENT ;메인 시작
ASSUME CS:MAIN,DS:MAIN ; 세그먼트 설정
MOV AH,4CH ; AH 레지스터에 4CH 값을 넣는다.
INT 21H ; 프로그램 종료 커널 서비스 호출
MAIN ENDS ;메인 종료
END ;프로그램 종료
위 내용을 코딩한 파일을 exam1.asm 이라고 하여 저장하시기 바랍니다. 확장자를 asm으로 설정하는 것은 현재 파일이 어셈블리 언어 소스라는 의미입니다.
본 책과 함께 제공하는 CD 에 MASM 이라는 디렉토리에 매크로 어셈블러 컴파일러 프로그램이 있습니다. 어셈블리언어를 실행파일로 컴파일하는 프로그램입니다. 이프로그램을 이용하여 위의 소스를 컴파일하여 실행파일로 만들 수 있습니다. C 디스크에 MASM 이라는 폴더를 만들고 이폴더에 CD에 있는 MASM 폴더안에 있는 모든 파일을 복사 합니다.
윈 도우의 시작메뉴에서 보조프로그램 항목에 보시면 “명령 프롬포트” 라는 항목이 있습니다. 이 항목을 클릭하여 콘솔 모드로 전환 합니다. 콘솔 모드란 그래픽 형태가 아니라 텍스트 기반으로 출력되는 검정색의 창을 의미합니다. 이 콘솔 모드에서 MASM 있는 폴더로 이동해야 합니다. C:\MASM 이라는 폴더에 복사하였다면 다음과 같이 매크로 어셈블러가 있는 폴더로 이동할 수가 있습니다.
CD C:\MASM\BIN
MASM 디렉토리의 BIN 디렉토리에 MASM.EXE 와 LINK.EXE 라는 파일이 있습니다. 이 두개의 파일이 어셈블리언어 소스를 컴파일하는 실행파일 입니다.
이곳에서 다음과 같이 하여 앞의 예제를 컴파일 합니다.
MASM c:\work\exam1.asm
위와 같이 하면 다음과 같은 메시지가 출력 됩니다.
Microsoft (R) MASM Compatibility Driver
Copyright (C) Microsoft Corp 1993. All rights reserved.
Invoking: ML.EXE /I. /Zm /c /Ta ..\..\예제\Chapter1\exam1.asm
Microsoft (R) Macro Assembler Version 6.13.7299
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
Assembling: c:\work\exam1.asm
위 와 같이하면 현재 폴더에 exam1.obj가 만들어 집니다. 이것은 프로그램을 컴파일하여 기계어 코드로 만들었다는 의미 입니다. 보통 목적 파일이라고 합니다. 이제 이파일을 컴파일하여 실행파일로 만들어 보겠습니다. 현재 폴더에서 다음과 같이 실행합니다.
LINK exam1.obj
위와 같이 하면 다음과 같은 메시지들이 나옵니다.
Microsoft (R) Segmented Executable Linker Version 5.31.009 Jul 13 1992
Copyright (C) Microsoft Corp 1984-1992. All rights reserved.
Run File [exam1.exe]:
List File [nul.map]:
Libraries [.lib]:
Definitions File [nul.def]:
LINK : warning L4021: no stack segment
LINK : warning L4038: program has no starting address
Run File 항목과 List File 항목 Libraries 항목에서는 아무것도 입력하지 않고 그냥 엔터키를 치시면 됩니다. 이렇게 되면 LINK 시 경고 메시지가 나오고 exam1.exe 라는 프로그램이 생성됩니다. 경고 메시지는 스텍 세그먼트가 없다는 것과 그리고 프로그램에 아무런 코드가 없다는 것입니다.
생 성된 exam1.exe를 실행시키면 아무것도 나타나지 않고 프로그램이 종료 됩니다. 프로그램 안에 아무런 내용도 넣지 않았기 때문입니다. 컴파일할 때 에러가 나오거나 링크할 때 에러가 나오면 스펠링을 제대로 맞추어 코딩했나를 확인해 보시기 바랍니다. 정확하게 제대로 코팅했을 경우 에러없이 출력되게 되어 있습니다.
이제 앞에서 제작한 exam1.asm 에 대해서 설명을 하겟습니다.
MAIN SEGMENT ;메인 시작
:
MAIN ENDS ;메인 종료
END ;프로그램 종료
어 셈블리 언어에서 프로그램을 시작할 때 “이곳이 프로그램 시작점이다” 라는 것을 알려주기 위해서 라벨 위치에 “MAIN" 이라는 것을 기록합니다. 그리고 시작점에 "SEGMENT" 라고 설정합니다. ”MAIN SEGMENT" 라고 하면 프로그램 코드의 시작점을 의미합니다. 프로그램의 종료를 알려줄때는 "MAIN ENDS" 라고 하면 “메인 프로그램의 종료”을 알려준것입니다. 본 프로그램이 소스가 모두 종료일 경우 “END"를 명령 라인에 기록합니다.
간단하게 이해한다면 위의 소스 내용을 코딩하고 “:” 이부분이 실제 코딩이라고 생각하면 간단합니다.
ASSUME CS:MAIN,DS:MAIN ; 세그먼트 설정
"ASSUME" 명령문은 세그먼트 주소를 설정한다는 의미입니다. 실제 프로그램이 시작될대는 CS(코드 세그먼트) 와 DS(데이터세그먼트) 에 현재 프로그램이 사용할 메모리 세그먼트가 할당되어 있어야 합니다. 위의 명령에 의해서 OS프로그램은 어플리케이션 프로그램을 메모리에 로드시키고 로드된 메모리의 세그먼트 주소를 CS와 DS에 설정하게 됩니다.
MOV AH,4CH ; AH 레지스터에 4CH 값을 넣는다.
INT 21H ; 프로그램 종료 커널 서비스 호출
"MOV AH,4CH" 는 AH 레지스터에 4C 라는 16진수를 넣으라는 의미입니다. “INT 21H"는 커널에 서비스 호출을 하는 것입니다. 소프트웨어 인터럽트라고 하여 설명을 하였습니다. 소프트웨어 인터럽트를 이용하여 21번을 호출하면 해당 모듈에서는 AH에 있는 값을 참조하여 명령을 수행합니다. AH에 4CH값이 있다면 현재 프로그램을 종료하고 프로그램코드를 메모리에서 삭제하라는 의미입니다. 콘솔 모드용 어셈블리 프로그램을 제작할때는 위의 코드를 꼭 삽입해야만 프로그램이 종료 되면서 원래 프롬포트 모드로 돌아가게 되어 있습니다.
본 항목에서 어셈블리 언어를 설명할 때 소프트웨어 인터럽트중 21H 번을 자주사용합니다. 소프트웨어 인터럽트 21번은 바이오스에서 제공하는 인터럽트가 아니라 MS-DOS에서 제공하는 인터럽트입니다. 지금은 콘솔모드에서 커널이 제공하는 서비스로 볼수 있습니다.
21번 인터럽트는 AH레지스터에 어떤 값을 넣는가에 따라서 서비스가 바뀝니다.
AH 에 ‘2’ 값을 넣고 DL 문자 코드값을 넣고 INT 21H를 호출시키면 DL에 넣은 문자 코드값을 문자형태로 화면에 출력합니다. ‘A'라는 문자 코드값이 41H 번입니다. 만일 화면에 ’A'라는 문자를 출력하고자 한다면 다음과 같이 할수 있습니다.
MOV DL,41H ;‘A' 에 해당하는 코드 41H를 넣는다
MOV AH,2 ; DL 레지스터에 있는 값을 화면에 출력하라는 명령 2번
INT 21H ; 소프트웨어 인터럽트 21H 번 호출
위와 같이 하면 소프트웨어 인터럽트 21H을 이용하여 화면에 문자를 출력할 수가 있습니다.
ex 2) 화면에 "ABC"를 출력하는 프로그램을 어셈블리 언어로 작성하라.
풀이)
exam2.asm 은 소프웨어 인터럽트를 이용하여 “ABC"를 화면에 출력하는 예제입니다.
MAIN SEGMENT
ASSUME CS:MAIN,DS:MAIN
START: MOV DL,41H ;‘A'값입력
MOV AH,2 ;명령 2번 설정
INT 21H ;시스템 호출
MOV DL,42H ;'B'값 입력
MOV AH,2 ;명령 2번 설정
INT 21H ;시스템 호출
MOV DL,43H ;'C'값 입력
MOV AH,2 ;명령 2번 설정
INT 21H ;시스템 호출
MOV AH,4CH ;프로그램 종료 명령 설정
INT 21H ;프로그램 종료
MAIN ENDS
END START
1-4-5 어셈블리어의 명령어
지 금까지 어셈블리 언어의 구조에 대해서 설명했습니다. 이제 어셈블리언어에서 사용하는 여러 명령어들을 설명하고자 합니다. 어셈블리 언어에서 사용하는 명령어는 CPU에서 사용하는 있는 사칙연산, 비교연산, 논리연산 및 프로그램 코드 이동 (보통 제어라고 함) 등을 하는 CPU 고유 명령어를 알기쉽게 간단한 영문 요약어로 설정한것입니다. 어셈블리어의 명령어를 이해하면서 CPU 가 사용하는 연산 명령어가 어떤것들이 있는가를 알수가 있습니다.
1-4-5-1 메모리 이동 명령어 MOV
MOV 명령어는 지금까지 많이 사용했습니다. MOV는 메모리 주소에 있는 데이터나 또는 레지스터에 있는 데이터 들의 값을 저장할수 있습니다. 다음은 MOV의 예입니다.
[1]MOV AH,3
[2]MOV DS,SI
[3]MOV BX, [345H]
[1]번 항목의 내용은 지금까지 자주 사용했던 내용입니다. [2]번 항목은 레지스터에 있는 데이터를 이동시키는 것입니다. SI 레지스터에 있는 값을 DS에도 저장한다는 의미입니다.
[3]번 항목은 메모리 [345H]번지에 있는 데이터를 BX에 저장하는 것입니다. BX는 16비트이기 때문에 345H 번지에 있는 데이터 16비트를 연속으로 가져와서 BX에 저장합니다.
1-4-5-2 사칙연산
사칙연산은 ADD,SUB,MUL,DIV 등이 있습니다. 표1은 사칙연산 명령어 리스트입니다.
[표1]사칙연산 명령어
명령
설명
예
ADD
덧셈
ADD AX,BX
ADC
자리올림을 고려한 덧셈
ADC BP,1234H
SUB
뺄셈
SUB AX,CX
SBB
자리받아 내림 고려한 뺄셈
SBB AX,CX
MUL
곱셈
MUL CX
IMUL
부호 있는 곱셈
IMUL BX
DIV
나눗셈
DIV [1234H]
IDIV
부호달린 나눚셈
IDIV BH
CBW
8비트 수치를 16비트로 확장
AL 레지스터의 값을 AX로 확장
CWD
16비트를 32비트로 확장 사용
AX 레지스터를 AX와 DX로 확장
INC
메모리 내용 증가
INC SI
DEC
메모리 내용 감소
DEC CX
덧 셈 과 뺄셈은 기본 명령어로 ADD 와 SUB 두개가 있으며 자리 올림과 자리 받아 내림을 고려한 ADC,SBB 가 있습니다. 곱셈을 할때는 AX 레지스터에 피승수를 넣고 인수레지스터나 번지에 승수가 설정되게 합니다. CBW는 8비트의 수치를 16비트의 수치로 확장하는데 사용합니다. AL레지스터에 있는 값을 AX로 확장해서 저장하는 명령이기 때문에 비트가 커집니다. 원래 데이터를 256이 최대값으로 생각하고 사용했는데 이 수치가 넘어서면 이때 현재 데이터를 그대로 저장하면서 16비트의 수를 사용할 때 사용합니다. CWD는 AX에 저장된 데이터를 또다시 32비트로 확장하기 위해서 AX와 DX를 동시에 사용하는 경우입니다. 이때는 65535 이상의 숫자로 사용할 때 원래 데이터가 16비트에 있을 경우 사용됩니다.
ex 3) 알파벳 'A‘에서 5번째에 위치한 문자를 화면에 출력하는 프로그램을 작성하라.
풀이)
MAIN SEGMENT
ASSUME CS:MAIN,DS:MAIN
START:
MOV BL,41H ;BL 레지스터에 ‘A'의 값 41H를 설정한다.
ADD BL,5 ; BL=BL+5 의 의미
MOV DL,BL ;BL의 데이터를 DL로 저장한다.
MOV AH,2 ;서비스 21번 명령 2번을 AH에 저장
INT 21H ;서비스 21번 호출
MOV AH,4CH ;프로그램 종료 명령 4CH를 저장
INT 21H ;서비스 21번 호출
MAIN ENDS
END START
1-4-5-3 논리연산
논 리 연산은 그동안 수학에서 많이 배웠둰 집합과 명제 부분에 해당하는 항목입니다. “엄마가 허락하고 아빠가 허락하면 난 스키장에 갈 수 있어” 라는 의미가 있다면 이것은 엄마 아빠 모두 허락해야 한다는 것입니다. 두분중 한분이라도 허락하지 앟으면 스키장에 갈수 없다는 것입니다. 즉 조건중 두개 모두가 합당할경우의 연산을 AND라고 합니다. AND일경우에는 두 조건이 모두 ‘참’이 되어야 ‘참’이되고 그렇지 않을 경우 ‘거짓’이 되는 연산입니다. “엄마나 아빠중에 한분만 허락해도 난 스키장에 갈수 있어” 라는 의미라면 이것은 두분중에 한분만 허락한다면 스키장에 갈수 있다는 것입니다. 이런 연산, 즉 두 조건중 한조건만 “참” 이되면 “참” 이된다는 연산을 OR연산이라고 합니다. 이런식으로 논리에 따라 값이 설정되는 연산을 논리 연산이라고 합니다. 앞에서 이논리 연산을 이용하여 덧셈 가산기를 만드는 방법을 이미 설명했습니다. 컴퓨터 연산에서는 이런 조건등을 모두 ‘참’을 1로 ‘거짓’을 0으로 설정합니다. 따라서 AND 일경우에는 두개의 값이 모두 1 일경우에만 1이고 OR은 두개의 값중 하나면 1이라도 1이됩니다. XOR는 두개가 서로 다른 값을 가질겨우에만 1이 됩니다.
표2는 논리연산 명령어 리스트입니다.
[표2] 논리 연산 명령어
명령
설명
예
AND
두개의 비트값이 모두 1일 경우 1
AND AL,AH
OR
두 비트값중 한개만 1일 경우 1
OR BL,BH
XOR
두 비트가 서로 다른값일 경우 1
XOR AX,BX
NOT
비트가 0이면 1로 1이면 0으로 바뀜
NOT AL
NEG
현재 값의 보수를 설정한다.
NEG DI
ex 4)
하나의 예를 들어 설명하겠습니다. AL에는 41H 가 그리고 AH에는 54H가 있을 경우 이것을 AND, OR, XOR, 그리고 AL에서 NOT 연산을 한 예입니다.
16진수
10진수
2진수
AL
41
65
01000001
AH
54
84
01010100
AND
40
64
01000000
OR
55
85
01010101
XOR
15
21
00010101
NOT AL
AA
170
10101010
1-4-5-4 시프트 연산
시 프트 연산이란 비트값을 이동시키는 연산을 의미합니다. 예를 들어서 1000 일 경우 이것을 오른쪽으로 1비트 쉬프트 하면 0100 이됩니다. 좌측의 첫비트의 1이 한비트 우측으로 이동하기 때문입니다. 쉬프트 연산의 명령어는 단어 조합으로 씁니다. 첫 번째 단어가 ‘S' 일경우에는 시프트 시켜라는 의미이고 ’R' 일경우에는 로테이트 시키라는 의미입니다. 로테이트(Rotate)란 회전을 의미하는데 만일 우측으로 쉬프트할 경우 마지막 비트가 다시 첫 비트로 이동할 때 이때를 로테이트라고 합니다. 그렇지 않고 마지막 비트가 사라지거나 또는 다른 형태로 처리 될경우는 쉬프트라고 합니다. 두 번째 단어는 H,O,C,A 등으로 표현을 할수 있습니다. H란 쉬프트 되었을때 빈자리를 0으로 설정하라는 의미이며, O는 빠져나간 비트를 넣으라는 의미이며, A는 부호비트를 설정할것인가의 의미입니다.‘C'는 캐리된 플러그 값을 넣으라는 의미입니다. 마지막 문자는 비트 이동을 우측으로 이동할것인가? 좌측으로 이동할것인가를 결정합니다. ‘L' 일경우에는 좌측으로 ’R'일경우에는 우측으로 이동합니다. 표3은 쉬프트 연산 명령어를 보여줍니다.
[표3]쉬프트 연산 명령어
명령
설명
예
SHL
좌측으로 이동 이동후 0으로 채움
SHL AX,2
SHR
우측으로 이동 이동후 0으로 채움
SHR AX,2
SAR
우측으로 이동, 부호 비트는 설정
SAR BX,CL
ROL
좌측으로 회전
ROL DI,2
ROR
우측으로 회전
ROR AX,2
RCL
좌측으로 회전하고 캐리플러그 넣음
RCL BX,2
RCR
우측으로 회전하고 캐리플러그 넣은
RCR BX,AX
쉬프트 연산중에 가장 많이 사용하는 것은 SHL 과 SHR 입니다. 아주 간단하게 쉬프트 연산을 하고 0으로 채우기 때문입니다. 이 연산은 2를 곱하거나 나누는 연산과 같습니다.
예 를 들어서 24라는 값에 2를 곱한다는 것은 24라는 값을 좌측으로 1번 이동시키면 됩니다. 2로 나눈다는 것은 현재 값을 우측으로 1번이동하면 됩니다. 만일 4를 곱하거나 나눌경우에는 같은방법으로 좌측으로 2번 우측으로 2번 이동하면 됩니다. 2의 승수를 이용하여 곱하거나 나눌때는 시프트연산이 빠릅니다.
1-4-5-5 비교 분기 명령
지 금까지 프로그래밍은 순차적입니다. 순차적이란 의미는 첫 번째 명령 읽고 다음 명령을 계속적으로 수행해 가는 형태를 의미합니다. 실제 프로그램은 순차적인 형태 외에 분기와 반복 형태가 많습니다. 분기와 반복이란 어떤 조건을 판단하고 해당 조건에 의해서 실행코드로 점프하는 형태입니다. 그림 1-24는 분기에 대한 설명입니다.
그림 1-24 순서도와 분기
START BLOCK에서 조건을 판단하고 조건이 참이면 YES BLOCK를 그렇지 않으면 NO BLOCK를 수행하고 그다음 NEXT BLOCK를 수행하는 것입니다. 그림 1-24의 왼쪽 그림은 메모리상에서 수행코드의 이동 형태를 도시한 것입니다. START BLOCK에서 조건을 판단하고 난후 NO 일 경우 NO BLOCK로 건너 뜁니다. 이제부터 건너 뛴다는 의미를 JUMP라고 표현을 하겠습니다. JUMP를 한다는 의미는 현재 프로그램 코드 세그먼트 주소와 데이터 세그먼트 주소 그리고 옵셋 번지가 바뀐다는 것입니다. 이렇게 바뀔때 어떤 레지스터의 값이 변하는가를 독자 여러분이 생각해 보시기를 바랍니다.
조건 판단에 사용되는 비교 명령은 CMP 입니다. CMP 는 인수로 주는 두개의 값을 비교해서 비교 결과를 플러그 래지스터에 저장만 합니다.
다음 그 조건에 의해서 분기하는 명령은 JMP,JAE,JNE 등이 있습니다.
표4는 분기, 반복 명령어 리스트입니다.
[표4]분기,반복 명령어 리스트
명령
설명
예
CMP
두개의 값을 비교해 결과를 플래그 레지스터에 저장한다.
CMP AX,345H
JMP
무조건 해당 번지로 점프한다
JMP NEXT
JAE
CMP에 의한 비교 결과가 크거나 같으면 해당 번지로 점프한다.
JAE YESBLOCK
JNE
CMP에 의한 비교결과가 같지 않으면 해당 번지로 점프한다.
JNE NOBLOCK
JG
CMP에 의한 비교결과가 크면 해당번지로 점프한다.
JG NOBLOCK
JNGE
CMP에 의한 비교결과가 크거나 같지 않으면 점프한다.
JNGE YESBLOCK
LOOP
CX레지스터에 기록한 값 만큼 반복한다.
LOOP YESBLOCK
LOOPE
CMP의 결과가 같으면 CX레지스터 기록한 값만큼 반복한다.
LOOPE YESBLOCK
LOOPNE
CMP의 결과가 잩지않으면 CX 레지스터 기록한 값 만큼 반복한다.
LOOPNE NOBLOCK
어셈블리 언어중에서 분기와 반복 명령어 사용법에 대한 이해가 가장 어렵게 느껴집니다. 명령을 두개를 사용해야만 분기가 되며 CX레지스터를 사용하여 반복을 하기 때문입니다.
예를 들어서 AL 과 BL에 데이터를 비교하여 YESBLOCK 로 이동하는 내용은 다음과 같으 형태의 코딩이 됩니다.
CMP AL,BL
JAE YESBLOCK
:
YESBLOCK: MOV AL,2
MOV DL,41H
INT 21
CMP 명령어는 AL과 BL의 값을 비교해서 그 결과를 플래그 레지스터에 저장합니다. 그리고 JAE 명령어는 플래그 레지스터에 저장한 값을 참조해서 두값이 같을 경우 YESBLOCK로 이동하게 됩니다. 다음 코드는 그림 1-24의형태를 어셈으로 코딩한 내용입니다.
CMP AL,BL
JAE YESBLOCK
JNE NOBLOCK
:
YESBLOCK: MOV AL,2
MOV DL,41H
INT 21
JMP NEXTBLOCK
NOBLOCK: MOV AL,2
MOV DL,42H
INT 21
JMP NEXTBLOCK
NEXTBLOCK:
MOV AH,4CH
INT 21H
YESBLOCK 는 'A'를 출력하고 NOBLOCK는 'B'를 출력합니다. 이때 두개의 분기로 갔다가 다시 NEXTBLOCK로 가기 위해서 JAE와 JNE 명령어를 사용한것입니다. CMP에 의한 결과 플러그에 따라서 YESBLOCK 와 NOBLOCK로 분기 됩니다. JUMP 명령어는 A,G,L,E,N 과 결합하여 여러 명령어로 나타납니다. 각 문자의 의미는 Above(크다),Greater(부호포함 크다), Less(부호를 포함해 작다),Equal(같다),Not (아니다) 입니다.
표 4에는 설명되지 않았지만 만일 같지 않다라는 명령을 사용하고자 한다면 조합에 의해서 JN을 사용하고 같다라는 명령어는 JE로 사용할수 있습니다.
ex 5)'A'부터 ‘K'까지 11개의 문자를 순서대로 출력시키되, ’B'문자를 ‘0’문자로 바꾸어서 출력하라.
풀이)
;exam4.asm
;문자 'A'부터 'K'까지 출력하는데 'B'만 '0'으로
;출력하는 프로그램
MAIN SEGMENT
ASSUME CS:MAIN,DS:MAIN
START:
MOV BL,40H ;BL에 'A'를 저장
MOV CX,11 ;반복을 11번한다
LOOPSTART: ;반복 시작점
ADD BL,1 ;BL를 증가 시킨다
CMP BL,42H ;BL과 42H(B) 와 비교
JE YES ;비교결과가 같은면 YES로 점프
JNE NO ;같지 않으면 NO블럭으로 점프
NO: ;NO블럭
MOV DL,BL ;BL값을 출력하기 위해 DL로 저장
MOV AH,2 ;서비스 명령 2번 설정
INT 21H ;서비스 21번 호출
JMP NEXT ;NEXT블럭으로 점프
YES: ;YES 블럭
MOV DL,30H ;Dl에 '0' 값을 저장
MOV AH,2 ;서비스 명령 2번 설정
INT 21H ;서비스 21번 호출
JMP NEXT ;NEXT 블럭으로 점프
NEXT:
MOV DL,',' ;DL에 ','문자 저장
MOV AH,2
INT 21H
LOOP LOOPSTART ;11번 LOOPSTART로 반복
MOV AH,4CH ;프로그램 종료
INT 21H
MAIN ENDS
END START
1-4-5-6 I/O 명령
PC 는 하드디스크, 모니터 어댑터, 키보드등이 주변장치와 연결되어 있으며 이 주변장치와 서로 통신을 I/O포트를 통해서 한다고 설명하엿습니다. I/O 포트에 데이터를 쓰는 명령은 INN 이며 I/O 포트에 데이터를 전송하는 명령은 OUT 입니다.
비디오 카드를 제어하는 방법을 설명하면서 I/O 프로그래밍에 대해서 설명하겠습니다.
모 니터 어댑터를 보통 비디오 카드라고 합니다. 비디오 카드는 일반적으로 4개의 I/O 포트를 사용합니다. 두개은 전송용이고 두개는 수신용입니다. 전송과 수신에서 포트를 두개 사용하는 이유는 하나는 명령이며 하나는 전달하는 데이터 값을 기록하기 위해서입니다. 예를 들어서 34H,35H 가 전송이고 36H,37H가 수신용이라면 34H에는 비디오카드에 전달하는 명령과 35H에는 명령과 함께 사용되는 데이터를 전달하게 됩니다. 수신용에서는 보통 레지스터 값을 참조하는데 사용되는데 36H에는 참조하고자 하는 레지스터 번호이며 37H에는 참조 값을 얻을수 있습니다.
ex 6)비디오 카드의 I/O 포트가 34H,35H,36H,37H 일때 1024x768의 그래픽 모드로 바꾸고자 하는 명령은 32H 번이고 이때 인수값은 칼라 모드 값이다. 현재 그래픽 모드가 성공적으로 수행되었는지를 참조하는 레지스터는 10H 이고 그값이 1일 경우 성공적으로 수행된것이다. 이것을 알 수 있는 어셈블리어 프로그래밍을 대략적으로 기술하라.
풀이)
OUT 34H,32H ;32번 명령 설정
OUT 35H,10H ;16칼라 모드
INN 36H,AX ;36H 값 얻기 AX 에 10H 값이며
INN 37H,BX ;37H 값 얻기 BX 에 1값이 들어 온다
1-4-5-7 블록 전송 명령
블 록 전송 명령은 한번에 여러 바이트의 데이터를 한꺼번에 레지스터에 로드하거나 또는 레지스터에 있는 16비트 이상의 데이터를 메모리에 전송하는 기능을 가지고 있습니다. 이명령은 SI 레지스터와 DI 레지스와 쌍으로 연결되어 있습니다.
먼저 SI 레지슽와 DI 레지스터에 데이터를 기록한후 블록 전송 명령을 하면 SI,DI 에 있는 메모리 번지를 참조하여서 데이터를 로드합니다. 이때 로드된 데이터는 AL,AX 레지스터에 기록 됩니다.
LODS 는 메모리 번지로부터 레지스터로 데이터를 로드하는 명령이며 STOS는 레지스터로부터 메모리로 데이터를 전송하는 명령입니다. 이때 끝의 문자가 B일 경우 바이트 이며 W일 경우 워드(Word) 라는 약자이며 16비트를 의미합니다. 이명령은 인수가 없으며 단순하게 LODSB, STOSTW, MOVSB, MOVSW 등으로 사용할 수가 있습니다.
1-4-6 어셈블러의 문제점
지 금까지 어셈블리 언어에 대해서 개략적으로 설명하였습니다. 필자는 이 장에서 어셈블리 언어를 완벽하게 이해시키고자 함이 아닙니다. 다만 C언어를 배우기 이전에 컴퓨터 구조와 실제 기계어 코드와 같은 의미의 어셈블리 언어를 익힘으로써 컴퓨터 시스템의 기본 지식을 연마하자는데 목적이 있습니다.
실 제로 어셈블리 언어로 코딩을 하면 프로그래밍이 매우 어렵습니다. 인간에 가까운 언어가 아니라 컴퓨터에 가까운 언어이기 때문에 소스를 보고 프로그래밍 구조를 이해하기가 힘들기 때문입니다. 또하나 어셈블리 언어로 만든 프로그램은 디버깅에서도 매우 큰 문제점을 가지게 됩니다. 디버깅을 하면서 저장된 레지스터와 메모리 관계를 일일이 기억을 해야 하기 때문입니다. 그러나 어셈블리 언어는 하드웨어를 직접 제어하기 때문에 하드웨어 처리에 강점을 가지고 있습니다. 이런 문제를 해결하기 위해서 고급언어로 탄생된 것이 바로 C 언어 입니다. C 언어는 하드웨어를 제어할수 있으면서 인간이 그래도 이해하기 쉬운 형태로 구성되어 있습니다. 또하나 모듈화를 하여 재사용을 지원한다는 점에서도 잇점이 있습니다. C언어 보다 더욱더 쉬운 형태의 프로그래밍은 기계와 멀어진다는 단점이 있습니다. 결국 아직까지는 C언어가 인간과 기계의 중간에서 프로그래밍을 최적화 할수 있는 언어로 아직까지 존재하는 이유가 됩니다.