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

컴퓨터 시스템 : CSAPP 3장 정리 - 3.5 장 산술 및 논리 연산

고웅 2025. 4. 5. 11:00

📘 3.5장 도입: 산술 및 논리 연산

🎯 이 장에서 무엇을 배우는가?

이 장에서는 컴퓨터가 덧셈, 뺄셈, 곱셈 같은 산술 연산이나
AND, OR, NOT 같은 논리 연산을 어떻게 수행하는지를 배운다.


🧠 왜 중요한가?

우리가 프로그램에서 a + b, x * 2, if (x > y) 같은 걸 사용한다. 컴퓨터는 이걸 아주 빠르게 계산하기 위해 레지스터, 비트 연산, 이진수 덧셈기 같은 도구를 사용한다. 이걸 어셈블리어에서 어떻게 처리하는지를 보면 컴퓨터가 똑똑하게 일하는 방식을 이해할 수 있다.


📌 3.5.1 Load Effective Address (LEA, 유효 주소 적재)

🤔 LEA란?

leaq 명령어는 주소를 계산하지만, 메모리에서 값을 읽지는 않는다

💡 예:

 
leaq 7(%rdx, %rdx, 4), %rax

이건 무슨 뜻인가?

  • %rdx에 어떤 값 x가 있다.
  • 7(%rdx, %rdx, 4)는
    → 7 + %rdx + 4 * %rdx = 5x + 7이라는 계산을 해준다
  • 결과는 %rax에 들어간다.

📌 즉, 단순 계산기로 쓰는 leaq


🧩 leaq 명령어의 형식

leaq [주소형식], 목적지레지스터
  • 주소형식은 마치 메모리에서 값을 읽는 형식처럼 생겼지만,
    실제로는 계산만 하고 값을 가져오진 않는다
  • 목적지 레지스터에는 그 계산 결과(주소 값)가 들어간다.

mov는 메모리에서 값을 가져오지만,
leaq는 그 주소(숫자)만 계산해서 가져온다.


🧮 leaq를 이용한 계산 예시

명령어 결과
leaq 9(%rdx), %rax %rax = q + 9
leaq (%rdx, %rbx), %rax %rax = q + p
leaq (%rdx, %rbx, 3), %rax %rax = q + 3p
leaq 2(%rbx, %rbx, 7), %rax %rax = 2 + 8p
leaq 0xE(, %rdx, 3), %rax %rax = 14 + 3q
leaq 6(%rbx, %rdx, 7), %rdx %rdx = 6 + p + 7q​

🎯 3.5.2 산술 연산 (Arithmetic Operations)

컴퓨터가 하는 기본 계산

이 절에서는 컴퓨터가 할 수 있는 기본 계산 명령어들을 소개한다.
덧셈, 뺄셈, 곱셈, 반전, 보수 같은 걸 말이다


📦 명령어 종류 요약표

명령어 설명 C 언어와 비교
addq S, D D ← D + S D += S;
subq S, D D ← D - S D -= S;
imulq S, D D ← D * S D *= S;
andq S, D D ← D & S 비트 AND
orq S, D D ← D | S 비트 OR
xorq S, D D ← D ^ S 비트 XOR
neg D D ← -D 음수로 바꾸기
not D D ← ~D 비트 반전
inc D D ← D + 1 하나 증가
dec D D ← D - 1 하나 감소

💡 대부분 명령어는 두 오퍼랜드(값)를 사용한다 (binary operation)


예제 C 코드와 어셈블리 비교

ong arith(long x, long y, long z) {
    long t1 = x ^ y;
    long t2 = z * 48;
    long t3 = t1 & 0x0F0F0F0F;
    long t4 = t2 - t3;
    return t4;
}


→ 이 코드는 다음과 같은 어셈블리로 바뀐다:

xorq %rsi, %rdi         ; x ^ y
leaq 0(,%rdx,48), %rax  ; z * 48
andl $0x0F0F0F0F, %edi  ; & 0x0F0F0F0F
subq %rdi, %rax         ; t2 - t3
  • leaq를 곱셈처럼 사용한 게 포인트다 (48 = 3 * 16으로 인덱스 연산으로 계산함)

🎯 3.5.3 시프트 연산 (Shift Operations)

🧠 시프트(Shift) 연산이란?

숫자를 비트 단위왼쪽이나 오른쪽으로 밀어서 계산하는 방법이다

컴퓨터는 숫자를 0과 1, 즉 비트로 저장한다.
시프트는 이 비트들을 좌우로 움직이면서 새로운 숫자를 만들어내는 것.

명령어 설명
sal, shl 왼쪽 시프트 (x << k) 2^k * x
sar 오른쪽 산술 시프트 (부호 유지) x / 2^k (음수도 지원)
shr 오른쪽 논리 시프트 (0 채움) 양수에서 / 2^k

sal과 shl은 같다 sar과 shr은 다르게 동작한다 (부호 처리)

💡 예제: 숫자 8 (이진수로 00001000)

1. 왼쪽 시프트 (shl $1, %rax)

00001000 → 00010000 8 → 16

숫자가 2배가 된다.

2. 오른쪽 논리 시프트 (shr $1, %rax)

00001000 → 00000100 8 → 4

숫자가 반으로 줄어든다.

3. 오른쪽 산술 시프트 (sar $1, %rax)

양수일 땐 shr이랑 똑같이 작동한다.
하지만 음수일 땐 앞에 1이 채워진다!

예: -8 (64비트에서 11111111...11111000)

sar $1, %rax → 여전히 음수 유지된다.

sar은 음수도 처리 가능, shr은 음수에서 틀릴 수 있다.


🧒 쉬운 비유

  • shl = 끝에 0을 덧붙여서 자리 올림
    (예: 8 → 80처럼 보임)
  • shr = 앞에 0을 붙여서 숫자 줄이기
  • sar = 앞 숫자 그대로 유지하면서 줄이기
    (음수도 올바르게 줄인다.)

🧪 정리표 (C 코드 비교)

어셈블리 C 코드
shl $1, %rax x << 1
shr $1, %rax (unsigned)x >> 1
sar $1, %rax x >> 1 (signed)

🧠 3.5.4 토의 (Discussion)

🎯 이 절의 핵심

대부분의 어셈블리 연산은 부호 있는 정수(signed)부호 없는 정수(unsigned) 모두에 사용할 수 있다.
하지만 오른쪽 시프트는 예외다!


💡 왜 오른쪽 시프트만 다를까?

  • 부호 있는 정수(음수 포함): sar → 산술 시프트
  • 부호 없는 정수: shr → 논리 시프트

📌 즉, 어떤 시프트를 쓰느냐에 따라 음수의 처리 방식이 다르다


👍 그래서 이게 중요한 이유?

이러한 특성 때문에 컴퓨터는 2의 보수 방식(two’s complement)을 써서
부호 있는 정수도 마치 부호 없는 정수처럼 간단하게 연산할 수 있게 된다.

  • 덧셈, 뺄셈, 곱셈은 모두 동일하게 처리 가능
  • 단, 나눗셈이나 시프트만 구별 필요

이게 바로 2의 보수가 컴퓨터에서 부호 있는 숫자를 표현하는 표준 방식이 된 이유이다.


🧠 3.5.5 특수 산술 연산 (Special Arithmetic Operations)

🎯 이 절의 핵심

때때로 계산 결과가 너무 커서 64비트로는 부족하다.
그래서 128비트(16바이트) 연산도 필요하다


📦 128비트 연산은 언제 필요할까?

  • 64비트 숫자 × 64비트 숫자 = 최대 128비트 결과 필요
  • 이럴 땐 %rax + %rdx 두 개의 레지스터를 붙여서 128비트처럼 사용한다.

💡 명령어 요약

명령어 설명 결과 저장 장소
imulq S 부호 있는 곱셈 %rdx:%rax ← S × %rax
mulq S 부호 없는 곱셈 %rdx:%rax ← S × %rax
cqto %rax의 부호 확장 → %rdx에 넣기 128비트 만들기 준비
idivq S 부호 있는 나눗셈 %rax ← 몫, %rdx ← 나머지
divq S 부호 없는 나눗셈 위와 같음

%rdx:%rax는 두 레지스터를 합쳐서 128비트처럼 사용하는 걸 의미한다.


📊 예시 비유

  • %rax: 계산기 아래쪽 반
  • %rdx: 계산기 위쪽 반
  • 둘이 합쳐서 큰 계산기가 되는 것이다.

예를 들어:

movq $10000000000, %rax movq $0, %rdx idivq $10

→ %rax에는 몫, %rdx에는 나머지가 저장된다.


✅ 마무리 요약

  • 3.5.4: 대부분 연산은 부호 유무에 관계없이 쓸 수 있지만, 시프트는 예외
  • 3.5.5: 128비트 결과가 필요한 곱셈·나눗셈 연산은 %rax, %rdx를 함께 사용
  • imulq, mulq, idivq, divq, cqto 등은 특수한 산술 상황에 사용된다.