[리버싱] 어셈블리어란
어셈블리어의 구조
어셈블리어는 기본적으로 명령어 (OpCode) 와 오퍼랜드 (Operand) 로 이루어져 있다. Operand 는 명령어 다음에 오는 레지스터 이름이나 값 즉, 명령 대상이 되는 레지스터나 값이다. 명령어를 Operator (연산자) 라고 부르며 이러한 Operator 의 종류에 따라 오퍼랜드의 개수가 다르다.
EX) MOV EAX, val1
operator operand1, operand2
어셈블리어 문법
어셈블리어의 문법에는 크게 Intel 방식과 AT&T 방식이 있는데 그 둘의 차이점은 다음과 같다.
Register 이름
AT&T 문법에서는 모든 레지스터 이름 앞에 %가 붙는다. 이는 레지스터와 다른 심볼을 혼동하지 않게 하는 장점이 있다.
예를 들어 eax 레지스터를 나타내는 경우
AT&T : %eax
Intel : eax
Operand 순서
AT&T 문법에서는 원본(source)이 왼쪽, 목적지(destination)가 오른쪽에 위치한다. Intel 문법에서는 이와 반대로 되어있다.
예를 들어 eax 에서 ebx 레지스터로 데이터를 복사하는 경우
AT&T : movl %eax, %ebx
Intel : mov ebx, eax
Operand 크기 지정
operand 의 크기를 지정할 때 크기에 따라 b (byte), w (word), l (long) 접미사를 명령어에 붙인다.
operand 로 지정된 레지스터를 가지고 크기를 판단할 수 있을 때는 이를 생략할 수 있으며, 판단할 수 없는 경우 32-bit 연산으로 가정하게 된다.
operand가 레지스터가 아니라 메모리인 경우는 반드시 접미사를 붙이는 게 좋다.
Intel 에서는 byte ptr, word ptr, dword ptr 같은 지시자 (specifier) 를 사용하여 이를 나타낸다.
예를 들어 word 크기의 foo 값을 bx 로 복사하는 경우
AT&T : movw foo, %ax
Intel : mov ax, word ptr [foo]
상수 (constant) 와 immediate 값
모든 상수와 immediate 값에는 $가 붙는다. 예를 들어 숫자 5를 나타내려면 $5라고 한다.
변수의 주소를 나타낼 때에도 앞에 $를 붙인다. 예를 들어 foo 란 변수의 주소는 $foo 이다. 그냥 foo 라고 하면 변수의 값을 나타내게 된다.
foo 변수의 주소를 eax 레지스터로 복사하는 경우
AT&T : lea $foo, %eax
Intel : lea eax, [foo]
숫자 0xd00d 를 eax 레지스터로 복사하는 경우
AT&T : movl $0xd00d, %eax
Intel : mov eax, 0d000h
메모리 참조
AT&T 문법은 소괄호를 이용해 10(%eax) 과 같이 표현하지만 Intel 문법은 대괄호 안에 주소를 넣어 [eax+10] 과 같이 표현한다.
eax 레지스터가 가리키는 주소의 값을 참조하는 경우
AT&T : (%eax)
Intel : [eax]
레지스터에 변수(var)의 옵셋을 합한 주소를 참조하는 경우
AT&T : var(%eax)
Intel : [eax + var]