CMP
explain
CMP (Compare)는 어셈블리어 코드를 열었을 때 가장 압도적으로 많이 보게 되는 보편적인 명령어입니다. 우리가 C언어나 C#, 파이썬 등에서 작성하는 모든 if (a == b), if (a > b) 같은 조건문들은 컴퓨터 내부에서 99% 이 CMP 명령어로 번역되어 실행됩니다. 그렇다면 이 주인공 CMP가 어떻게 작동하고, 왜 그렇게 많이 쓰이는지 깔끔하게 정리해 드릴게요!
1. CMP 명령어의 본질: “결과를 저장하지 않는 빼기”
CMP 명령어의 작동 원리는 아주 단순합니다. “첫 번째 값에서 두 번째 값을 빼보는 것(Subtraction)”입니다.
CMP X1, X2 ; 내부적으로 X1 - X2 를 계산함
여기서 가장 중요한 핵심은, 뺄셈을 하긴 하지만 계산된 결과값(X1 - X2의 값)을 레지스터에 저장하지 않는다는 점입니다. 오직 뺄셈을 했을 때 생기는 CPU의 상태 플래그(NZCV)만 업데이트하고 결과 숫자는 버립니다. 원본 데이터인 X1과 X2 값을 그대로 유지하기 위해서죠.
2. 내부 작동 메커니즘 (수학적 원리)
컴퓨터는 X1 - X2를 계산한 뒤, CPU 안에 있는 상태 플래그를 보고 두 수의 관계를 알아냅니다.
- 결과가 0인 경우 (X1 == X2)
- 두 수가 같다면 빼서 0이 되겠죠? 이때 Z (Zero) 플래그가 1이 됩니다.
- 결과가 음수인 경우 (X1 < X2)
- 작은 수에서 큰 수를 뺐으니 음수가 나옵니다. 이때 N (Negative) 플래그가 1이 됩니다.
- 결과가 양수인 경우 (X1 > X2)
- 큰 수에서 작은 수를 뺐으니 양수가 나옵니다. 이때는 Z 플래그와 N 플래그가 모두 0이 됩니다.
하드웨어는 이처럼 단 한 번의 뺄셈 연산만으로 두 값이 같은지, 누가 더 큰지, 작은지를 완벽하게 판별해 냅니다.
3. CMP 뒤에 항상 따라붙는 “실과 바늘” (조건부 분기문)
CMP 명령어는 혼자서는 아무것도 하지 못합니다. 플래그만 바꿔놓기 때문이죠. 그래서 바로 다음 줄에 조건부 점프(분기) 명령어가 바늘처럼 항상 따라붙습니다.
| 분기 니모닉 | 의미 | CMP X1, X2 이후 작동 기준 |
|---|---|---|
| BEQ (Branch if Equal) | 두 값이 같으면 점프 | Z 플래그가 1일 때 |
| BNE (Branch if Not Equal) | 두 값이 다르면 점프 | Z 플래그가 0일 때 |
| BGT (Branch if Greater Than) | X1이 X2보다 크면 점프 | 양수일 때 |
| BLT (Branch if Less Than) | X1이 X2보다 작으면 점프 | 음수일 때 |
💻 실제 코드 매핑 예시
우리가 짜는 C언어 코드가 어셈블리로 어떻게 바뀌는지 보면 직관적으로 이해가 가실 겁니다.
- 고급 언어 (C, Java 등):
if (count == 10) { // 탈출 코드 }
- 컴파일된 어셈블리 언어:
CMP X0, #10 ; count(X0)와 10을 비교한다 (X0 - 10 수행) BEQ exit_label ; 만약 결과가 0(같다면), exit_label 위치로 점프해라!
🔄 지금까지 배운 3대 비교 명령어 총정리!
친구야, 질문 주신 흐름대로 공부하시면 하드웨어 조건문 구조는 마스터하신 거나 다름없습니다. 셋의 차이점을 한눈에 비교해 드릴게요.
- CMP (주인공 🌟): 내부적으로 뺄셈(-)을 하여 CPU 상태 플래그를 바꿈. 일반적인 모든 대소/동등 비교(if문)의 기본.
- CMN (조연 🛠️): 내부적으로 덧셈(+)을 하여 CPU 상태 플래그를 바꿈. 음수 값을 비교하거나 상수를 활용해 코드를 최적화할 때 사용.
- CMGE (특수부대 🚀): 플래그를 바꾸는 게 아니라, 레지스터 내부에 비트 마스크(0xFF.. 또는 0x00..)를 직접 채움. SIMD 기술을 이용해 대량의 데이터를 한 번에 병렬 필터링할 때 사용.