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

컴퓨터 시스템 : CSAPP 3장 정리 - 3.4 장 정보 접근하기 Part.2

고웅 2025. 4. 5. 10:25

3.4.1 "오퍼랜드 지정자(Operand Specifiers)"

🧠 오퍼랜드란?

오퍼랜드(Operand)는 명령어에서 사용되는 값

예를 들어, 계산기에서 3 + 5라면

  • +는 연산자 (operator),
  • 3과 5는 오퍼랜드

어셈블리에서도 똑같다

mov %rax, %rbx

여기서 %rax와 %rbx는 오퍼랜드야.
→ “rax에 있는 값을 rbx로 복사해 줘!”


🔧 오퍼랜드의 종류

컴퓨터는 다양한 종류의 값을 계산에 쓸 수 있어! 대표적으로 3가지이다:

종류 예시 설명
즉시 값 (Immediate) $10, $0x20 그냥 숫자 자체!
레지스터 (Register) %rax, %rbx 빠른 기억상자
메모리 (Memory) (%rax), 8(%rbx) 주소를 따라가서 값을 가져와요

🧮 메모리 주소 지정 (주소 계산 방법들)

컴퓨터는 주소를 숫자로 계산할 수 있다.
다양한 주소 계산 공식(어드레싱 방식)이 있다.

📦 주소 방식 정리표

형식 의미
Imm 그냥 주소값 (예: 0x100)
(ra) 레지스터 ra가 가리키는 주소
Imm(rb) rb 주소 + Imm 만큼 더한 위치
(rb, ri) rb + ri 위치
Imm(rb, ri) Imm + rb + ri
(, ri, s) ri * s 위치
Imm(, ri, s) Imm + ri * s
(rb, ri, s) rb + ri * s
Imm(rb, ri, s) Imm + rb + ri * s

📌 예: 8(%rax, %rdx, 4)
→ 주소 = 8 + %rax + 4 * %rdx

📦 “%rax는 서랍 주소, %rdx는 인덱스 번호, 4는 간격”이라고 생각하면 된다.


🧩 예제 1

movq 8(%rdi, %rcx, 4), %rax

“%rdi + %rcx * 4 + 8” 위치에 있는 값을 꺼내서 %rax에 넣어달라

이건 배열에서 arr[rcx] 같은 걸 가져오는 방식과 비슷하다.

3.4.2 "데이터 이동 명령어(Data Movement Instructions)"

🎯 이 절의 핵심 주제는?

컴퓨터가 값을 옮기는 방법을 배운다
"여기 있는 값을 저기다가 복사해 줘!" 하는 명령들을 배운다.


📦 mov 명령어란?

mov는 어셈블리어에서 가장 많이 쓰이는 명령어

mov 소스, 목적지

예를 들어:

mov %rax, %rbx

→ %rax에 있던 값을 %rbx에 복사해줘!

마치 “A상자에 있는 블록을 B상자에 복사해 줘!” 하는 것과 같다.


📏 mov 명령어는 크기에 따라 종류가 다르다

명령어 크기 설명
movb 1바이트 작은 조각 옮기기 (문자 하나)
movw 2바이트 두 조각 (짧은 숫자)
movl 4바이트 보통 크기 (정수 하나)
movq 8바이트 큰 크기 (긴 정수)

🧩 mov 명령어 예시 5가지

  1. 즉시값 → 레지스터→ 0x4050이라는 숫자를 eax에 넣어줘
movl $0x4050, %eax
  1. 레지스터 → 레지스터→ bp의 값을 sp에 복사해줘
    movw %bp, %sp
  2. 메모리 → 레지스터→ 주소 계산해서 거기 있는 값을 al로 복사
    movb (%rdi,%rcx), %al
  3. 즉시값 → 메모리→ 메모리에 바로 -17을 써넣기
    movb $-17, (%esp)
  4. 레지스터 → 메모리→ rax에 있는 값을 주소 rbp-12에 저장!
    movq %rax, -12(%rbp)

❗주의할 점: 메모리 ↔ 메모리 복사 불가!

x86-64에서는 메모리에서 메모리로 직접 이동은 안 된다.
예를 들어,

movq (%rax), (%rbx)  ; ❌ 안 됨!

 

이런 건 안 되고, 이렇게 두 단계로 나눠야 한다.

movq (%rax), %rcx
movq %rcx, (%rbx)
중간에 rcx라는 레지스터를 거쳐야 한다.

🧠 movl의 특별한 성질

movl %eax, %ebx

이건 단순히 4바이트만 복사하는 게 아니다.

  • %ebx 전체 8바이트 중에서
  • 앞쪽 4바이트는 0으로 채워진다.

→ rax에서 eax만 복사하면, 상위 4바이트는 지워진다.

이건 movl만의 특별한 동작이다.

3.4.2 추가 정보 "데이터 이동이 목적지 레지스터를 변경하는 방법 이해하기"

더보기

🎯 핵심 주제: 레지스터 값은 "부분만 바꿀 수도" 있고 "전체가 바뀔 수도" 있다.

컴퓨터에서 값을 저장하는 레지스터는 보통 8바이트(64비트) 크기이다. 하지만 어떤 명령어는 1바이트, 2바이트, 4바이트만 바꾸기도 한다. 이럴 때 나머지 바이트는 어떻게 될까?


📦 예시 상황: %rax라는 레지스터가 있다

우리가 %rax 안에 있는 값을 이렇게 여러 방법으로 바꿔본다고 해보겠다:

1  movabsq $0x0011223344556677, %rax   ; 초기값 설정
2  movb $-1, %al
3  movw $-1, %ax
4  movl $-1, %eax
5  movq $-1, %rax

1️⃣ movabsq $0x0011223344556677, %rax

64비트 전체에 0011223344556677이라는 값을 넣는다.
%rax = 00 11 22 33 44 55 66 77

2️⃣ movb $-1, %al

1바이트(%al)만 FF로 바꾼다. 나머지는 그대로

%rax = 00 11 22 33 44 55 66 FF

3️⃣ movw $-1, %ax

2바이트(%ax)를 FFFF로 바꾼다. 나머지는 그대로

%rax = 00 11 22 33 44 55 FF FF

4️⃣ movl $-1, %eax

4바이트(%eax)를 FFFFFFFF로 바꾸는데, 놀랍게도 앞쪽 4바이트도 0으로 만들어버린다

%rax = 00 00 00 00 FF FF FF FF

🔺 이게 특별한 규칙이다.

  • 32비트 명령(movl)이 레지스터에 저장될 때, 나머지 위쪽 바이트는 0으로 지워진다.

5️⃣ movq $-1, %rax

전체 64비트를 FFFFFFFFFFFFFFFF로 바꾼다

%rax = FF FF FF FF FF FF FF FF