데이터 이동 명령어
movq - Move Quadword (64비트)
형식: movq source, destination
기능: 64비트 데이터를 source에서 destination으로 복사
예시:
movq %rsp, %rbp # %rsp의 값을 %rbp로 복사
movq %rsi, -16(%rbp) # %rsi를 메모리 [%rbp-16]에 저장
movl - Move Long (32비트)
형식: movl source, destination
기능: 32비트 데이터를 source에서 destination으로 복사
특징: 목적지가 64비트 레지스터면 상위 32비트 자동 0
예시:
movl $0x0, %eax # 상수 0을 %eax에 저장
movl %edi, -4(%rbp) # %edi를 메모리 [%rbp-4]에 저장
movl -20(%rbp), %edi # 메모리 [%rbp-20]을 %edi로 로드
스택 명령어
pushq - Push Quadword
형식: pushq source
동작:
1. %rsp -= 8 (스택 포인터 8바이트 감소)
2. [%rsp] = source (값을 스택에 저장)
예시:
pushq %rbp # %rbp를 스택에 저장
구조도:
실행 전:
├──────┤ ← %rsp
│ │
실행 후:
├──────┤
│ %rbp │ ← push된 값
├──────┤ ← %rsp (8바이트 아래)
popq - Pop Quadword
형식: popq destination
동작:
1. destination = [%rsp] (스택에서 값 꺼냄)
2. %rsp += 8 (스택 포인터 8바이트 증가)
예시:
popq %rbp # 스택에서 값을 꺼내 %rbp에 저장
구조도:
실행 전:
├──────┤
│ 0x500│ ← 저장된 값
├──────┤ ← %rsp
실행 후:
├──────┤ ← %rsp (8바이트 위)
│ 0x500│
├──────┤
%rbp = 0x500 (복원됨)
산술 명령어
addl - Add Long (32비트)
형식: addl source, destination
기능: destination = destination + source
예시:
addl $0x3, %edi # %edi = %edi + 3
addl %eax, %ebx # %ebx = %ebx + %eax
제어 흐름 명령어
ret - Return
형식: ret
동작:
1. %rip = [%rsp] (리턴 주소를 꺼냄)
2. %rsp += 8 (스택 포인터 증가)
3. 해당 주소로 점프
결과: 함수를 호출한 곳으로 복귀
구조도:
실행 전:
├──────────┤
│ 리턴 주소 │ ← [%rsp]
├──────────┤ ← %rsp
실행 후:
├──────────┤ ← %rsp (8바이트 위)
│ 리턴 주소 │
├──────────┤
%rip = 리턴 주소 (점프!)
명령어 크기 접미사
┌─────────┬─────────┬──────────┐
│ 접미사 │ 크기 │ 예시 │
├─────────┼─────────┼──────────┤
│ b │ 8비트 │ movb │
│ w │ 16비트 │ movw │
│ l │ 32비트 │ movl │
│ q │ 64비트 │ movq │
└─────────┴─────────┴──────────┘
전체 명령어 요약
┌─────────┬──────────────┬─────────────────────┐
│ 명령어 │ 의미 │ 동작 │
├─────────┼──────────────┼─────────────────────┤
│ pushq │ Push 64bit │ 스택에 저장 │
│ popq │ Pop 64bit │ 스택에서 꺼냄 │
├─────────┼──────────────┼─────────────────────┤
│ movq │ Move 64bit │ 64비트 복사 │
│ movl │ Move 32bit │ 32비트 복사 │
├─────────┼──────────────┼─────────────────────┤
│ addl │ Add 32bit │ 32비트 덧셈 │
├─────────┼──────────────┼─────────────────────┤
│ ret │ Return │ 함수 복귀 │
└─────────┴──────────────┴─────────────────────┘
실제 코드 분석
asm
0x00: pushq %rbp # %rbp 백업
0x01: movq %rsp, %rbp # 기준점 설정
0x04: movl $0x0, %eax # return 0 준비
0x09: movl %edi, -4(%rbp) # argc 저장 (32bit)
0x0c: movq %rsi, -16(%rbp) # argv 저장 (64bit)
0x10: movl -20(%rbp), %edi # x 로드 (32bit)
0x13: addl $0x3, %edi # x += 3
0x19: movl %edi, -20(%rbp) # x 저장
0x1c: popq %rbp # %rbp 복원
0x1d: ret # 복귀
핵심 패턴:
- movl: 32비트 정수 처리 (int)
- movq: 64비트 포인터/주소 처리
- pushq/popq: 스택 관리
- addl: 32비트 산술 연산
----------------
[강의안 예시 코드]
명령어 접미사 (크기)
┌─────────┬─────────┬──────────┐
│ 접미사 │ 크기 │ 예시 │
├─────────┼─────────┼──────────┤
│ b │ 1 byte │ movb │
│ w │ 2 byte │ movw │
│ l │ 4 byte │ movl │
│ q │ 8 byte │ movq │
└─────────┴─────────┴──────────┘
명령어별 실제 동작
pushq %rbp (0x00)
스택에 8바이트 push
동작:
1. %rsp -= 8
2. [%rsp] = %rbp
의미: %rbp를 스택에 백업
메모리/레지스터 변화:
실행 전:
%rsp: 0x4f8
%rbp: 0x500
Stack
├──────────┤ ← 0x4f8 (%rsp)
│ │
└──────────┘
실행 후:
%rsp: 0x4f0 (8 감소)
%rbp: 0x500 (그대로)
Stack
├──────────┤
│ 0x500 │ ← push된 값
├──────────┤ ← 0x4f0 (%rsp)
│ │
└──────────┘
movq %rsp, %rbp (0x01)
64비트 복사
동작:
%rbp = %rsp
의미: 새 기준점 설정
레지스터 변화:
실행 전:
%rsp: 0x4f0
%rbp: 0x500
실행 후:
%rsp: 0x4f0
%rbp: 0x4f0 ← 같아짐!
movl $0x0, %eax (0x04)
32비트 상수를 레지스터로 이동
동작:
%eax = 0
특징: 상위 32비트 자동 0
레지스터 변화:
실행 전:
%rax: 0x12345678ABCDEF00
실행 후:
%rax: 0x0000000000000000
↑↑↑↑↑↑↑↑ 상위 32비트 자동 0
%eax: 0x00000000
movl %edi, -4(%rbp) (0x09)
32비트 레지스터를 메모리로 저장
동작:
[%rbp - 4] = %edi (4바이트)
의미: argc를 스택에 저장
메모리 변화:
%rbp: 0x4f0
%edi: 1 (argc 값)
Stack
├──────────┤ ← 0x4f0 (%rbp)
│ 0x00000001│ ← 0x4ec (%rbp-4, argc)
├──────────┤
│ │
└──────────┘
movq %rsi, -16(%rbp) (0x0c)
64비트 레지스터를 메모리로 저장
동작:
[%rbp - 16] = %rsi (8바이트)
의미: argv를 스택에 저장
메모리 변화:
%rbp: 0x4f0
%rsi: 0x7fffffffe000 (argv 주소)
Stack
├──────────┤ ← 0x4f0 (%rbp)
│ argc (1) │ ← 0x4ec
│ │
│ 0x7fff...│ ← 0x4e0 (%rbp-16, argv)
├──────────┤
movl -20(%rbp), %edi (0x10)
메모리에서 32비트를 레지스터로 로드
동작:
%edi = [%rbp - 20] (4바이트)
의미: 변수 x를 레지스터로 로드
메모리/레지스터 변화:
%rbp: 0x4f0
Stack
├──────────┤ ← 0x4f0
│ argc │
│ argv │
│ x = 0 │ ← 0x4dc (%rbp-20)
├──────────┤
실행 후:
%edi: 0 (x 값)
addl $0x3, %edi (0x13)
32비트 덧셈
동작:
%edi = %edi + 3
의미: x에 3을 더함
레지스터 변화:
실행 전:
%edi: 0
실행 후:
%edi: 3
movl %edi, -20(%rbp) (0x19)
레지스터를 메모리로 저장
동작:
[%rbp - 20] = %edi (4바이트)
의미: 계산 결과를 x에 저장
메모리 변화:
%edi: 3
Stack
├──────────┤
│ argc │
│ argv │
│ x = 3 │ ← 0x4dc (%rbp-20, 업데이트!)
├──────────┤
popq %rbp (0x1c)
스택에서 8바이트 pop
동작:
1. %rbp = [%rsp]
2. %rsp += 8
의미: 이전 기준점 복원
메모리/레지스터 변화:
실행 전:
%rsp: 0x4f0
%rbp: 0x4f0
Stack
├──────────┤
│ 0x500 │ ← 저장된 이전 %rbp
├──────────┤ ← 0x4f0 (%rsp)
실행 후:
%rsp: 0x4f8 (8 증가)
%rbp: 0x500 (복원!)
Stack
├──────────┤ ← 0x4f8 (%rsp)
│ 0x500 │
├──────────┤
ret (0x1d)
함수 복귀
동작:
1. %rip = [%rsp]
2. %rsp += 8
3. 해당 주소로 점프
의미: 호출한 곳으로 복귀
메모리/레지스터 변화:
실행 전:
%rsp: 0x4f8
Stack
├──────────┤ ← 0x4f8 (%rsp)
│ 0x1234 │ ← 리턴 주소
├──────────┤
실행 후:
%rsp: 0x500 (8 증가)
%rip: 0x1234 (점프!)
전체 흐름 - 레지스터 & 메모리 변화
초기 상태
Registers:
%rsp: 0x4f8
%rbp: 0x500
%rip: 0x00
%rdi: 1 (argc)
%rsi: 0x7fff... (argv)
Stack:
├──────────┤ ← 0x4f8 (%rsp)
│ 리턴주소 │
├──────────┤
0x00: pushq %rbp
Registers:
%rsp: 0x4f0 ← 변경
%rbp: 0x500
%rip: 0x01
Stack:
├──────────┤
│ 리턴주소 │
├──────────┤
│ 0x500 │ ← push
├──────────┤ ← 0x4f0 (%rsp)
0x01: movq %rsp, %rbp
Registers:
%rsp: 0x4f0
%rbp: 0x4f0 ← 변경 (기준점)
%rip: 0x04
Stack: 변화 없음
0x04: movl $0x0, %eax
Registers:
%rax: 0x0000000000000000 ← 변경
%rip: 0x09
Stack: 변화 없음
0x09: movl %edi, -4(%rbp)
Registers:
%rip: 0x0c
Stack:
├──────────┤ ← 0x4f0 (%rbp)
│ argc=1 │ ← 0x4ec
├──────────┤
│ 0x500 │
├──────────┤ ← 0x4f0 (%rsp)
0x0c: movq %rsi, -16(%rbp)
Registers:
%rip: 0x10
Stack:
├──────────┤ ← 0x4f0 (%rbp)
│ argc=1 │ ← 0x4ec
│ │
│ argv │ ← 0x4e0 (8바이트)
├──────────┤
│ 0x500 │
├──────────┤ ← 0x4f0 (%rsp)
0x10: movl -20(%rbp), %edi
Registers:
%edi: 0 ← 변경 (x 로드)
%rip: 0x13
Stack:
├──────────┤ ← 0x4f0
│ argc │
│ argv │
│ x = 0 │ ← 0x4dc (%rbp-20)
├──────────┤
│ 0x500 │
├──────────┤ ← %rsp
0x13: addl $0x3, %edi
Registers:
%edi: 3 ← 변경 (0+3)
%rip: 0x19
Stack: 변화 없음
0x19: movl %edi, -20(%rbp)
Registers:
%rip: 0x1c
Stack:
├──────────┤
│ argc │
│ argv │
│ x = 3 │ ← 0x4dc (업데이트!)
├──────────┤
│ 0x500 │
├──────────┤ ← %rsp
0x1c: popq %rbp
Registers:
%rbp: 0x500 ← 복원
%rsp: 0x4f8 ← 8 증가
%rip: 0x1d
Stack:
├──────────┤ ← 0x4f8 (%rsp)
│ 리턴주소 │
├──────────┤
│ 0x500 │
├──────────┤
0x1d: ret
Registers:
%rip: (리턴주소) ← 점프
%rsp: 0x500 ← 8 증가
완전히 이전 상태로 복귀!
핵심 정리
명령어 접미사:
l = 32비트 (4바이트)
q = 64비트 (8바이트)
push/pop:
항상 8바이트 단위 (q)
mov:
크기에 따라 l 또는 q
add:
32비트 연산 = addl
'concept' 카테고리의 다른 글
| 운영체제 프로세스 개념 정리 (0) | 2025.10.17 |
|---|---|
| x86-64 레지스터의 자동 Zero-Extension 규칙 (0) | 2025.10.05 |
| [임시] 강의자료 정리: 함수 호출 과정 - Virtual Memory (1) | 2025.10.05 |
| [Virtual Memory] x86-64 함수 호출 & Virtual Memory 기반 스택 프레임 정리 (SysV ABI) (0) | 2025.10.05 |
| x86-64 스택 프롤로그(Stack Prologue)와 스택 프레임(Stack Frame) (0) | 2025.10.02 |