이 글은 https://dreamhack.io/lecture/courses/37, https://dreamhack.io/lecture/courses/63 토대로 작성한 글입니다.
컴퓨터는 컴퓨터의 언어인 기계어(Machine Code)로 소통을 하고 여러 상호작용을 한다.
하지만 기계어는 0과 1로 구성되어 있어서 사람이 읽고 작성하고 이해하기에는 너무 어렵다.
그래서 컴퓨터 과학자 중 한 명인 David Wheeler는 EDSAC을 개발하면서 어셈블리 언어(Assembly Language)와 어셈블러(Assembler)라는 것을 고안했습니다.
어셈블리어(Assembly Language)는 기계어와 1 대 1 대응이 되어 있고, 어셈블리어(Assembly Language)는 어셈블러(Assembler)를 통해서 기계어로 치환이 된다.
어셈블리어(Assembly Language)는 0과 1로 이루어져 있는 기계어(Machine Code)보다 사람이 읽기 더 편하다.
이번 시간에는 어셈블리어(Assembly Language)에 대해 더 자세하게 알아보겠다.
이전 Backgruond: Computer Architecture (https://velog.io/@securitykss/Dreamhack-1.-Background-2-Computer-Architecture)에서 CPU에 사용되는 ISA는 IA-32, x86-64, ARM, MIPS 등 다양한 졸류가 있다고 언급한 적이 있다.
x86-64에는 x86-64가 사용하는 어셈블리어가 있고,
ARM에는 ARM이 사용하는 어셈블리어가 존재한다.
우리는 x86-64 어셈블리어를 알아보자.
명령어(operation, opcode)와 피연산자(operand)로 구성되어 있다.
피연산자(operand)는 3가지 종류가 올 수 있다.
상수(Immediate Value)
상수는 위의 그림에서 3처럼 숫자를 사용한다.
레지스터(Regitster)
레지스터는 위의 그림에서 eax처럼 레지스터들을 사용한다.
메모리(Memory)
메모리 피연산자는 []으로 둘러싸인 것으로 표현되며, 앞에 크기 지정자(Size Directive) TYPE PTR이 추가될 수 있습니다. 여기서 타입에는 BYTE, WORD, DWORD, QWORD가 올 수 있으며, 각각 1바이트, 2바이트, 4바이트, 8바이트의 크기를 지정합니다.
ex) mov rax, QWORD PTR[0X40393]
해석: 0x40393 주소 안의 데이터를 8바이트 만큼 참조해서 rax에 대입
데이터 이동, 산술 연산, 논리 연산, 비교, 분기에 관한 명령어에 대해 알아 보겠다.
mov, lea 명령어
mov 명령어
mov dst, src : src에 들어있는 값을 dst에 대입
ex1) mov rax, rdi : rdi의 값을 rax에 대입
ex2) mov rsi, QWORDPTR[rdi] : rdi가 가리키는 주소의 값을 8바이트 만큼 참조해서 rsi에 대입
lea 명령어
lea dst, src : src의 유효 주소(Effective Address, EA)를 dst에 저장
ex) lea rsi, [rbx + 8*rcx] : rbx + 8*rcx를 rsi에 대입
add, sub, inc, dec 연산 명령어
add 연산
add dst, src : dst에 src의 값을 더함
ex) add eax, 3 : eax += 3
sub 연산
sub dst, src: dst에서 src의 값을 뺍니다.
ex) sub eax, 3 : eax -= 3
inc 연산
inc op: op의 값을 1 증가시킴
ex) inc eax : eax += 1
dec 연산
dec op: op의 값을 1 감소 시킴
ex) dec eax : eax -= 1
and, or, xor, not 연산 명령어
and 연산
and dst, src: dst와 src의 비트가 모두 1이면 1, 아니면 0
ex) and eax, ebx
[Reg] : eax = 0x14ff(0001 0100 1111 1111)(2비트), ebx = 0x1234(0001 0010 0011 0100)(2비트)
[Code] : and eax, ebx
[연산 방법] : 모두 1인 경우 1, 아니면 00001 0100 1111 1111 (0x14ff)
& 0001 0010 0011 0100 (0x1234)
= 0001 0000 0011 0100 (0x1034)
[Result] : eax = 0x1034
or 연산
or dst, src: dst와 src의 비트 중 하나라도 1이면 1, 아니면 0
ex) or eax, ebx
[Reg] : eax = 0x14ff(0001 0100 1111 1111)(2비트), ebx = 0x1234(0001 0010 0011 0100)(2비트)
[Code] : or eax, ebx
[연산 방법] : 하나라도 1이면 1, 두 개 다 0인 경우 00001 0100 1111 1111 (0x14ff)
| 0001 0010 0011 0100 (0x1234)
= 0001 0110 1111 1111 (0x14ff)
[Result] : eax = 0x14ff
xor 연산
xor dst, src: dst와 src의 비트가 서로 다르면 1, 같으면 0
ex) xor eax, ebx
[Reg] : eax = 0x14ff(0001 0100 1111 1111)(2비트), ebx = 0x1234(0001 0010 0011 0100)(2비트)
[Code] : xor eax, ebx
[연산 방법] : 서로 다르면 1, 같으면 00001 0100 1111 1111 (0x14ff)
^ 0001 0010 0011 0100 (0x1234)
= 0000 0110 1100 1011 (0x06cb)
[Result] : eax = 0x06cb
not 연산
not op: op의 비트 전부 반전
ex) not eax
[Reg] : eax = 0x14ff(0001 0100 1111 1111)(2비트)
[Code] : not eax
[연산 방법] : 비트 반전, 0 -> 1, 1 -> 0 으로 바꿈!(0x14ff)
! (0001 0100 1111 1111)
= 1110 1011 0000 0000 (0xeb00)
[Result] : eax = 0xeb00
cmp 명령어
cmp op1, op2: op1과 op2를 비교
ex)
mov rax, 0xA
mov rbx, 0xA
cmp rax, rbx ; ZF=1(rax - rbx = 0이므로 Zero Flag가 0으로 설정)
test 명령어
test op1, op2: op1과 op2를 비교
ex)
xor rax, rax (rax를 0으로 만듦)
test rax, rax ; ZF = 1 (rax가 0이므로)
cmp 명령어와 test 명령어의 차이
cmp는 두 피연산자의 차를 이용한 비교이다.
test는 두 피연산자를 and 연산자를 통해서 비교한다.
분기 명령어는 rip(현재 프로그램이 실행되고 있는 위치)를 이동 시켜 실행 흐름을 바꾼다.
분기문은 여기 소개된 것 이외에도 많은 수가 존재한다.
jmp 명령어
jmp addr: addr로 rip를 이동시킵니다.
jmp 명령어는 조건이 어떻든 간에 무조건 가리키는 주소로 분기한다.(무조건 분기)ex)
xor rax, rax (rax == 0)
jmp 1 ; jump to 1조건 상관없이 무조건 1로 분기
je 명령어
je addr: 직전에 비교한 두 피연산자가 같으면 점프 (jump if equal)
ex)
mov rax, 4
mov rbx ,4
cmp rax, rbx (rax == rbx)
je 1 ; jump to 1rax와 rbx는 같으므로 je 조건에 충족, 1로 분기 가능
jg 명령어
jg addr: 직전에 비교한 두 연산자 중 전자가 더 크면 점프 (jump if greater)
ex)
mov rax, 5
mov rbx, 3
cmp rax, rbx ; rax > rbx
jg 1 ; jump to 1rax가 rbx보다 더 크므로 jg 조건에 충족, 1로 분기 가능
CPU의 ISA에 따라 어셈블리어가 다 다르다.
그 중에서 x86-64 어셈블리어를 간략하게 알아 보았다.
다음 시간에는 Background: x86 Assembly - 2를 알아보자.
https://learn.dreamhack.io/37#5 (그림 출처)
https://dreamhack.io/lecture/courses/37, https://dreamhack.io/lecture/courses/63