suminworld

concept

x86-64 어셈블리 명령어

숨usm 2025. 10. 5. 04:02

데이터 이동 명령어

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