📘 3장 6절 도입부: "제어(컨트롤)"
우리가 컴퓨터한테 “이거 해!” 하고 명령을 내릴 때, 컴퓨터는 순서대로 차례차례 그 명령들을 따라 한다. 그런데 어떤 때는 "만약 이 조건이 맞으면 이걸 하고, 아니면 저걸 해!"라고 조건을 걸 수도 있다. 마치 게임에서 “보스를 이기면 다음 스테이지로 가고, 아니면 다시 도전하기” 같은 것이다.
이렇게 "조건에 따라 행동을 다르게 하기"를 제어 흐름(control flow)이라고 한다. 그리고 컴퓨터는 점프(jump)라는 특별한 명령을 써서 이 흐름을 바꾼다. “여기서 저기로 점프!”라고 말이다.
🧠 3.6.1절 - 조건 코드 (Condition Codes): 컴퓨터가 생각하는 방법
컴퓨터는 계산을 한 다음, 그 결과에 대해서 “이건 0인가?”, “음수인가?”, “넘쳐버렸나?” 같은 정보를 작은 불빛(1비트짜리 스위치)처럼 저장해 놓는다. 이걸 조건 코드(Condition Codes)라고 한다.
이 조건 코드에는 네 가지가 있다:
- CF (Carry Flag) – "계산하다가 넘쳐서 옆으로 새어 나갔어!" → unsigned 덧셈에서 넘쳤는지 체크
- ZF (Zero Flag) – "결과가 0이야!"
- SF (Sign Flag) – "결과가 음수야!" → 앞에 '-'가 붙는 숫자
- 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
🧪 예시 코드로 보기
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) 한다.
- 이렇게 하면 프로그램이 옮겨져도 점프가 잘 작동된다.
'크래프톤 정글 (컴퓨터 시스템: CSAPP) > 3장 프로그램의 기계수준 표현' 카테고리의 다른 글
컴퓨터 시스템 : CSAPP 3장 정리 - 3.7 프로시저 Part.1 (0) | 2025.04.06 |
---|---|
컴퓨터 시스템 : CSAPP 3장 정리 - 3.6 장 제어문 Part.2 (0) | 2025.04.05 |
컴퓨터 시스템 : CSAPP 3장 정리 - 3.5 장 산술 및 논리 연산 (0) | 2025.04.05 |
컴퓨터 시스템 : CSAPP 3장 정리 - 3.4 장 정보 접근하기 Part.3 (0) | 2025.04.05 |
컴퓨터 시스템 : CSAPP 3장 정리 - 3.4 장 정보 접근하기 Part.2 (0) | 2025.04.05 |