크래프톤 정글 (컴퓨터 시스템: CSAPP)/3장 프로그램의 기계수준 표현

컴퓨터 시스템 : CSAPP 3장 정리 - 3.6 장 제어문 Part.1

고웅 2025. 4. 5. 14:57

📘 3장 6절 도입부: "제어(컨트롤)"

우리가 컴퓨터한테 “이거 해!” 하고 명령을 내릴 때, 컴퓨터는 순서대로 차례차례 그 명령들을 따라 한다. 그런데 어떤 때는 "만약 이 조건이 맞으면 이걸 하고, 아니면 저걸 해!"라고 조건을 걸 수도 있다. 마치 게임에서 “보스를 이기면 다음 스테이지로 가고, 아니면 다시 도전하기” 같은 것이다.

이렇게 "조건에 따라 행동을 다르게 하기"를 제어 흐름(control flow)이라고 한다. 그리고 컴퓨터는 점프(jump)라는 특별한 명령을 써서 이 흐름을 바꾼다. “여기서 저기로 점프!”라고 말이다.


🧠 3.6.1절 - 조건 코드 (Condition Codes): 컴퓨터가 생각하는 방법

컴퓨터는 계산을 한 다음, 그 결과에 대해서 “이건 0인가?”, “음수인가?”, “넘쳐버렸나?” 같은 정보를 작은 불빛(1비트짜리 스위치)처럼 저장해 놓는다. 이걸 조건 코드(Condition Codes)라고 한다.

이 조건 코드에는 네 가지가 있다:

  1. CF (Carry Flag) – "계산하다가 넘쳐서 옆으로 새어 나갔어!" → unsigned 덧셈에서 넘쳤는지 체크
  2. ZF (Zero Flag) – "결과가 0이야!"
  3. SF (Sign Flag) – "결과가 음수야!" → 앞에 '-'가 붙는 숫자
  4. OF (Overflow Flag) – "너무 커져서 표현할 수 없는 숫자가 됐어!" → signed 숫자에서 넘쳤는지 확인

예를 들어, a랑 b를 더해서 t를 만든다고 할 때:

  • CF는: t가 a보다 작으면 "오! 넘쳤네?" (unsigned 계산 기준)
  • ZF는: t가 0이면 "오! 0이 나왔어!"
  • SF는: t가 음수면 "이건 마이너스야!"
  • OF는: a랑 b가 둘 다 양수(또는 음수)인데 결과 t가 음수가 되면 "이건 진짜 넘쳤다!"​.

이 조건 코드는 다음 명령을 "할까? 말까?" 결정할 때 사용되는데. 예를 들면, “이 값이 0이면 저기로 점프해!” 같은 명령을 가능하게 만든다


🔍 비교(compare) 명령어: "누가 더 크지?"

  • cmp 명령어는 두 숫자를 비교해서 "누가 더 크지? 같나? 작나?"를 판단한다.
  • 예를 들어 cmp a, b는 실제로는 b - a를 계산하는 것과 같다. 하지만 이 결괏값을 어디에 저장하진 않고, 대신에 결과를 바탕으로 조건 코드를 설정한다.

이걸 바탕으로 컴퓨터는 "어떤 조건이 맞는가?"를 판단할 수 있다. 예를 들면:

  • 결과가 0이면: 같다
  • 결과가 음수면: 앞에 있는 숫자가 더 작다
  • 결과가 양수면: 앞에 있는 숫자가 더 크다

🧪 시험(test) 명령어: "이 안에 뭐가 있을까?"

  • test 명령어는 a & b (비트 AND 연산)을 해보는 것이다.
  • AND 연산은 숫자의 각 비트(0과 1)를 비교해서 둘 다 1인 자리만 1로 남기는 것이다.
  • 이 결과로 조건 코드가 설정된다.

예를 들어 testq %rax, %rax는 자기 자신을 검사하는 것이다.

  • 이 결과가 0이면: 이 값은 “0이다.”
  • 음수면: “이건 마이너스 숫자”

즉, 값이 0인지, 음수인지, 양수인지 등을 알아볼 수 있는 도구이다.

 

🎯 중요한 점!

  • 이 cmp와 test 명령어는 아무 값도 바꾸지 않고 그냥 “판단만” 한다.
  • 대신 조건 코드를 이용해서 나중에 점프하거나, 어떤 작업을 할지 결정하는 데 쓰인다.

쉽게 말해,

  • cmp는 "누가 더 크니?" 하고 비교하기,
  • test는 "이 값 안에 어떤 특성이 있을까?" 하고 검사하기.

🧠 3.6.2절 -  조건 코드 사용하기(Accessing the Condition Codes)

컴퓨터는 조건 코드를 가지고 판단을 한다 그럼 이제는 그 조건들을 어떻게 사용하는지 배워보겠다 아래 세 가지 방법이 있다:


1️⃣ 조건을 이용해서 0 또는 1 만들기 (set 명령어)

  • 예를 들어, 컴퓨터가 “이 값이 0이야?”라고 조건을 검사한 다음, 참이면 1, 거짓이면 0을 저장한다.
  • 이걸 해주는 게 set으로 시작하는 명령어들이다

예시:

  • sete는 같으면 1 (equal)
  • setne는 다르면 1 (not equal)
  • setl은 작으면 1 (signed <)
  • setg는 크면 1 (signed >)
  • setb는 unsigned에서 작으면 1 (below)

이렇게 각각의 조건마다 다른 set 명령어가 있다.

명령어 의미 조건 코드 의미
sete 같을 때 1 (equal) ZF = 1
setne 다를 때 1 (not equal) ZF = 0
setl 작을 때 1 (signed) SF ≠ OF
setle 작거나 같을 때 1 ZF = 1 or SF ≠ OF
setg 클 때 1 (signed) ZF = 0 and SF = OF
setge 크거나 같을 때 1 SF = OF
setb 작을 때 1 (unsigned) CF = 1
setbe 작거나 같을 때 1 (unsigned) CF = 1 or ZF = 1
seta 클 때 1 (unsigned) CF = 0 and ZF = 0
setae 크거나 같을 때 1 (unsigned) CF = 0

2️⃣ 조건에 따라 “점프”하기 (jump 명령어)

  • 컴퓨터는 “만약 조건이 맞다면, 저기 있는 명령어로 점프하자!”라고 할 수 있다.
  • 마치 보드게임에서 “특정 숫자가 나오면 뒤로 3칸 가기!” 같은 느낌이다.

예:

  • je = 같으면 점프 (jump if equal)
  • jne = 다르면 점프 (jump if not equal)

3️⃣ 조건에 따라 값 옮기기 (conditional move)

  • “이 조건이 맞으면 저 값으로 바꾸자!”라는 식이다.
  • 예를 들어, 두 숫자 중 더 큰 숫자를 선택할 때 사용할 수 있다.

예시:

  • cmovg = 값이 크면 복사 (move if greater)
  • cmove = 값이 같으면 복사

조건이 맞을 때만 값을 옮기고, 아니면 그냥 가만히 있는다

방법 설명
set 명령어 조건에 따라 0 또는 1 저장 setl, sete 등
jump 명령어 조건에 따라 명령어 점프 je, jne 등
move 명령어 조건에 따라 값 복사 cmovg, cmove 등

🧠 3.6.3절 - Jump Instructions (점프 명령어)

🪂 점프(Jump) 명령어란?

보통 컴퓨터는 명령어를 한 줄씩 순서대로 실행한다. 하지만 어떤 상황에서는 “이제 이 줄은 건너뛰고, 저기로 가자!” 하고 점프할 수 있다.
마치 보드게임에서 "지금 이 칸에서 저 칸으로 바로 이동!" 하는 거랑 비슷하다.

🧠 점프에는 두 가지 종류가 있다

1️⃣ 무조건 점프 (Unconditional Jump)

  • 그냥 무조건! 조건 없이 바로 점프한다.
  • 명령어: jmp label

예:

jmp finish   ; finish라는 이름의 위치로 바로 이동한다

2️⃣ 조건부 점프 (Conditional Jump)

  • 어떤 조건이 맞을 때만 점프한다
  • 조건은 위에서 배운 조건 코드를 이용해 검사한다.

예:

cmpq %rsi, %rdi
jge L2       ; 만약 %rdi가 %rsi보다 크거나 같으면 L2로 점프한다

🧾 자주 쓰이는 조건부 점프들 (조건별로 정리)

명령어 조건 코드 의미
je 또는 jz 같으면 점프 ZF = 1
jne 또는 jnz 다르면 점프 ZF = 0
jg (signed) 더 크면 점프 ~(SF ^ OF) & ~ZF
jge (signed) 크거나 같으면 점프 ~(SF ^ OF)
jl (signed) 작으면 점프 SF ^ OF
jle (signed) 작거나 같으면 점프 (SF ^ OF) | ZF
ja (unsigned) 크면 점프 ~CF & ~ZF
jb (unsigned) 작으면 점프 CF = 1
jbe (unsigned) 작거나 같으면 점프 CF | ZF

🏷️ 점프는 라벨(label)로 이동한다

  • 점프하려는 곳에는 이름표(label) 를 달아놔야 한다.
  • 예:
.L1:           ; 여기가 점프 도착지이다.
movq %rax, %rbx

🧪 예시 코드로 보기

asm
복사
movq $0, %rax     ; %rax에 0을 넣고
jmp .L1           ; .L1로 점프한다

movq (%rax), %rdx ; 이부분은 건너뛰어진다.

.L1:
popq %rdx         ; 여기가 점프한 위치이다.
  • 여기서는 jmp 때문에 movq (%rax), %rdx는 실행되지 않고 넘어간다
  • 대신 .L1:로 점프해서 popq %rdx부터 실행해요​.

🧠 3.6.4절 - 점프 인스트럭션 인코딩(Jump Instruction Encodings)

💡 점프 명령어는 컴퓨터가 "어디로 갈지" 알려줘야 한다

어셈블리 코드에서는 점프 명령어를 jmp .L1 같은 식으로 사용한다. 여기서 .L1은 라벨(label), 즉 “어디로 갈지 정한 이름표”이다.
하지만 실제 컴퓨터 속에서는 이 .L1 같은 이름이 없고, 대신 숫자 주소로 바뀌어야 한다. 이걸 인코딩(encoding) 한다고 한다.


🔢 점프 인코딩 방식 두 가지

1️⃣ PC 상대 주소 (PC-relative)

  • 가장 많이 쓰이는 방법이다!
  • "점프할 주소와 다음 명령어의 차이”를 저장한다.
  • 그 차이를 1, 2, 또는 4 바이트로 표현할 수 있다.
  • 이 방식은 프로그램이 다른 위치로 옮겨져도 자동으로 작동돼서 아주 편리하다

예:

jmp .L2   ; 현재 위치보다 3바이트 뒤에 있는 .L2로 점프한다

이때는 0x03이라는 값이 인코딩된다.


2️⃣ 절대 주소 (Absolute Address)

  • 이건 점프할 정확한 주소를 직접 4바이트로 기록하는 방식이다.
  • PC-relative 방식보다 좀 더 딱딱한 방식이고, 이동성은 떨어진다.

🧪 실제 예시 보기

다음은 C 파일을 컴파일해서 나온 어셈블리 코드 일부이다.

1  movq %rdi, %rax
2  jmp .L2
3 .L3:
4  sarq %rax
5 .L2:
6  testq %rax, %rax
7  jg .L3
8  rep; ret

이걸 기계어로 보면:

0: 48 89 f8       ; mov
3: eb 03          ; jmp .L2 (현재+3바이트)
5: 48 d1 f8       ; sar
8: 48 85 c0       ; test
b: 7f f8          ; jg .L3 (현재 - 8바이트로 뒤로 점프)
d: f3 c3          ; repz ret

여기서 jmp는 eb 03, 즉 “다음 명령에서 +3바이트”라는 뜻이고, jg는 7f f8, 즉 “-8바이트” 점프이다.


🎯 핵심 요약!

  • 점프 명령어는 컴퓨터한테 어디로 점프할지 알려줘야 한다.
  • 그 주소는 보통 현재 위치 기준으로 상대적으로 저장(PC-relative) 한다.
  • 이렇게 하면 프로그램이 옮겨져도 점프가 잘 작동된다.