오퍼랜드 식별자란?
어셈블리에서 “이 데이터 어디서 가져올거야?”를 명시하는 방식
즉, 값의 출처(location of data) 를 어떻게 지정하느냐임
오퍼랜드의 종류
| 구분 | 예시 | 해석 | 핵심 특징 |
|---|---|---|---|
| Immediate | $0x10 | 상수 16 | 값 그 자체 |
| Register | %rax | 레지스터 rax에 저장된 값 | 가장 빠름, 가장 흔함 |
| Memory | 8(%rbp) | rbp+8 위치의 메모리 값 | 간접 참조, 주소 계산 포함 |
Immediate(즉시값) 타입 ($value)
movq $5, %rax ; rax에 5 저장
- $5 : 숫자 그 자체
- 앞에 $는 “뒤에 오는 것이 주소가 아닌 값” 이라는 선언
- C로 따지면 x = 5; 같은 느낌
movq $0x10, %rax ;rax에 0x10을 저장
- 메모리에서 가져오는게 아닌, 명령어 내부에서 즉시 가져옴
- CPU는 값을 해석할 필요 없이 바로 실행
- 이는 명령어 저장 구조에 의해 가능
- [opcode][destination][immediate 0x10]
- 속도 빠름, 비용 낮음, 하지만 무조건 상수만 가능
Register 타입 (%rax, %rcx, …)
movq %rdi, %rax ; rdi -> rax
- 위 코드는 CPU 내부에 있는 저장소 간 복사를 의미
- C로 따지면 x = y; 랑 대응되는 의미
addq %rax, %rbx
- 두 레지스터 간 연산
- CPU입장에서는 내부 저장소 끼리 연산수행
- 메모리 접근 안함 → 가장 빠름, 캐시나 버스 트래픽 없음
Memory(메모리 참조) 타입 ((%rax), 8(%rbp), …)
movq (%rsp), %rax ; rsp(스택 꼭대기) -> rax
- 괄호는 무조건 메모리 참조라는 뜻
- (%rsp) → “rsp가 가리키는 주소에 있는 값”
movq (%rdi), %rax
- 여기서 %rdi는 그냥 주소
- 그 주소에 접근해 주소가 가리키는 값을 로드
- 즉 괄호 → 메모리 간접 참조
- (%rdi) = “%rdi에 있는 값을 주소로 생각해서, 그 메모리 위치에 있는 값 가져와”
예시
movq 8(%rbp, %rcx, 4), %rax
- 의미 분석:
- 베이스 : %rbp
- 인덱스 : %rcx
- 스케일 : 4 (즉, rcx * 4)
- 오프셋 : 8
- 전체 주소 =
%rbp + (%rcx * 4) + 8
배열의 인덱스 접근 처럼 생긴 고급 메모리 참조 방식
마치 C에서의 arr[i + 2]나, struct[i].x에 대응
주의사항
- Immediate와 Memory 착각첫 째는 16을 rax로, 두 번째는 메모리 주소 0x10을 읽는 것
movq $0x10, %rax movq 0x10, %rax- mov %eax, (%rax) vs mov (%rax), %eax
- 이는 읽기 / 쓰기가 바뀜
- mov (%rax), %eax → 메모리에서 읽어오기
- mov %eax, (%rax) → 메모리에 쓰기
- 이는 읽기 / 쓰기가 바뀜
요약
- $ → 즉시값
- % → 레지스터
- ( ) → 메모리 주소 참조 (이때 64비트 레지스터만 주소 참조 가능)
| 표기 | 의미 |
|---|---|
| $value | 값 그 자체 (immediate) |
| %reg | 레지스터 값 |
| (%reg) | 레지스터가 가리키는 주소의 값 (memory indirect) |
| offset(%reg) | 주소 오프셋 포함된 메모리 참조 |
| (%base, %idx, scale) | 배열식 주소 연산 |
오퍼랜드 형식 읽기
왜 필요한가?
”메모리 오퍼랜드”를 어떻게 해석하는지 정리된 도표
즉, mov, add, cmp, lea 같은 명령어가 ”어디서 값을 읽고/쓸지” 결정할 때 사용하는 주소 계산방식

각 Form 설명
| Form | 의미 |
| $imm | 즉시 값, 그냥 숫자. 메모리 안 봄 |
| %rax | 레지스터 값 |
| imm | 절대 주소. 거의 안 씀. OS나 커널 영역에서나 나옴 |
| (%rax) | %rax가 가리키는 메모리 |
| 8(%rax) | %rax + 8 주소의 메모리 |
| (%rax,%rcx) | %rax + %rcx 주소 |
| 8(%rax,%rcx) | %rax + %rcx + 8 |
| (%rcx,4) | %rcx * 4 주소 |
| 8(,%rcx,4) | 8 + %rcx * 4 |
| (%rax,%rcx,4) | %rax + %rcx * 4 (진짜 배열처럼 생김) |
| 8(%rax,%rcx,4) | %rax + %rcx * 4 + 8 |
- 컬럼
- Form : 어셈블리 문법상 어떻게 쓰이는지
- Operand Value : 내부적으로 어떤 주소를 참조하게 되는지 (메모리 접근 수식)
- Name : 해당 방식의 이름
- 전체 주소 계산 공식 (‼중요)
[imm + R[rb] + R[ri]*s]
모든 주소 지정의 뿌리
- imm : 상수 오프셋 (Immediate)
- rb : Base Register (기준 주소)
- ri : Index Register (인덱스)
- s : Scale (배열 요소 크기 등, 1,2,4,8 중 하나)
예제
movl 8(%rbp), %eax
→ rbp + 8 주소에서 4바이트 값을 읽어서 %eax(32비트, 4바이트)에 저장
movl (%rdi, %rcx, 4), %eax
→ 배열 접근
- %rdi = 배열 시작 주소
- %rcx = 인덱스
- *4 = 4바이트(구조체 크기)
즉 eax = A[rcx];
movb $1, 16(%rbx,%rdx,8)
→ 구조체 배열의 특정 필드에 값 저장하는 상황
- %rbx = struct 배열 시작 주소
- %rdx = 인덱스
- *8 = 8바이트(구조체 크기)
- +16 = 필드 오프셋
즉 arr[rdx].field = 1;
- 구조체 크기는 1, 2, 4, 8 중 하나만 가능
- 메모리 ↔ 메모리 연산은 안 됨
- add (%rax), (%rbx) 절대 불가
연습문제
| 주소 | 값 | 레지스터 | 값 | |
|---|---|---|---|---|
| 0x100 | 0xFF | %rax | 0x100 | |
| 0x104 | 0xAB | %rcx | 0x1 | |
| 0x108 | 0x13 | %rdx | 0x3 | |
| 0x10C | 0x11 |
| Operand | Value |
|---|---|
| %rax | |
| 0x104 | |
| $0x108 | |
| (%rax) | |
| 4(%rax) | |
| 9(%rax,%rdx) | |
| 260(%rcx,%rdx) | |
| 0xFC(,%rcx,4) | |
| (%rax,%rdx,4) |
답안
| Operand | Value |
| --- | --- |
| %rax | 0x100 |
| 0x104 | 0xAB |
| $0x108 | 0x108 |
| (%rax) | 0xFF |
| 4(%rax) | 0xAB |
| 9(%rax,%rdx) | 0x11 |
| 260(%rcx,%rdx) | 0x13 |
| 0xFC(,%rcx,4) | 0xFF |
| (%rax,%rdx,4) | 0x11 |
728x90
'CS:APP' 카테고리의 다른 글
| [C, Assembly] movq 예제 (0) | 2025.04.07 |
|---|---|
| mov 인스트럭션 - CS:APP 3.4.2 (0) | 2025.04.07 |
| 레지스터가 뭔데 - CS:APP 3.4 (0) | 2025.04.07 |
| GCC는 C를 어떻게 기계어로 짜깁기할까? - CS:APP 3.2 요약과 인사이트 (0) | 2025.04.07 |
| 암달의 법칙 (Amdahl's law) (0) | 2025.04.07 |