SKYLIGHT STUDIO

[Assembly #2] 레지스터 본문

Computer Programming/Assembly

[Assembly #2] 레지스터

SKY_L 2023. 10. 20. 16:57

역사는 운명론을 가르치지 않는다 - 샤를 드골

오늘 학습할 내용은 레지스터. 어셈블리어를 처음 학습하는 학부생들에게 결투신청을 하는 처음의 난관이다.

대다수의 어셈블리어 입문서적들은 이렇게들 말한다.

 

"IA-32 레지스터는 범용 레지스터가 8개 있으며, 각 역할은 다음과 같다. EAX는 정수 연산, ECX는 카운팅..."

 

물론 무식하게 외우면 좋겠지만, 한번 이렇게들 생각해보면 이해하기 쉬울 지도 모르겠다.

 

레지스터는 변수다.

 

물론 컴퓨터수학적인 개념으로 변수(Variable)를 생각하면 당연히 와닿지는 않을 것이다. 개념 자체가 아예 다르기도 하고.

 

'리버스 엔지니어링 바이블(강병탁 저)'에서 이 '레지스터=변수' 야매(?) 이론을 이렇게 설명한다.

 

변수는 변수인데, CPU가 사용하는 변수.

 

다만 CPU가 사용하는 변수라 개수가 몇 개 안되고, 그래서 메모리의 힘을 빌려 연산을 시작하는 것이라고 생각한다.

그리고 C언어로 코딩할때 변수로 더하고 빼고 나누는 연산을 할 수 있는 것처럼, 어셈블리에서도 연산을 할때 레지스터끼리 연산을 한다고 생각하면 된다. 이것이 전제조건이다.

 


자, 그러면 이제 본격적으로 파고들어가보자.

일단 레지스터는 총 8가지가 있다.

 

 

- EAX

- EBX

- ECX

- EDX

- ESI

- EDI

- EBP

- ESP

 

 

어지러워지지만 조금만 더 참고 견뎌내보자.

레지스터마다 역할이 다 다르므로 더 어지러워지기(?) 때문이다.

 

일단 한가지 염두에 두어야 할 것은, 대개 EAX~EDX는 중간에 있는 알파벳 순서로 외우곤 하는데 역할론적으로 생각해보면 EAX, EDX, ECX, EBX로 학습하는 것이 낫다. 자세한 내용은 후술.

 


EAX

Extended Accumulator Register. 즉 확장 누산기 레지스터. 컴퓨터구조론을 학습한 학부생이라면 반가울 용어다.

일단 역할은 "산술 계산을 하며, 리턴값을 전달"하는 것이다. 썩 와닿지는 않지만 앞서 말했던 레지스터=변수 야매이론으로 생각해보자.

 

일단 당연히 계산식에 동원될 것이니 당연하게도 더하기, 빼기, 곱셈, 나눗셈 등에 자주 등장한다. 또한 함수의 리턴값이나 return 100 등의 코드에서 100에 해당하는 값이 바로 EAX에 기록된다. 이후 EDI에서 다시 한번 설명한다.

 

EDX

Extended Data Register. 확장 데이터 레지스터.

EAX의 하위호환 비스무리한 존재. EAX와 역할은 같지만 리턴 값의 용도로는 사용되지 않는다. 부호 확장 명령 등에 쓰이고 큰 수의 곱셈 또는 나눗셈 등의 연산이 이루어질때 덤으로 사용되기도. 

ECX

Extended Count Register. 확장 카운트 레지스터.

대강 이렇게 생각하면 된다. C언어의 for문에서 i의 역할. 말 그대로 카운터의 역할을 수행한다.

특이한 점은 i++가 아닌 i--라는 것. 미리 루프를 돌 값을 넣어넣고 감소시킨다.

EBX

Extended Base address Register. 확장 베이스-어드레스 레지스터. 메모리 주소를 저장할 때 사용되며 ESI 레지스터나 EDI 레지스터와 결합될 수 있다.

 

사실 특이한 기능을 위해 만들어진 레지스터가 아닌 스페어 레지스터라고 봐도 무방. 어떤 목적을 가지고 만들어진 레지스터가 아니다. 따라서 레지스터가 하나쯤 더 필요하거나 공간이 필요할 때 등 적당한 용도를 프로그래머나 컴파일러가 알아서 만들어서 사용한다.

ESI / EDI

각각 Extended Source Index / Extended Destination Index.앞서 EAX ~ EDX와 조금 다른 결이고, 연산보다는 주로 문자열이나 각종 반복 데이터를 처리 또는 메모리를 옮기는 데에 사용된다.

 

이 둘을 묶어서 설명한 이유는 어쩔 수 없기 때문이다.앞서 우리는 레지스터를 변수로 생각한다고 했다. C언어를 학습한 사람이라면 이렇게 생각을 해보자.

 

memcpy(void *dest, void *src, size_t count)

 

memcpy() 함수는 첫번째 인자를 목적지로, 두번째 인자를 출발지로 갖는다. 말 그대로 두번째 인자에서 첫번째 인자로 메모리를 복사한다.

 

memcpy()와 마찬가지로 어셈블리어에서는 ESI에서 메모리를 읽어 EDI복사한다는 것.

그냥 source와 destionation을 숙지해두면 된다.

 

ESI와 EDI를 학습하면 필수적으로 AL, AH 또한 학습해야 하는데-- 이건 조금 있다 하겠다.

 

ESP

 Extended Stack Pointer. SP라고도 한다.

스택의 최상단 주소값을 저장하고 있는 레지스터다, 스택의 주소는 높은 값에서 낮은 값으로 할당되는데, 스택의 성질을 고려해보면 최상단의 주소는 가장 작은 값이 될 것이다.

 

데이터가 스택 내에서 계속 쌓이거나, 반환되기 위해 필수적으로 필요한 레지스터.

참고로 반환된 주소의 데이터는 바뀌지 않고 그대로 남아있게 된다(나중에 어떠한 이유로 덮어써질수는 있다). 이유는 데이터를 굳이 임의의 수로 초기화 하지 않아도, ESP의 값만 바꿔주면 사실상 문제 될게 없기 때문.

EBP

 

현재 스택 프레임의 베이스 주소를 담는다. ESP와 EBP는 다음 기회에 설명한다.

 


이제 본격적으로 레지스터를 예를 들어가며 설명하기 전 EAX를 구성하는 레지스터들인 AL, AH에 대해 설명해야 할 필요성이 있다.

 

 

 

앞서 언급했던 EAX 등의 레지스터는 32비트--즉 4바이트의 크기다. 그리고 AX는 16비트, 즉 2바이트이고 AH와 AL은 각각 8비트-- 1비트가 되는 것이다.

 

그래서 EAX가 0xaabbccdd라면 결과적으로 AX은 ccdd이고 AH와 AL은 각각 cc와 dd에 대응하게 되는 것이다.

이제 예를 들어보겠다.

 

 

지금 EAX는 0X778563412라는 변수가 담겨져 있다. 여기서 다음과 같은 코드들을 수행한다고 해보자.

 

mov ah, byte ptr ds:[esi]
mov al, byte ptr ds:[esi]
mov ax, word ptr ds:[esi]

 

일단 해당 코드들의 어셈블리 코드를 해석해보자. 

 

자세한 내용은 다음에 학습하겠지만... 일단 단편적으로나마 알 수 있다.

첫번째 라인은 esi 주소에 담긴 값을 바이트로(즉 1바이트만) ah에 넣으라는 것. 두번째도 비슷하다.

 

마지막 라인은 ax는 워드로 2바이트의 크기를 차지한다는 것을 감안하며 실제 트레이싱(프로그램의 실행에 관한 정보를 기록하기 위한 로깅의 특별한 사용)을 하겠다는 의미이다.

 

마지막 라인이 좀 어렵다. 그래서 한번 예를 들어서 설명해보도록 하겠다.

 

ESI : 0x401020 - 83 EC 40 56

해당 줄의 의미는 ESI에 담긴 0x401020 번지에 83 EC 40 56이라는 이 담겨져 있다는 뜻이다.

이 값들이 EAX에 옮겨지는 과정을 한번 따라가보자.

 

mov ah, byte ptr ds:[esi]

 

이제 해당 코드를 한번 수행해보자.

현재 EAX의 AH은 0x34

바이트 하나를 떼온다고 했으니 0x83을 ESI에게서 떼온 뒤 치환하면 된다.

 

따라서 결과론적으로 EAX : 0x78568312. ah에 새로운 값이 들어갔다

같은 방법으로 두번째 코드도 수행하면 EAX : 0x78568383!

 

mov ax, word ptr ds:[esi]

 

대망의 세번째 코드를 수행해보자. 워드(Word)라고 했으니 바이트 2개를 가져와야 한다.

따라서 EAX는 최종적으로 0x7856EC83이라는 결과값이 나온다!

 

이게 이해가 가지 않는 사람이 있을 수 있는데, 리틀 엔디언(Little Endian) 표기법에 대한 학습이 필요하다.

이건 차후에 게시글로 정리하던지 해야 할 듯 싶음.

 


이런 16비트 레지스터가 AX만 있지는 않을 것이다. 레지스터는... 음, 비슷비슷하니까.

당연히 다른 레지스터들도 다 존재하고... 그냥 A, B, C, D로 시작하는 각 레지스터명에 L과 H만 붙이면 된다. 괜히 미련하게 암기하지 말자. 여기서 L은 Low, H는 High이다.

 

32비트 16비트 상위 8비트 하위 8비트
EAX AX AH AL
EDX DX DH DL
ECX CX CH CL
EBX BX BH BL

REFERENCE

『리버스 엔지니어링 바이블: 코드 재창조의 미학』 - 강병탁 저

21. 스택 : 레지스터 ESP, EBP와 명령어 POP, PUSH|작성자 zxwnstn

 

'Computer Programming > Assembly' 카테고리의 다른 글

[Assembly] 어셈블리어  (0) 2023.10.19