본문 바로가기

High Level Technique/Window System

명령어, 레지스터의 구성

명령어, 레지스터의 구성



컴퓨터를 사용하는데 가장 많이 들어본 이야기가 "컴퓨터는 0, 1로만 이해한다." 입니다.


하지만 사람이 0과 1로 보기에는 무리가 있고, 이것을 쉽게 보기위해서 어셈블리어, C언어 등 다양한 언어들이 나왔습니다.


리버싱을 하게되면 어셈블리어를 보게 되는데, 이 어셈블리어는 0과 1로 이루어진 값을 일대일 대응시켜 만들어진 언어입니다.



이러한 어셈블리어들은 어떻게 만들어졌는지 알아보도록 하겠습니다.



현재 많은 컴퓨터들이 64비트로 실행되고 있습니다. 물론 32비트도 많이 있습니다. 하지만 하드웨어사양도 높아지고 처리해야하는 데이터 양도 많이져서 64비트를 많이 사용하고 있습니다.

앞서 어셈블리어는 0과 1로 이루어진 값을 일대일 대응시켜서 만들어졌다고 했는데 이번 포스팅에서는 16비트를 기준으로 설명하도록 하겠습니다.



32비트에서는 레지스터가 EAX, EBX, ECX, EDX 등이 있고, 64비트에서는 RAX, RBX, RCX, RDX 등이 있습니다.

ARM에서는 r0, r1, r2 ... r30(?) 으로 이루어져 있습니다. 사실 30인지 더 있는지 기억이 안남...



여튼 간단히 ARM에서 r0, r1 으로 사용하는 것처럼 설명하겠습니다.





레지스터 구성


레지스터를 만드는데  몇 개를 이용할 것인지 정해야 합니다. r0 부터 r7까지 총 8개를 사용하도록 하겠습니다.

총 8개의 레지스터를 사용한다고 했으니 r0 부터 r7까지 각각의 레지스터들이 어떤 역할을 할지도 정해야 합니다. 


r4는 instruction register r5는 stack pointer r6은 link register r7은 program counter 라고 하겠습니다.





명령어 구성


레지스터 개수도 정했고 어떻게 사용할지도 정했고 16비트를 기준으로 한다고도 했고 이제 각 비트 값에 따라 어떤 명령으로 만들지 생각을 해야 합니다.

가령 001은 덧셈 010은 뺄셈 011은 곱하기 100은 나누기와 같이 정의를 해주어야 합니다.


그러면 총 16개의 비트에 값이 채워져 들어오는데 어떻게 더하기를 하는건지 어떤 비트가 숫자인지 구별을 할까요?





명령어, 레지스터 정의


계속해서 말을 하지만 컴퓨터는 0과 1만 이해할 수 있습니다. 어떤 것이 더하기를 나타내는 값이고 어떤 것이 레지스터를 나타내는 것인지 모르죠.


더하기는 ADD 001

빼기는 SUB 010

곱하기는 MUL 011

나누기는 DIV 100


r0은 000

r1은 001

r2는 010

r3는 011

r4는 100

r5는 101

r6은 110

r7은 111


이렇게 정의하도록 하겠습니다.










자 그렇다면 0000101010010111 이라는 비트가 처리되야 하는데 어떻게 처리를 할까요?




위와 같이 앞 2비트는 예약으로 두고 다음 3비트는 명령어 다음 3비트는 레지스터 다음 4비트는 값1 다음 4비트는 값2 이렇게 구별하도록 합니다.

따라서 위 비트는 r2에 r1과 7을 더해 저장하라 라는 의미가 됩니다.











여기서 궁금한 점이 생깁니다. 앞서 r1은 001이라고 정의를 했습니다. 그런데 위 그림에서는 1001로 되어있습니다. 왜 이렇게 될까요?


r2 = 3 + 4와 같은 연산을 해야한다면 아래와 같이 정의할 수 있습니다.




하지만 r2 = r1 + 4와 같은 연산을 해야 한다고 가정하면 아래와 같이 비트를 정의할 수 있습니다.





r1 부분을 보면 0001로 되어있습니다. 컴퓨터는 이 값을 숫자 1로 생각을 해야하는 것인지 r1레지스터로 생각을 해야하는 것인지 모르게 됩니다.



그래서 레지스터라는 것을 알려주기 위해서 4비트 중 맨 앞비트에 1을 넣게 되어 이 값은 레지스터의 값이라는 것을 알려주게 됩니다.







LOAD & STORE 명령어 및 디자인



우리가 C언어에서 선언과 초기화를 할때 다음과 같이 작성합니다.


int a = 10;

int b = 20;

int c = 0;


c = a + b;


이런 식으로 작성을 했습니다.



위와 같이 선언을 하게되면 메모리 공간에 a=10, b=20, c=0 이 저장되어있겠죠. 그러면 메모리에서 레지스터에 가져와서 연산을 해야하는데 이 또한 명령어가 필요하겠죠.

이러한 명령어가 LOAD, STORE 명령어 입니다.


마찬가지로 LOAD, STORE도 비트로 정의를 해줘야 합니다.


LOAD는 110, STORE는 111로 정의하도록 하겠습니다.






예약 다음 3비트를 읽어드려서 LOAD라는 것으로 CPU가 알게되면 다음 값들은 Destination, Source로 판단을 하고 처리를 하게 됩니다.


마찬가지로 STORE도 똑같습니다.



LOAD r1, 0x10 이라면 0x10 번지에 값을 r1으로 이동한다라는 뜻이 됩니다.



여기서 문제가 발생할 수 있는 부분이 있습니다.



Destination에서는 r0 ~ r7 까지이기 때문에 범위를 벗어나지 않습니다. 하지만 Source 부분은 0x00 ~ 0xFF 까지만 가능합니다. 


하지만 0x100 주소를 가져오게 된다면 문제가 발생할 수 있습니다.









Direct와 Indirect


앞서 Source 부분에서 값의 범위를 넘어가게 되면 문제가 발생한다고 했습니다. 


지금까지 값을 호출하는 방식은 Direct 방식입니다. 이러한 방식에 문제가 발생하기 때문에 Indirect 방식으로 접근을 해야합니다.


간단히 말하자면 0x10번지의 값 10을 바로 레지스터에 넣지않고 0x10에 주소를 넣어 해당 주소로 이동하여 값을 가져오도록 하는 것입니다.



바로 저장을하는 것이아니라 한번 더 거쳐서 값을 저장하는 것입니다.


이 또한 Direct 모드, Indirect모드도 비트로 표현을 해야합니다.



지금까지 예약으로 남겨둔 비트가 Direct와 Indirect로 사용됩니다. 00이라면 Direct 11이라면 Indirect로 사용되는 것이죠.




'High Level Technique > Window System' 카테고리의 다른 글

커널 오브젝트 (Kernel Object)  (0) 2016.12.26
프로세스  (0) 2016.12.26
Polymorphic  (0) 2016.09.13
x86 & x64  (1) 2016.09.12
SBCS, MBCS, WBCS  (0) 2016.09.12