어셈블리 제어문 [ 크래프톤 정글 19일차 ]

jinsung·2025년 5월 31일
3

크래프톤 정글 9기

목록 보기
17/59

저 간단한 어셈블리어는 읽을 수 있습니다

라고 면접에서 곧 말할 수 있을 것 같다..

나 제법 멋있을지도..?

이전에 이어서

오퍼랜드데이터 이동 인스트럭션을 관련하면서 어셈블리어로 작성된 인스트럭션들이 한 줄 씩 어떻게 실행되는지 직선적인 동작을 공부 했었는데요.

C 언어에서의 반복문이나, 스위치문들은 , 연산 결과에 따라 각각 다른 연산이 실행되는 조건부 실행이 요구되는데요.

어셈블리에서 조건부 동작을 구현하기 위해서 어떤 방법을 사용하는지 알아볼까요?

부릉 가요~

  • 출처 솔로지옥

1. 조건코드

조건코드는

  • 가장 최근에 실행된 연산의 결과를 저장해요.

조건코드의 종류에는

  • ZF ( Zero Flag ) : 가장 최근의 연산 결과가 0인지
  • SF ( Sign Flag ) : 가장 최근의 연산 결과가 음수인지
  • OF ( Overflow Flag ) : 가장 최근의 연산 결과가 2의 보수 표현 오버플로우인지
  • CF ( Carry Flag ) : 가장 최근의 연산 결과가 비부호형 오버플로우인지

등등이 있어요.

이 조건코드들은 어셈블리의 ADD, SUB, XOR, INF, DEC, SAL, SAR 등등의 다양한 연산 인스트럭션들이 쓰이고 나면 그 연산 결과에 따라 저장되어요.

예를들어 ZF 는 ADD 의 결과가 0일 때 1로 바뀌겠죠?

그리고 기본적인 연산 말고
연산의 결과는 어딘가에 저장하지 않으면서
오로지 조건코드만 바꾸는 인스트럭션 명령어가 있습니다.

1-1. CMP 와 TEST

항목CMP (Compare)TEST (Bitwise Test)
목적두 값을 뺀 결과를 비교두 값을 AND 연산 후 결과를 비교
기본 연산a - ba & b
피연산자보통 서로 다른 두 값 (예: cmp a, b)보통 동일한 값이나 마스크 (예: test a, a 또는 test a, mask)
결과 저장 여부연산 결과를 저장하지 않음연산 결과를 저장하지 않음
영향을 주는 플래그ZF, SF, OF, CF 등 설정ZF, SF 등 설정 (OF, CF는 영향 없음)
자주 쓰이는 용도크기 비교 (==, <, >, 등)값이 0인지 검사 / 특정 비트 마스크 검사
예시cmp %rax, %rbxrbx - rax 비교test %rax, %rax%rax == 0 검사

CMP 와 TEST 는

두 연산의 결과를 어디에 저장하진 않구요

ZF, CF 같은 조건코드만 변경해요.

이 연산결과는 나중에 조건판별을 하는데 쓰입니다.

조건코드는 어디에 저장되어있을까요?

조건코드는 위 사진처럼 "플래그 레지스터"에 저장되어 있습니다.

플래그 레지스터의 비트번호 0번을 보시면 CF (Carry flat)가 보입니다.

잘 찾아보시면 6번에 ZF , 7번에 SF도 있네요.

이렇게 연산결과를 가지고있는 플래그레지스터를 사용해서 조건판별을 하게 됩니다.

2. 조건코드 사용하기

이렇게 조건코드가 저장되어 있는 건 봤는데요.

어떤 명령어를 통해서 이 조건코드를 사용해야 할까요?

우선, 조건코드를 사용하는데에는 총 3가지 방법이 있습니다.

1. Set
=> Set 명령어를 사용해서 0또는 1을 한 개의 바이트에 기록해요.
2. jmp
=> jmp 명령어를 사용해서 프로그램의 다른 주소로 이동하는 방법이예요.
3. cmove
=> cmove 명령어를 사용해서 데이터를 전송하는 방법이예요.

텍스트로만 보면 이해하기 어려우니까
예제를 살펴보면서 각 명령어가 정확히 어떤 역할을 하는지 이해해봐요!

3. 조건 코드의 활용 예제들

각 조건코드 사용 방법에 대한 예제를 하나씩 보면서, 어떤 연산 결과에 따라 조건적으로 어떤 일이 일어나는지 알아볼게요.

3-1. 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, %raxrax - rbx의 결과가 0이면 ZF를 1로 설정합니다.
  • sete %cl은 ZF가 1일 때 cl 레지스터에 1을 저장합니다.
  • 즉, rax == rbx일 때 cl = 1, 그렇지 않으면 cl = 0이 됩니다.

3-2. 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이 됩니다.

3-3. 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가 실제로 어떤 조건을 기준으로 플래그를 설정하고, 그 플래그를 활용해서 조건부 동작을 만드는지 감이 오셨나요?

4. 조건부 접미사 뜻

접미사의미조건 코드 조합설명
e / zequal / zeroZF == 1같을 때
ne / nznot equal / nonzeroZF == 0다를 때
ssignSF == 1결과가 음수일 때
nsnot signSF == 0결과가 양수일 때
ggreaterZF == 0 && SF == OF(signed) a > b
gegreater or equalSF == OF(signed) a >= b
llessSF != OF(signed) a < b
leless or equalZF == 1SF != OF(signed) a <= b
aaboveCF == 0 && ZF == 0(unsigned) a > b
aeabove or equalCF == 0(unsigned) a >= b
bbelowCF == 1(unsigned) a < b
bebelow or equalCF == 1ZF == 1(unsigned) a <= b

s와 j와 cmove 뒤에 붙는 접미사는 모두 공통입니다.

그래서 이 표를 보면 어떤 접미사가 어떤 조건코드를 참고하는지 알 수 있어요.

5. 실사용 예제

movq $42, %rax
movq $42, %rbx
cmp %rbx, %rax     # rax - rbx → ZF = 1
sete %cl           # ZF == 1 → cl = 1

이 어셈블리는

두 값이 같으면 1 아니면 0을 반환하는 어셈블리예요!

cmp 로 먼저 연산하고
그뒤에 setequal 을 사용해서 값을 저장해요.

회고

나... 간단한 어셈블리는 읽을 수 있다구..?

0개의 댓글