
저 간단한 어셈블리어는 읽을 수 있습니다
라고 면접에서 곧 말할 수 있을 것 같다..
나 제법 멋있을지도..?
오퍼랜드나 데이터 이동 인스트럭션을 관련하면서 어셈블리어로 작성된 인스트럭션들이 한 줄 씩 어떻게 실행되는지 직선적인 동작을 공부 했었는데요.
C 언어에서의 반복문이나, 스위치문들은 , 연산 결과에 따라 각각 다른 연산이 실행되는 조건부 실행이 요구되는데요.
어셈블리에서 조건부 동작을 구현하기 위해서 어떤 방법을 사용하는지 알아볼까요?
부릉 가요~

조건코드는
조건코드의 종류에는
등등이 있어요.
이 조건코드들은 어셈블리의 ADD, SUB, XOR, INF, DEC, SAL, SAR 등등의 다양한 연산 인스트럭션들이 쓰이고 나면 그 연산 결과에 따라 저장되어요.
예를들어 ZF 는 ADD 의 결과가 0일 때 1로 바뀌겠죠?
그리고 기본적인 연산 말고
연산의 결과는 어딘가에 저장하지 않으면서
오로지 조건코드만 바꾸는 인스트럭션 명령어가 있습니다.
| 항목 | CMP (Compare) | TEST (Bitwise Test) |
|---|---|---|
| 목적 | 두 값을 뺀 결과를 비교함 | 두 값을 AND 연산 후 결과를 비교함 |
| 기본 연산 | a - b | a & b |
| 피연산자 | 보통 서로 다른 두 값 (예: cmp a, b) | 보통 동일한 값이나 마스크 (예: test a, a 또는 test a, mask) |
| 결과 저장 여부 | 연산 결과를 저장하지 않음 | 연산 결과를 저장하지 않음 |
| 영향을 주는 플래그 | ZF, SF, OF, CF 등 설정 | ZF, SF 등 설정 (OF, CF는 영향 없음) |
| 자주 쓰이는 용도 | 크기 비교 (==, <, >, 등) | 값이 0인지 검사 / 특정 비트 마스크 검사 |
| 예시 | cmp %rax, %rbx → rbx - rax 비교 | test %rax, %rax → %rax == 0 검사 |
CMP 와 TEST 는
두 연산의 결과를 어디에 저장하진 않구요
ZF, CF 같은 조건코드만 변경해요.
이 연산결과는 나중에 조건판별을 하는데 쓰입니다.
조건코드는 어디에 저장되어있을까요?

조건코드는 위 사진처럼 "플래그 레지스터"에 저장되어 있습니다.
플래그 레지스터의 비트번호 0번을 보시면 CF (Carry flat)가 보입니다.
잘 찾아보시면 6번에 ZF , 7번에 SF도 있네요.
이렇게 연산결과를 가지고있는 플래그레지스터를 사용해서 조건판별을 하게 됩니다.
이렇게 조건코드가 저장되어 있는 건 봤는데요.
어떤 명령어를 통해서 이 조건코드를 사용해야 할까요?
우선, 조건코드를 사용하는데에는 총 3가지 방법이 있습니다.
1. Set
=> Set 명령어를 사용해서 0또는 1을 한 개의 바이트에 기록해요.
2. jmp
=> jmp 명령어를 사용해서 프로그램의 다른 주소로 이동하는 방법이예요.
3. cmove
=> cmove 명령어를 사용해서 데이터를 전송하는 방법이예요.
텍스트로만 보면 이해하기 어려우니까
예제를 살펴보면서 각 명령어가 정확히 어떤 역할을 하는지 이해해봐요!
각 조건코드 사용 방법에 대한 예제를 하나씩 보면서, 어떤 연산 결과에 따라 조건적으로 어떤 일이 일어나는지 알아볼게요.
set 명령어movq $5, %rax
movq $5, %rbx
cmp %rbx, %rax # rax - rbx => 5 - 5 = 0 → ZF = 1
sete %cl # ZF가 1이면 cl = 1
# 즉, rax == rbx 라면 cl = 1
cmp %rbx, %rax는 rax - rbx의 결과가 0이면 ZF를 1로 설정합니다.sete %cl은 ZF가 1일 때 cl 레지스터에 1을 저장합니다.rax == rbx일 때 cl = 1, 그렇지 않으면 cl = 0이 됩니다.jmp 명령어 (조건부 점프)movq $10, %rax
movq $20, %rbx
cmp %rbx, %rax # rax - rbx => 10 - 20 = -10 → SF ≠ OF, → 점프 조건 충족
jl less_label # rax < rbx 일 때 less_label 로 점프
movq $0, %rcx # 점프 안했으면 rcx = 0
jmp end_label
less_label:
movq $1, %rcx # rax < rbx 였다면 rcx = 1
end_label:
jl은 signed 비교에서 < (less than)을 의미합니다.rax < rbx일 경우 rcx = 1, 그렇지 않으면 rcx = 0이 됩니다.cmove 명령어 (조건부 데이터 이동)test %rdi, %rdi # rdi & rdi → ZF = 1 if rdi == 0
movq (%rdi), %rax # rax = *rdi
movq $0, %rdx # 대체할 기본값 ve = 0
cmove %rdx, %rax # 만약 rdi == 0 이면, rax = rdx (= 0)
test %rdi, %rdi는 rdi가 0인지 검사하는 용도로 사용됩니다.cmove %rdx, %rax는 ZF가 1일 때만 동작합니다.rdi == 0일 때 rax에 기본값 0을 대입하는 조건부 대입이 됩니다.cmove는 조건을 만족할 때만 값이 이동합니다. 만족하지 않으면 아무 일도 일어나지 않아요.
이제 cmp, test, set, jmp, cmove가 실제로 어떤 조건을 기준으로 플래그를 설정하고, 그 플래그를 활용해서 조건부 동작을 만드는지 감이 오셨나요?
| 접미사 | 의미 | 조건 코드 조합 | 설명 | ||
|---|---|---|---|---|---|
| e / z | equal / zero | ZF == 1 | 같을 때 | ||
| ne / nz | not equal / nonzero | ZF == 0 | 다를 때 | ||
| s | sign | SF == 1 | 결과가 음수일 때 | ||
| ns | not sign | SF == 0 | 결과가 양수일 때 | ||
| g | greater | ZF == 0 && SF == OF | (signed) a > b | ||
| ge | greater or equal | SF == OF | (signed) a >= b | ||
| l | less | SF != OF | (signed) a < b | ||
| le | less or equal | ZF == 1 | SF != OF | (signed) a <= b | |
| a | above | CF == 0 && ZF == 0 | (unsigned) a > b | ||
| ae | above or equal | CF == 0 | (unsigned) a >= b | ||
| b | below | CF == 1 | (unsigned) a < b | ||
| be | below or equal | CF == 1 | ZF == 1 | (unsigned) a <= b |
s와 j와 cmove 뒤에 붙는 접미사는 모두 공통입니다.
그래서 이 표를 보면 어떤 접미사가 어떤 조건코드를 참고하는지 알 수 있어요.
movq $42, %rax
movq $42, %rbx
cmp %rbx, %rax # rax - rbx → ZF = 1
sete %cl # ZF == 1 → cl = 1
이 어셈블리는
두 값이 같으면 1 아니면 0을 반환하는 어셈블리예요!
cmp 로 먼저 연산하고
그뒤에 setequal 을 사용해서 값을 저장해요.
회고
나... 간단한 어셈블리는 읽을 수 있다구..?