x86 assembly data move instruction
[1. 데이터 이동]
mov <reg> <reg>
=> 두번째 피연산자에 명시 된 레지스터에 저장된 값을 첫번째 피연산자에 명시 된 레지스터에 저장한다.
mov <reg> <mem>
=> 두번째 피연산자에 명시 된 메모리 주소에 저장 된 값을 첫번째 피연산자에 명시 된 레지스터에 저장한다.
mov <mem> <reg>
=> 두번째 피연산자에 명시 된 레지스터에 저장 된 값을 첫번째 피연산자에 명시 된 메모리 주소에 저장한다.
mov <reg> <const>
mov <mem> <const>
=> 두번째 피연산자에 명시 된 상수 값을 첫번째 피연산자에 명시 된 레지스터/메모리 주소에 저장한다.
; example code
section .bss
num resb 8 ; reserve 8bytes
num1 resb 8
section .text
global _start
_start:
mov rax, 0x50
mov ebx, 0x30
mov r10, num ; store num address
mov r11, num1
mov DWORD [num], 0x12345678
mov DWORD [num+4], 0x12345678
mov cl, BYTE [num] ; 0x78
mov dx, WORD [num] ; 0x5678
mov r8d, DWORD [num] ; 0x12345678
mov r9, QWORD [num]
mov r12, 0x9876543210987654
mov QWORD [num1], r12
mov rax, 60
mov rdi, 0
syscall
num 은 8byte 공간이 할당되었지만,
mov 명령어에서 두번째 피연산자로 상수 값이 오는 경우 4byte 까지만 할당이 가능하다.
따라서 8byte 공간을 초기화 하기 위해 4바이트를 두번에 걸쳐서 초기화 시킨다.
그리고 indirection addressing mode 를 사용할 때에는 BYTE, WORD, DWORD, QWORD 와 같은 키워드를 이용하여
얼마만큼 이동 시킬 지 그 byte 값을 명시해야 한다.
아래는 위 코드 실행 시 각 레지스터 및 메모리에 저장된 값을 보여 준다.
[2. Stack 관련 명령어]
메모리내 하드웨어 지원 스택을 사용 할 수 있게 해주는 명령어로
RSP 레지스터를 이용해서 직접 메모리 주소를 직접 계산하면서 stack 을 활용 할 수 도 있다.
push <reg> <-> pop <reg>
push <mem> <-> pop <mem>
push <const> <-> pop <const>
; example code
section .text
global _start
_start:
mov rax, 0x1111111111111111
push rax
inc rax ; rax=rax+1
push rax
inc rax
pop rbx ; expect 0x1111111111111111
pop rcx ; expect 0x1111111111111112
mov rbp, rsp ; rbp point to top of stack
mov DWORD [rbp-4], 0x12345678 ; like push
mov DWORD [rbp-8], 0x87654321
mov edx, DWORD [rbp-8] ; like pop
mov r8d, DWORD [rbp-4]
mov rax, 60
mov rdi, 0
syscall
위 코드는 push/pop instruction 을 통해 stack 을 사용하는 것과
stack pointer 를 직접 제어하여 stack 을 사용하는 두가지 방식을 보여주고 있다.
stack pointer 를 직접 제어하는 방식에서
DWORD 의 크기는 4bytes 이므로, 현재 stack 은 아래와 같은 상태가 된다.
stack:
[<---0x12345678--->]
[<---0x87654321--->]
아래는 실제로 각 레지스터에 할당된 값을 보여주고 있다.
[3. 메모리 주소 관련 명령어]
LEA = Load Effective Address
[4. 참고자료]