[Week6 - CSAPP] 3.5 ~ 3.11 - 미안하다 요약할 시간이 없다.

2025. 10. 20. 15:19CSAPP

ㅈㄱㄴ이다.

 

미안하지만 .1장을 요약할 때 마다 하루나 걸려서 너무 힘든 관계로 남은 3장은 GPT를 통해 요약했다.

 

이 못나고 게으르고 시간이 없는 필자를 용서해주면 좋겠다... 미안하다.....

 

요약은 Gpt 5 pro 모델에 프롬프트와 cs:app 3장 영문을 준 뒤에 했다.

 

3.5 산술과 논리 연산

이 장에서는 플래그(조건 코드)를 처음 만난다.
CPU는 연산을 할 때 결과를 저장할 뿐 아니라 “결과가 어떤 상태인지”도 플래그에 기록한다.

 

플래그의미
ZF 결과가 0인가?
SF 음수인가?
CF 자리올림(캐리) 발생?
OF 오버플로 발생?

예를 들어, cmpq %rax, %rbx는 실제로는 %rbx - %rax를 계산하지만 결과는 버리고,
그 대신 조건 코드만 설정한다.

이 플래그는 곧 분기(jmp, je, jne, jl...) 명령의 근거가 된다.

특이한 명령 하나:
leaq는 주소 계산용 명령이지만, 사실상 덧셈/곱셈에도 쓴다.
게다가 플래그를 건드리지 않는다.
즉, "주소 계산기"이자 “조건 안전 계산기”.


3.6 제어 흐름 (if, while, for, switch)

모든 제어문은 결국 “조건 점프”로 구현된다.

  • if문 → 조건 코드 확인 → 분기(je, jne, jl, ...)
  • while문 → 조건 검사 → 루프 본문 → 다시 점프
  • for문 → while의 변형 (초기화 + 조건 + 증감)
  • switch문점프 테이블(jump table) 사용 (케이스가 많을 때 빠름)

💡 cmov (조건부 이동) 명령은 분기 없이 결과만 바꾼다.
예측 실패로 인한 성능 하락을 줄이는 멋진 최적화 도구다.


3.7 프로시저 (함수 호출)

함수를 호출하면 호출 규약(calling convention)에 따라 인자와 반환값이 전달된다.

 

역할레지스터
인자(1~6) %rdi, %rsi, %rdx, %rcx, %r8, %r9
반환값 %rax
호출자 보존 %r10, %r11
피호출자 보존 %rbx, %rbp, %r12~%r15

call 명령은

  1. 복귀 주소를 스택에 push하고
  2. 함수 시작 지점으로 점프한다.

ret 명령은

  1. 스택에서 주소를 pop하고
  2. 그곳으로 돌아간다.

스택은 작은 주소 쪽으로 성장한다.
즉, push 하면 %rsp -= 8, pop 하면 %rsp += 8.


3.8 배열

배열은 “메모리 속에 연속된 공간”이다.
원소 a[i]의 주소는 간단하다:

 
주소 = base + (i × 원소 크기)

예:

  • (%rdi, %rsi, 4) → a[i] (int 배열의 i번째 값)
  • ((i × 열 수) + j) 계산으로 다차원 배열도 접근한다.

3.9 구조체와 공용체

C의 구조체는 멤버 순서대로 메모리에 저장되지만,
CPU가 빠르게 접근하도록 정렬(alignment) 규칙을 지킨다.
그래서 멤버 사이에 패딩(padding)이 끼어 공간이 비는 일이 있다.

예:

 
struct A { char c; // 1바이트 int i; // 4바이트 };

총 8바이트(중간에 3바이트 패딩).
멤버 순서만 바꿔도 크기가 달라진다!


3.10 제어와 데이터 결합 + 보안

C의 강력함 = 자유.
자유 = 책임.
책임 안 지면 → 버퍼 오버플로우 💣

스택에 할당된 배열을 넘치게 채우면,
리턴 주소까지 덮어쓸 수 있다.
공격자는 이를 이용해 임의 코드로 점프한다.

💥 그래서 OS는 방어막을 쳤다:

  • ASLR (주소 무작위화): 실행마다 메모리 주소를 섞는다.
  • Stack Canary: 복귀 주소 앞에 “수호자 값”을 둬서 손상 시 탐지.
  • NX bit: 스택 영역을 실행 불가로 만든다.

이 세 가지가 합쳐져 현대 시스템은 훨씬 안전해졌다.


3.11 부동소수점

정수 연산과 다르게, 실수(float/double)는 XMM 레지스터를 사용한다.
즉, movsd, addsd, mulsd, divsd 같은 명령으로 계산한다.
여러 개의 실수를 한 번에 처리하는 벡터 명령(AVX)도 존재한다.

실수 인자는 XMM 레지스터로 전달되고, 반환값도 XMM0에 담긴다.


3.12 요약 정리

3장은 CS:APP 전체의 “기계 언어 입문서”다.
이 장만 이해하면

  • C 코드가 어셈블리로 어떻게 바뀌는지,
  • 스택과 레지스터가 어떻게 협업하는지,
  • 왜 보안과 최적화가 레벨 낮은 곳에서 시작되는지
    전부 한눈에 보인다.

⚙️ 추가 — 실제 세계 업데이트 (Beyond CS:APP 3e)

  • 현대 리눅스는 PIE(위치 독립 실행 파일)ASLR을 기본 활성화함.
  • 기본 컴파일 옵션에는 스택 보호(-fstack-protector-strong), CET(Control-flow Enforcement)가 들어감.
  • Windows x64는 다른 호출 규약(rcx, rdx, r8, r9)을 사용하고, Red Zone이 없다.
  • 대부분의 CPU는 AVX2 이상을 기본 지원하며, x87 FPU는 역사 속으로 사라짐.

💬 마무리

이제 “if, for, struct, 함수 호출” 같은 게 전부
“cmp, jmp, leaq, call, ret”으로 바뀌는 과정이 보일 것이다.

C는 하드웨어의 시뮬레이터다.
이걸 읽을 수 있으면, 컴퓨터의 사고방식이 눈앞에 펼쳐진다.


 

똥글 미안하다.

 

생성형 AI로 글을 쓰는 내가 나도 싫다 미안하다 ㅜㅜ