Assembly를 공부하며 계속 보완할 예정입니다
💻 x86-64 아키텍쳐
데이터 이동
mov dst, src
: src에 들어있는 값을 dst에 대입lea dst, src
: src의 유효 주소(Effective Address, EA)를 dst에 저장
산술 연산
add dst, src
: dst에 src의 값을 더함sub dst, src
: dst에서 src의 값을 뺌inc op
: op의 값을 1 증가inc eax
-> eax += 1
dec eax
: op의 값을 1 감소dec eax
-> eax -= 1
논리 연산
: 비트 단위로 논리 연산한 값을 dst에 저장
and dst, src
: dst와 src의 비트가 모두 1이면 1, 아니면 0or dst, src
: dst와 src의 비트 중 하나라도 1이면 1, 아니면 0xor dst, src
: dst와 src의 비트가 서로 다르면 1, 같으면 0not op
: op의 비트 전부 반전하여 op에 저장
비교
: 두 피연산자의 값을 비교하고, Flag를 설정
cmp op1, op2
: op1과 op2를 비교- 두 피연산자를 빼어 결과가 0이 되면 ZF 플래그 설정 후, 플래그에 따라 두 값이 같았는지 판단. 연산의 결과는 op1에 대입하지 않음
test op1, op2
: op1과 op2를 비교- 두 피연산자에 AND 비트 연산을 취하여 결과가 0이 되면 ZF 플래그 설정 후, 플래그에 따라 피연산자가 0이었는지 판단할 수 있음. 연산의 결과는 op1에 대입하지 않음
분기
: 분기 명령어는 rip
(Instruction Pointer)를 이동시켜 실행 흐름을 바꿈
jmp addr
: addr로 rip를 이동je addr
: 직전에 비교한 두 피연산자가 같으면 점프(jump if equal)jg addr
: 직전에 비교한 두 연산자 중 전자가 더 크면 점프(jump if greater)
Opcode - Stack
push val : val을 스택 최상단에 쌓음
push A
-> stack 최상단에 A 값 대입
pop reg : 스택 최상단의 값을 꺼내서 reg에 대입
pop B
-> stack 최상단의 값을 B에 대입
Opcode - Procedure
: 프로시저(Procedure)는 특정 기능을 수행하는 코드 조각을 의미한다. 프로시저를 사용하여 반복되는 연산을 재사용하거나, 기능 별 코드 조각에 이름을 붙여 가독성에 용이하다.
call addr : addr에 위치한 프로시저를 호출
call A
==push return_address; jmp 0x401000
-> A 주소에 위치한 프로시저 호출
leave : 스택 프레임 정리
leave
==mov rsp, rbp; pop rbp
ret : return_address로 반환(호출자의 실행 흐름으로 돌아감)
ret
==pop rip
스택 프레임 : 스택 영역을 구분 없이 사용 시에 서로 다른 함수가 같은 메모리 영역을 사용할 수 있게 되기 때문에 변수 등이 오염될 수 있음. 이를 위해 스택의 영역을 명확히 구분하고자 스택 프레임을 사용함.
Opcode - Systemcall(syscall)
: 시스템 콜은 유저 모드에서 시스템 소프트웨어에게 어떤 동작을 하기 위해 사용된다.
예를 들어, 사용자가 cat file.c
(파일 읽기)를 요청하면 파일 시스템에 접근하여 file.c라는 파일을 읽어 화면에 출력해야 한다. 이때, 유저 모드에서는 파일 시스템에 접근할 수 없기 때문에 커널에게 도움을 요청하는 시스템 콜을 실행해야 한다.
커널 모드 : 운영체제가 전체 시스템을 제어하기 위해 시스템 소프트웨어에 부여하는 권한. 커널 모드에서는 시스템의 모든 부분을 제어할 수 있음. ex) 파일 시스템, 입출력, 네트워크 통신, 메모리 관리 등 유저 모드 : 운영체제가 사용자에게 부여하는 권한. 커널의 막강한 권한을 보호할 수 있음.
syscall : 커널에게 필요한 동작을 요청
- 요청 : rax
- 인자 순서 : rdi -> rsi -> rdx -> rcx -> r8 -> r9 -> stack
- syscall table을 참조