이번에는 컴퓨터 구조와 명령어 집합구조, 인텔의 x86-64에 대해 간단히 살펴볼 것이다.
컴퓨터는 각자 다른 기능을 수행하는 여러 부품들의 도움으로 작동한다. CPU는 컴퓨터의 작동에 핵심이 되는 연산을 처리하고, 저장장치는 데이터를 저장한다. 이 외에도 GPU는 그래픽 데이터를, 랜카드는 네트워크 통신을, 사운드 카드는 소리 데이터를 처리하는 것에 특화되어 있다. 각 부품들은 특징이 뚜렷하여 컴퓨터에서 고유의 기능을 수행한다.
이처럼 서로 다은 부품들이 모여서 '컴퓨터'라는 하나의 기계로서 작동할 수 있는 것은 컴퓨터에 대한 기본 설계가 존재하기 때문이다. 이러한 설계를 '컴퓨터 구조(Computer Architecture)'라고 부른다.
전체적인 컴퓨터 구조 중에서 특히 CPU가 사용하는 명령어와 관련된 설계를 명령어 집합구조(Instruction Set Architecture, ISA)라고 하는데, 가장 널리 사용되는 ISA 중 하나가 인텔의 x86-64 아키텍처를 대상으로 작성됐다.
시스템 해킹 공부를 시작하는 시점에서, 컴퓨터 구조 및 x86-64에 대한 이해는 앞으로의 학습에 중요한 기초 지식이 될 것이다. 그러나 이를 암기하려고 하기보다는 큰 줄기를 살펴본다는 생각으로 가볍게 훑어볼 것을 추천한다.
초기 컴퓨터 과학자 중 한명인 폰 노이만은 컴퓨터에 연산, 제어, 저장의 세 가지 핵심 기능이 필요하다고 생각했다. 근대의 컴퓨터는 연산과 제어를 위해 중앙처리장치(Central Processing Unit, CPU)를, 저장을 위해 기억장치(memory)를 사용한다. 그리고 장치간에 데이터나 제어 신호를 교환할 수 있도록 버스(bus)라는 전자 통로를 사용한다.
중앙처리장치🧠
CPU는 프로그램의 연산을 처리하고 시스템을 관리하는 컴퓨터의 두뇌이다. 프로세스의 코드를 불러오고, 실행하고, 결과를 저장하는 일련의 모든 과정이 CPU에서 일어난다.
CPU는 산술/논리 연산을 처리하는 산술논리장치(Arithmetic Logic Unit, ALU)와 CPU를 제어하는 제어장치(Control Unit), CPU에 필요한 데이터를 저장하는 레지스터(Register) 등으로 구성된다.
기억장치 💾
기억장치는 컴퓨터가 동작하는데 필요한 여러 데이터를 저장하기 위해 사용되며, 용도에 따라 주기억장치와 보조기억장치로 분류된다. 주기억장치는 프로그램 실행과정에서 필요한 데이터들을 임시로 저장하기 위해 사용되며, 대표적으로 램(Random-Access Memory, RAM)이 있다. 이와 반대로 보조기억장치는 운영 체제, 프로그램 등과 같은 데이터를 장기간 보관하고자 할 때 사용된다. 대표적으로 하드 드라이브(Hard Disk Drive, HDD), SSD(Solid State Drive)가 있다.
버스 🚌
버스는 컴퓨터 부품과 부품 사이 또는 컴퓨터와 컴퓨터 사이에 신호를 전송하는 통로를 말한다. 대표적으로 데이터가 이동하는 데이터 버스(Data Bus), 주소를 지정하는 주소 버스(Address Bus), 읽기/쓰기를 제어하는 제어 버스(Control Bus)가 있다. 이외에도 랜선이나 데이터 전송 소프트웨어, 프로토콜 등도 버스라고 불린다.
💡기억장치가 있는데 CPU안에 레지스터가 왜 필요할까?
CPU는 굉장히 빠른 속도로 연산을 처리하는데, 이를 위해 데이터의 빠른 교환이 필요하다.
예를 들어 사탕을 1초에 100개 생산하는 기계가 있다고 가정해 보자. 만약 이 기계에 초당 100개의 재료를 공급하지 못한다면, 재료가 공급될 때까지 대기해야 하므로 최대의 생산효율을 달성할 수 없다. 또한 완성된 사탕을 초당 100개씩 가져가지 못한다면, 결국 기계 앞에 사탕이 쌓여서 생산을 중단해야 하는 상황을 맞게 된다.
이처럼 CPU도 필요한 데이터를 빠르게 공급하고, 반출할 수 있어야 자신의 효율을 제대로 발휘할 수 있다. 그런데 CPU의 연산속도가 기억장치와의 데이터 교환속도보다 압도적으로 빠르기 때문에, 기억장치만을 사용하면 병목현상이 발생한다. 따라서 CPU는 교환속도를 획기적으로 단축하기 위해 레지스터와 캐시라는 저장장치를 내부에 갖고 있는 것이다.
명령어 집합 구조(Instruction Set Architecture, ISA)란 CPU가 해석하는 명령어의 집합을 의미한다. 프로그램은 기계어로 이루어져 있는데, 프로그램을 실행하면 이 명령어들을 CPU가 읽고 처리한다.
ISA는 IA-32, x86-64(x64), MIPS, AVR 등 다양하게 존재한다. 이렇게 다양한 ISA가 개발되고 사용되는 이유는 모든 컴퓨터가 동일한 수준의 연산 능력을 요구하지 않으며, 컴퓨팅 환경도 다양하기 때문이다.
예를 들어, 인텔의 x86-64는 고성능 프로세서를 설계하기 위해 사용된다. 이를 기반으로 한 CPU들은 많은 전력을 소모하며, 발열도 상대적으로 심하다. 그러므로 안정적으로 전력을 공급할 수 있고, 냉각 장치를 구비하는데 공간상의 부담이 크지 않은 데스크톱 또는 랩톱에 적합하다. 그러나 드론과 같이 배터리를 사용하거나 공유기, 인공지능 스피커처럼 크기가 작은 임베디드 기기들은 이러한 제약조건을 해결하기 어렵다. 특히 스마트폰은 피부에 닿기 때문에 발열 문제에 민감하고, 배터리도 작동하므로 인텔의 고성능 프로세서를 장착하기 매우 부적합하다. 그래서 많은 임베디드 장비들은 전력 소모와 발열이 적은 ARM이나 MIPS 또는 AVR의 프로세서를 사용하고 있다.
많은 아키텍처 중에서 이 포스팅에선 x86-64아키텍처만을 대상으로 하는데, 그 이유는 오른쪽 원형 그래프에서 볼 수 있듯, 인텔의 x86기만 CPU의 점유율이 압도적이기 때문이다. 이 입문용 포스팅에서는 가장 범용적인 x64아키텍처를 대상으로 시스템해킹의 기본 개념을 소개할 것이고, 이들을 다른 아키텍처에 적용하는 방법은 다른 심화 내용에서 다루도록 하겠다.
x64 아키텍처는 인텔의 64비트 CPU 아키텍처이다. 인텔의 32비트 CPU 아키텍처인 IA-32를 64비트 환경에서 사용할 수 있도록 확장한 것으로, 대다수의 개인용 컴퓨터들이 인텔의 x64 CPU를 사용하고 있다.
n비트 아키텍처
위의 '64비트 아키텍처', '32비트 아키텍처'에서 64와 32는 CPU가 한번에 처리할 수 있는 데이터의 크기이다.
컴퓨터 과학에서는 이를 CPU가 이해할 수 있는 데이터의 단위라는 의미에서 WORD라고 부른다. WORD의 크기는 CPU가 어떻게 설계됐느냐에 따라 달라진다. 예를 들어, 일반적인 32비트 아키텍처에서 ALU는 32비트까지 계산할 수 있으며, 레지스터의 용량 및 각종 버스들의 대역폭이 32비트이다. 따라서 이들로 구성된 CPU는 설계 상 32비트의 데이터까지만 처리할 수 있게 된다.
WORD가 크면 유리한 점
현대의 PC는 대부분 64비트 아키텍처의 CPU를 사용하는데, 그 이유 중 하나는 32비트 아키텍처의 CPU가 제공할 수 있는 가상메모리의 크기가 작기 때문이다. 가상메모리는 CPU가 프로세스에게 제공하는 가상의 메모리 공간인다. 32비트 아키텍처에서는 4,294,967,296바이트(=4기가 바이트)가 최대호 제공 가능한 가상메모리의 크기이다. 일상적으로 사용하기에는 적절할 수 있지만, 많은 메모리 자원을 소모하는 전문 소프트웨어나 고사양의 게임 등을 실행할 때는 부족할 수 있다.
반면 64비트 아키텍처에서는 이론상 16엑사바이트(=16,777,216 테라바이트)의 가상메모리를 제공할 수 있다. 이는 웬만해서는 완전한 사용이 불가능할 정도로 큰 크기이기 깨문에, 가용한 메모리의 자원이 부족해서 소프트웨어의 최고 성능을 낼 수 없다거나 소프트웨어의 실행이 불가능한 상황은 거의 발생하지 않는다.
레지스터는 CPU가 데이터를 빠르게 저장하고 사용할 때 이용하는 보관소이며, 산술 연산에 필요한 데이터를 저장하거나 주소를 저장하고 참조하는 등 다양한 용도로 사용된다. x64 아키텍처에는 범용 레지스터(General Register), 세그먼트 레지스터(Segment Register), 명령어 포인터 레지스터(Instruction Pointer Register, IP), 플래스 레지스터(Flag Register)가 존재한다.
x64 아키텍처에는 cs, ss, ds, es, fs, gs 총 6가지 세그먼트 레지스터가 존재하며, 각 레지스터의 크기는 16비트이다. 세그먼트 레지스터는 x64로 아키텍처가 확장되면서 용도에 큰 변화가 생긴 레지스터이다.
과거 IA-32, IA-16에서는 세그먼트 레지스터를 이용하여 사용 가능한 물리 메모리의 크기를 키우려고 했다. 예를 들어 IA-16에서는, 어떤 주소를 cs:offset라고 한다면, 실제로는 cs<<4 + offset의 주소를 사용하여 16비트 범위에서 접근할 수 없는 주소에 접근할 수 있었다. 당시에는 범용 레지스터의 크기가 작아서 사용 가능한 메모리의 주소 폭이 좁았지만, x64에서는 사용 가능한 주소 영역이 굉장히 넓기 때문에 이런 용도로는 거의 사용되지 않았다.
현대의 x64에서 cs, ds, ss 레지스터는 코드 영역과 데이터, 스택 메모리 영역을 가리킬 때 사용되고, 나머지 레지스터는 운영체제 별로 용도를 결정할 수 있도록 범용적인 용도로 제작된 세그먼트 레지스터이다.
플래스 레지스터는 프로세서의 현재 상태를 저장하고 있는 레지스터이다. x64 아키텍처에서는 RFLAGS라고 불리는 64비트 크기의 플래그 레지스터가 존재하며, 과거 16비트 플래스 레지스터가 확장된 것이다. 깃발을 올리고, 내리는 행위로 신호를 전달하듯, 플래그 레지스터는 자신을 구성하는 여러 비트들로 CPU의 현재 상태를 표현한다.
RFLAGS는 64비트이므로 최대 64개의 플래그를 사용할 수 있지만, 실제로는 아래쪽의 20여개의 비트만 사용한다.
그리고 이 중에서도 앞으로 주로 접하게 될 것들은 아래와 같다.
플래그
의미
CF(Carry Flag)
부호 없는 수의 연산 결과가 비트의 범위를 넘을 경우 설정 된다.
ZF(Zero Flag)
연산의 결과가 0일 경우 설정 된다.
SF(Sign Flag)
연산의 결과가 음수일 경우 설정 된다.
OF(Overflow Flag)
부호 있는 수의 연산 결과가 비트 범위를 넘을 경우 설정 된다.
플래그를 사용하는 간단한 예로, 3의 값을 갖는 a와 5의 값을 갖는 b가 있을 때, a에서 b를 빼는 연산을 하면, 연산의 결과가 음수이므로 SF가 설정된다. 그러면 CPU는 SF를 통해 a가 b보다 작았음을 알 수 있다.
위에서 x86-64 아키텍처는 IA-32의 64비트 확장 아키텍처이며, 호환이 가능하다고 했다. IA-32에서 CPU의 레지스터들은 32비트 크기를 가지며, 이들의 명칭은 각각 eax, ebx, ecx, edx, esi, edi, esp, ebp였다. 호환성을 위해 이 레지스터들은 x86-64에서도 그대로 사용이 가능하다.
앞서 소개한 rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp가 이들의 확장된 형태이며, eax, ebx 등은 확장된 레지스터의 하위 32비트를 가르킨다. 예를 들어, eax는 rax의 하위 32비트를 의미한다.
또한 마찬가지로 과거 16비트 아키텍처인 IA-16과의 호환을 위해 ax, bx, cx, dx, si, di, sp, bp는 eax, ebx, ecx, edx, esi, edi, esp ,ebp의 하위 16비트를 가르킨다.
이들 중 몇몇은 다시 상위 8비트, 하위 8비트로 나뉘는데 이들 전체에 대한 내용은 아래쪽 그림에서 확인할 수 있다.
이번에는 컴퓨터 구조와 명령어 집합구조, 인텔의 x86-64에 대해 간단히 살펴볼 것이다.
컴퓨터는 각자 다른 기능을 수행하는 여러 부품들의 도움으로 작동한다. CPU는 컴퓨터의 작동에 핵심이 되는 연산을 처리하고, 저장장치는 데이터를 저장한다. 이 외에도 GPU는 그래픽 데이터를, 랜카드는 네트워크 통신을, 사운드 카드는 소리 데이터를 처리하는 것에 특화되어 있다. 각 부품들은 특징이 뚜렷하여 컴퓨터에서 고유의 기능을 수행한다.
이처럼 서로 다은 부품들이 모여서 '컴퓨터'라는 하나의 기계로서 작동할 수 있는 것은 컴퓨터에 대한 기본 설계가 존재하기 때문이다. 이러한 설계를 '컴퓨터 구조(Computer Architecture)'라고 부른다.
전체적인 컴퓨터 구조 중에서 특히 CPU가 사용하는 명령어와 관련된 설계를 명령어 집합구조(Instruction Set Architecture, ISA)라고 하는데, 가장 널리 사용되는 ISA 중 하나가 인텔의 x86-64 아키텍처를 대상으로 작성됐다.
시스템 해킹 공부를 시작하는 시점에서, 컴퓨터 구조 및 x86-64에 대한 이해는 앞으로의 학습에 중요한 기초 지식이 될 것이다. 그러나 이를 암기하려고 하기보다는 큰 줄기를 살펴본다는 생각으로 가볍게 훑어볼 것을 추천한다.
초기 컴퓨터 과학자 중 한명인 폰 노이만은 컴퓨터에 연산, 제어, 저장의 세 가지 핵심 기능이 필요하다고 생각했다. 근대의 컴퓨터는 연산과 제어를 위해 중앙처리장치(Central Processing Unit, CPU)를, 저장을 위해 기억장치(memory)를 사용한다. 그리고 장치간에 데이터나 제어 신호를 교환할 수 있도록 버스(bus)라는 전자 통로를 사용한다.
중앙처리장치🧠
CPU는 프로그램의 연산을 처리하고 시스템을 관리하는 컴퓨터의 두뇌이다. 프로세스의 코드를 불러오고, 실행하고, 결과를 저장하는 일련의 모든 과정이 CPU에서 일어난다.
CPU는 산술/논리 연산을 처리하는 산술논리장치(Arithmetic Logic Unit, ALU)와 CPU를 제어하는 제어장치(Control Unit), CPU에 필요한 데이터를 저장하는 레지스터(Register) 등으로 구성된다.
기억장치 💾
기억장치는 컴퓨터가 동작하는데 필요한 여러 데이터를 저장하기 위해 사용되며, 용도에 따라 주기억장치와 보조기억장치로 분류된다. 주기억장치는 프로그램 실행과정에서 필요한 데이터들을 임시로 저장하기 위해 사용되며, 대표적으로 램(Random-Access Memory, RAM)이 있다. 이와 반대로 보조기억장치는 운영 체제, 프로그램 등과 같은 데이터를 장기간 보관하고자 할 때 사용된다. 대표적으로 하드 드라이브(Hard Disk Drive, HDD), SSD(Solid State Drive)가 있다.
버스 🚌
버스는 컴퓨터 부품과 부품 사이 또는 컴퓨터와 컴퓨터 사이에 신호를 전송하는 통로를 말한다. 대표적으로 데이터가 이동하는 데이터 버스(Data Bus), 주소를 지정하는 주소 버스(Address Bus), 읽기/쓰기를 제어하는 제어 버스(Control Bus)가 있다. 이외에도 랜선이나 데이터 전송 소프트웨어, 프로토콜 등도 버스라고 불린다.
💡기억장치가 있는데 CPU안에 레지스터가 왜 필요할까?
CPU는 굉장히 빠른 속도로 연산을 처리하는데, 이를 위해 데이터의 빠른 교환이 필요하다.
예를 들어 사탕을 1초에 100개 생산하는 기계가 있다고 가정해 보자. 만약 이 기계에 초당 100개의 재료를 공급하지 못한다면, 재료가 공급될 때까지 대기해야 하므로 최대의 생산효율을 달성할 수 없다. 또한 완성된 사탕을 초당 100개씩 가져가지 못한다면, 결국 기계 앞에 사탕이 쌓여서 생산을 중단해야 하는 상황을 맞게 된다.
이처럼 CPU도 필요한 데이터를 빠르게 공급하고, 반출할 수 있어야 자신의 효율을 제대로 발휘할 수 있다. 그런데 CPU의 연산속도가 기억장치와의 데이터 교환속도보다 압도적으로 빠르기 때문에, 기억장치만을 사용하면 병목현상이 발생한다. 따라서 CPU는 교환속도를 획기적으로 단축하기 위해 레지스터와 캐시라는 저장장치를 내부에 갖고 있는 것이다.
명령어 집합 구조(Instruction Set Architecture, ISA)란 CPU가 해석하는 명령어의 집합을 의미한다. 프로그램은 기계어로 이루어져 있는데, 프로그램을 실행하면 이 명령어들을 CPU가 읽고 처리한다.
ISA는 IA-32, x86-64(x64), MIPS, AVR 등 다양하게 존재한다. 이렇게 다양한 ISA가 개발되고 사용되는 이유는 모든 컴퓨터가 동일한 수준의 연산 능력을 요구하지 않으며, 컴퓨팅 환경도 다양하기 때문이다.
예를 들어, 인텔의 x86-64는 고성능 프로세서를 설계하기 위해 사용된다. 이를 기반으로 한 CPU들은 많은 전력을 소모하며, 발열도 상대적으로 심하다. 그러므로 안정적으로 전력을 공급할 수 있고, 냉각 장치를 구비하는데 공간상의 부담이 크지 않은 데스크톱 또는 랩톱에 적합하다. 그러나 드론과 같이 배터리를 사용하거나 공유기, 인공지능 스피커처럼 크기가 작은 임베디드 기기들은 이러한 제약조건을 해결하기 어렵다. 특히 스마트폰은 피부에 닿기 때문에 발열 문제에 민감하고, 배터리도 작동하므로 인텔의 고성능 프로세서를 장착하기 매우 부적합하다. 그래서 많은 임베디드 장비들은 전력 소모와 발열이 적은 ARM이나 MIPS 또는 AVR의 프로세서를 사용하고 있다.
많은 아키텍처 중에서 이 포스팅에선 x86-64아키텍처만을 대상으로 하는데, 그 이유는 오른쪽 원형 그래프에서 볼 수 있듯, 인텔의 x86기만 CPU의 점유율이 압도적이기 때문이다. 이 입문용 포스팅에서는 가장 범용적인 x64아키텍처를 대상으로 시스템해킹의 기본 개념을 소개할 것이고, 이들을 다른 아키텍처에 적용하는 방법은 다른 심화 내용에서 다루도록 하겠다.
x64 아키텍처는 인텔의 64비트 CPU 아키텍처이다. 인텔의 32비트 CPU 아키텍처인 IA-32를 64비트 환경에서 사용할 수 있도록 확장한 것으로, 대다수의 개인용 컴퓨터들이 인텔의 x64 CPU를 사용하고 있다.
n비트 아키텍처
위의 '64비트 아키텍처', '32비트 아키텍처'에서 64와 32는 CPU가 한번에 처리할 수 있는 데이터의 크기이다.
컴퓨터 과학에서는 이를 CPU가 이해할 수 있는 데이터의 단위라는 의미에서 WORD라고 부른다. WORD의 크기는 CPU가 어떻게 설계됐느냐에 따라 달라진다. 예를 들어, 일반적인 32비트 아키텍처에서 ALU는 32비트까지 계산할 수 있으며, 레지스터의 용량 및 각종 버스들의 대역폭이 32비트이다. 따라서 이들로 구성된 CPU는 설계 상 32비트의 데이터까지만 처리할 수 있게 된다.
WORD가 크면 유리한 점
현대의 PC는 대부분 64비트 아키텍처의 CPU를 사용하는데, 그 이유 중 하나는 32비트 아키텍처의 CPU가 제공할 수 있는 가상메모리의 크기가 작기 때문이다. 가상메모리는 CPU가 프로세스에게 제공하는 가상의 메모리 공간인다. 32비트 아키텍처에서는 4,294,967,296바이트(=4기가 바이트)가 최대호 제공 가능한 가상메모리의 크기이다. 일상적으로 사용하기에는 적절할 수 있지만, 많은 메모리 자원을 소모하는 전문 소프트웨어나 고사양의 게임 등을 실행할 때는 부족할 수 있다.
반면 64비트 아키텍처에서는 이론상 16엑사바이트(=16,777,216 테라바이트)의 가상메모리를 제공할 수 있다. 이는 웬만해서는 완전한 사용이 불가능할 정도로 큰 크기이기 깨문에, 가용한 메모리의 자원이 부족해서 소프트웨어의 최고 성능을 낼 수 없다거나 소프트웨어의 실행이 불가능한 상황은 거의 발생하지 않는다.
레지스터는 CPU가 데이터를 빠르게 저장하고 사용할 때 이용하는 보관소이며, 산술 연산에 필요한 데이터를 저장하거나 주소를 저장하고 참조하는 등 다양한 용도로 사용된다. x64 아키텍처에는 범용 레지스터(General Register), 세그먼트 레지스터(Segment Register), 명령어 포인터 레지스터(Instruction Pointer Register, IP), 플래스 레지스터(Flag Register)가 존재한다.
x64 아키텍처에는 cs, ss, ds, es, fs, gs 총 6가지 세그먼트 레지스터가 존재하며, 각 레지스터의 크기는 16비트이다. 세그먼트 레지스터는 x64로 아키텍처가 확장되면서 용도에 큰 변화가 생긴 레지스터이다.
과거 IA-32, IA-16에서는 세그먼트 레지스터를 이용하여 사용 가능한 물리 메모리의 크기를 키우려고 했다. 예를 들어 IA-16에서는, 어떤 주소를 cs:offset라고 한다면, 실제로는 cs<<4 + offset의 주소를 사용하여 16비트 범위에서 접근할 수 없는 주소에 접근할 수 있었다. 당시에는 범용 레지스터의 크기가 작아서 사용 가능한 메모리의 주소 폭이 좁았지만, x64에서는 사용 가능한 주소 영역이 굉장히 넓기 때문에 이런 용도로는 거의 사용되지 않았다.
현대의 x64에서 cs, ds, ss 레지스터는 코드 영역과 데이터, 스택 메모리 영역을 가리킬 때 사용되고, 나머지 레지스터는 운영체제 별로 용도를 결정할 수 있도록 범용적인 용도로 제작된 세그먼트 레지스터이다.
플래스 레지스터는 프로세서의 현재 상태를 저장하고 있는 레지스터이다. x64 아키텍처에서는 RFLAGS라고 불리는 64비트 크기의 플래그 레지스터가 존재하며, 과거 16비트 플래스 레지스터가 확장된 것이다. 깃발을 올리고, 내리는 행위로 신호를 전달하듯, 플래그 레지스터는 자신을 구성하는 여러 비트들로 CPU의 현재 상태를 표현한다.
RFLAGS는 64비트이므로 최대 64개의 플래그를 사용할 수 있지만, 실제로는 아래쪽의 20여개의 비트만 사용한다.
그리고 이 중에서도 앞으로 주로 접하게 될 것들은 아래와 같다.
플래그
의미
CF(Carry Flag)
부호 없는 수의 연산 결과가 비트의 범위를 넘을 경우 설정 된다.
ZF(Zero Flag)
연산의 결과가 0일 경우 설정 된다.
SF(Sign Flag)
연산의 결과가 음수일 경우 설정 된다.
OF(Overflow Flag)
부호 있는 수의 연산 결과가 비트 범위를 넘을 경우 설정 된다.
플래그를 사용하는 간단한 예로, 3의 값을 갖는 a와 5의 값을 갖는 b가 있을 때, a에서 b를 빼는 연산을 하면, 연산의 결과가 음수이므로 SF가 설정된다. 그러면 CPU는 SF를 통해 a가 b보다 작았음을 알 수 있다.
위에서 x86-64 아키텍처는 IA-32의 64비트 확장 아키텍처이며, 호환이 가능하다고 했다. IA-32에서 CPU의 레지스터들은 32비트 크기를 가지며, 이들의 명칭은 각각 eax, ebx, ecx, edx, esi, edi, esp, ebp였다. 호환성을 위해 이 레지스터들은 x86-64에서도 그대로 사용이 가능하다.
앞서 소개한 rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp가 이들의 확장된 형태이며, eax, ebx 등은 확장된 레지스터의 하위 32비트를 가르킨다. 예를 들어, eax는 rax의 하위 32비트를 의미한다.
또한 마찬가지로 과거 16비트 아키텍처인 IA-16과의 호환을 위해 ax, bx, cx, dx, si, di, sp, bp는 eax, ebx, ecx, edx, esi, edi, esp ,ebp의 하위 16비트를 가르킨다.
이들 중 몇몇은 다시 상위 8비트, 하위 8비트로 나뉘는데 이들 전체에 대한 내용은 아래쪽 그림에서 확인할 수 있다.