레지스터는 CPU의 작은 저장 공간으로 CPU가 데이터에 접근하는 가장 빠른 방법을 제공한다. x86 명령 셋에서 CPU는 8개의 범용 레지스터(EAX, EDX, ECX, ESI, EDI, EBP, ESP, EBX)를 사용한다. CPU에는 그 밖에도 다른 레지스터들이 있지만, 이 8개의 범용 레지스터가 요구되는 경우에 대해서만 살펴보자. 8개의 범용 레지스터는 CPU가 명령을 효과적으로 처리할 수 있도록 각기 용도에 맞게 설계됐다. 따라서 각 레지스터가 어떻게 사용되는지 이해하는 것이 중요하다.



EAX 레지스터는 어큐뮬레이터 레지스터(Accumulator Register)라고도 부르며, 산술 연산을 수행하기 위해 사용되거나 함수의 리턴 값을 전달하기 위해 사용된다. x86 명령 셋에서 최적화된 많은 명령이 데이터 계산과 저장으 위해 EAX 레지스터를 사용하게 설계됬다. 즉, 더하기, 빼기, 비교 연산 같은 대부분의 기본적인 연산이 EAX 레지스터를 사용하게 최적화됐다. 또한 곱하기나 나누기 같이 좀 더 특화된 연산의 경우는 EAX 레지스터 내에서만 수행될 수도 있다. 


앞에서 설명했듯이 함수의 리턴 값은 EAX 레지스 내에서만 수행될 수 있다. 따라서 EAX에 저장된 값을 조사하면 호출한 함수가 성공했는지, 실패했는지 여부를 쉽게 판단할 수 있으며, 함수가 반환한 리턴 값이 무엇인지 알 수 있다.



EDX 레지스터는 데이터 레지스터(Data Register)이다. 이 레지스터는 기본적으로 EAX 레지스터의 확장 개념으로 사용된다. 즉, 곱하기나 나누기 같이 복잡한 연산을 위해 추가적으로 데이터를 저장할 때 사용된다. EDX 레지스터는 범용 목적의 저장소로도 사용된다. 하지만 대부분의 경우 EAX 레지스터와 함께 연동해서 수행되는 연산에 사용된다.



ECX 레지스터는 카운터 레지스터(Counter Register)라 불리며, 반복적으로 수행되는 연산에 주로 사용된다. 반복 연산에서는 문자열을 저장하거나 카운트를 세는 작업이 수행된다. 그런데 중요한 점은, ECX 레지스터는 값을 증가시키면서 카운트를 세는 것이 아니라 값을 감소시키면서 카운트를 센다는 점이다. 다음의 간단한 파이썬 코드를 살펴보자.


counter = 0

while counter < 10:
	print "Loop number: %d" % counter
	counter += 1


위 코드를 어셈블리 언어로 변환해보면 카운트 값을 나타내는 ECX 레지스터의 값이 첫 번째 반복 연산을 수행할 때는 10이고, 두 번째 반복 연산을 수행할 때는 9로 감소한다는 점을 알게 될 것이다. 그런데 위 파이썬 코드에서의 카운트 값은 증가되는 방향으로 작성되어 있다. 이는 다소 혼동을 줄 수 있는데, 어셈블리 언어에서의 카운트 값은 항상 감소하는 식으로 동작한다는 점을 기억하면 혼동되지 않을 것이다.


x86 어셈블리 언어에서 데이터를 처리하는 반복문에서는 효과적으로 데이터를 처리하기 위해 ESI 레지스터와 EDI 레지스터를 사용한다. ESI 레지스터는 데이터 연산을 위한 원천지 인덱스(Source Index)를 나태내거나 입력 데이터 스트림의 위치를 나타내기 위해 사용된다. EDI 레지스터는 데이터 연산의 목적지 인덱스(Destination Index)를 나타내거나 데이터 연산의 결과가 저장되는 위치를 나타내는 데 사용된다. ESI 레지스터는 읽기 위해 사용되고 EDI 레지스터는 쓰기 위해서 사용된다고 생각하면, ESI, EDI 레지스터의 용도를 좀 더 쉽게 기억할 수 있을 것이다. 이처럼 데이터 연산에 인덱스 레지스터를 사용함으로써 프로그램의 실행 성능이 상당히 향상된다.


ESP 레지스터EBP 레지스터는 각기 스택 포인터(Stack Pointer)와 베이스 포인터(Base Pointer) 레지스터이다. 이 레지스터들은 함수 호출과 스택 연산에 사용된다. 함수가 호출될 때 먼저 함수에 전달되는 파라미터가 스택에 PUSH되고 그 다음에는 리턴 주소가 스택에 PUSH된다. ESP 레지스터는 스택의 가장 높은 위치를 가리킨다. 따라서 함수 호출시 ESP 레지스터는 리턴 주소를 가리킨다. EBP 레지스터는 호출 스택의 가장 낮은 위치를 가리키는 데 사용된다. 경우에 따라서는 컴파일러가 코드 최적화를 위해 스택 프레임 포인터로 사용되는 EBP 레지스터의 사용을 제거하는 경우도 있다. 이런 경우에는 EBP 레지스터를 다른 범용 레지스터와 동일한 용도로 사용한다.


EBX 레지스터는 특정한 목적으로 설계된 레지스터가 아니다. 따라서 추가적인 저장소로 이 레지스터를 사용한다.


또 하나의 특별한 레지스터로는 EIP 레지스터가 있다. 이 레지스터는 현재 실행 중인 명령의 주소를 가리킨다. CPU가 바이너리 코드를 실행시킴에 따라 EIP 레지스터는 CPU가 현재 어느 코드를 실행시키고 있는 중인지 나타내기 위해 계속적으로 실행되는 코드의 주소를 갱신한다.


디버거는 레지스터의 값을 읽거나 변경할 수 있어야 한다. 각 운영체제는 디버거가 CPU와 상호 작용하고 레지스터의 값을 읽거나 변경할 수 있는 인터페이스를 제공한다. 





< 요약 >

EAX 레지스터

: Accumulator Register, 산술 연산을 수행 or 함수의 리턴 값을 전달.

EDX 레지스터

: Data Register, EAX와 함께 복잡한 연산을 위한 추가적인 데이터를 저장할 때 사 용

ECX 레지스터

: Counter Register, 반복적으로 수행되는 연산(반복문)에 사용됨. 반복 연산에서 문자열을 저장하거나 카운트를 셈.


ESI 레지스터/ EDI 레지스터

: ESI레지스터는 Source Index를 나타내고, EDI 레지스터는 Destination Index를 나태낸다. 데이터 연산을 읽기 위해서 ESI 레지스터가 사용되고, 데이터 연산을 쓰기 위해 EDI 레지스터가 사용된다.


ESP 레지스터

: 특정한 목적은 없음. 레지스터의 일반 목적인 저장소로 쓰임.


EIP 레지스터

: 바이너리 코드 실행 중에 현재 실행되고 있는 명령의 주소를 가리킨다.





+ Recent posts