어셈블리어에서 제일 많이 쓰는 명령어는 mov 명령일 것이다. mov 명령어에도 종류가 많지만 3개만 알아본다.
(1) 레지스터에서 메모리 또는 레지스터로 값을 이동
(2) 레지스터 또는 메모리에서 값을 읽어서 레지스터에 이동
(3) 레지스터에 직접값을 입력(immediate operand)
(1), (2) 의 Instruction Format 은 다음과 같다.
Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | ||||
100010 | D | W | Mod | REG | R/M | Disp1 | Disp2 | Disp3 | Disp4 |
D(Direction)는 1bit 이며 REG 가 가리키는 레지스터의 방향이다. D=0 이면 (Source) 레지스터로부터 데이터를 읽는 것이고, D=1 (Destination)이면 레지스터에 값을 넣는것을 뜻한다. r32 는 REG 를 뜻하므로 r32 가 첫번째 operand 인가, 아니면 두번째 operand 인가에 따라서 D 의 값이 달라진다. r32가 첫번째 operand라면 D=1 이다. 두번째 operand 라면 D=0 이다.
D | Source | Destination |
0 | reg Field | ModR/M or SIB Byte |
1 | ModR/M or SIB Byte | reg Field |
W는 1bit 이며 레지스터의 형태를 나타낸다. W=0 이면 8비트 레지스터이고, W=1 이면 32비트 레지스터를 뜻한다.
REG | W = 0 | W = 1 |
000 | AL | EAX |
001 | CL | ECX |
010 | DL | EDX |
011 | BL | EBX |
100 | AH | ESP |
101 | CH | EBP |
110 | DH | ESI |
111 | BH | EDI |
32비트 레지스터만을 생각한다면, W=1 이 된다.
32비트 레지스터라고 생각하고 r32 의 위치를 바꾸었을때 instruction format 은 다음과 같다.
89/r MOV r/m32, r32
Byte1 |
Byte2 |
||||||||
100010 |
REG |
R/M |
Byte1 |
Byte2 |
Byte3 |
|||||||
100010 |
REG |
R/M |
Disp1 |
Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | ||||
100010 | 0 | 1 | 10 | REG | R/M | Disp1 | Disp2 | Disp3 | Disp4 |
Byte1 |
Byte2 |
||||||||
100010 |
REG |
R/M |
8B/r MOV r32, r/m32
Byte1 |
Byte2 |
||||||||
100010 |
REG |
R/M |
Byte1 |
Byte2 |
Byte3 |
|||||||
100010 |
REG |
R/M |
Disp1 |
Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | ||||
100010 | 1 | 1 | 10 | REG | R/M | Disp1 | Disp2 | Disp3 | Disp4 |
Byte1 |
Byte2 |
||||||||
100010 |
REG |
R/M |
mov eax, [ecx] 는 변위가 없는 메모리 모드이다. 메모리에 접근하지만 변위는 없다.
Byte1 |
Byte2 |
||||||||
100010 |
mov eax, ecx 와 같은 경우 operand 가 둘 다 32비트 레지스터이고 메모리에서 읽지 않으므로 변위(Dislacement) 는 필요가 없다. 따라서 2바이트 로만 구성된다. 둘다 레지스터 이므로 Mod = 11 이다.
Byte1 |
Byte2 |
||||||||
100010 |
변위(Displacement)가 있고, 메모리를 접근해야 하는 경우는 다음과 같다. 변위가 8비트 일경우 Mod = 01 이다.
Mod field 를 읽는 법을 알아보자.
Mod | 설명 |
00 | 변위(Displacement) 없는 메모리 모드 |
01 | 8비트 변위(+disp8) 메모리 모드 |
10 | 32비트 변위(+disp32) 메모리 모드 |
11 | 레지스터 모드 |
mov [ebp-0x08], eax 의 해석은 다음과 같다.
10001001 01000101 11111000 = 89 45 F8
Byte1 |
Byte2 |
Byte3 |
|||||||
100010 |
첫번째 operand 가 메모리에 쓰는 형태이므로 명령은 89/r MOV r/m32, r32 임을 알 수 있다. 첫번째 operand 는 ebp, 두번째 operand 는 eax 이다. 변위는 -0x08 이므로 11111000 = F8 이 된다.
mov eax, [ebp+0x08] 과 같은 명령의 해석은 다음과 같다.
10001011 01000101 00001000 = 8B 45 08
mov eax, [ebp+0x08] 과 같은 명령의 해석은 다음과 같다.
Byte1 |
Byte2 |
Byte3 |
|||||||
100010 |
두번째 operand 가 메모리에서 읽는 형태이므로 명령은 8B/r MOV r32, r/m32 임을 알 수 있다. 첫번째 operand 는 eax, 두번째 operand 는 ebp 이다. 변위는 0x08 이므로 00001000 = 08 이 된다.
mov eax, [ecx+128] 이라면 8비트 변위(-128 ~ +127)를 초과하므로 32비트 변위를 사용한다.
Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | ||||
100010 | 1 | 1 | 10 | 000 | 001 | 10000000 | 00000000 | 00000000 | 00000000 |
10001011 10000001 10000000 00000000 00000000 00000000 = 8B 81 80 00 00 00
mov eax, [ecx+127] 는 8비트 변위 안에 있으므로 다음과 같이 3바이트 명령어가 된다.
Byte1 |
Byte2 |
Byte3 |
|||||||
100010 |
10001011 01000001 01111111 = 8B 41 7F
(3)의 Instruction Format 은 다음과 같다.
Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | ||
1011 | W | REG | Data1 | Data2 | Data3 | Data4 |
앞에서 본 것처럼 W 는 REG 의 레지스터 형식이다. W=1 이면 REG 는 32비트 레지스터이다. EAX 이면 REG = 000 이므로 Opcode 는 10111000 = B8 이 된다. REG 가 ECX 이면 REG = 001 이므로 Opcode 는 10111001 = B9 이다.
mov operand1 | Byte1 | |||
Hexadecimal | 1011 | W | REG | |
mov al | B0 | 1011 | 0 | 000 |
mov cl | B1 | 1011 | 0 | 001 |
mov dl | B2 | 1011 | 0 | 010 |
mov bl | B3 | 1011 | 0 | 011 |
mov ah | B4 | 1011 | 0 | 100 |
mov ch | B5 | 1011 | 0 | 101 |
mov dh | B6 | 1011 | 0 | 110 |
mov bh | B7 | 1011 | 0 | 111 |
mov eax | B8 | 1011 | 1 | 000 |
mov ecx | B9 | 1011 | 1 | 001 |
mov edx | BA | 1011 | 1 | 010 |
mov ebx | BB | 1011 | 1 | 011 |
mov esp | BC | 1011 | 1 | 100 |
mov ebp | BD | 1011 | 1 | 101 |
mov esi | BE | 1011 | 1 | 110 |
mov edi | BF | 1011 | 1 | 111 |
mov eax, 0x01020304 는 다음과 같이 표현된다.
Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | ||
1011 | 1 | 000 | 00000100 | 00000011 | 00000010 | 00000001 |
10111000 00000100 00000011 00000010 00000001 = B8 04 03 02 01
IA-32 는 리틀 엔디언(Little Endian) 이다. 리틀 엔디언은 바이트 단위로 끊어서 높은 주소로 올라갈수록 낮은 자리수로 끝나는 것을 뜻한다. 위의 instruction 에서 Byte1 은 낮은주소, Byte5 는 높은 주소이다. 0x01020304 에서 04 는 낮은 자리, 01은 높은 자리이다. 바이트 단위로 끊는다는 점에 주의해야 한다. 바이트 단위로 끊으면 01 02 03 04 의 4개가 나온다. 이것을 높은 자리순으로 배열한 것인가 낮은 자리순으로 배열한 것인가 생각하는 것이다.
←낮은 주소 높은 주소→
Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | ||
1011 | 1 | 000 | 00000100 | 00000011 | 00000010 | 00000001 |
P.S. 어드레싱 방법이 엄청나게 복잡하다. 보는 사람도 어지러운데, 만든 사람은 더 어지럽겠지? -_-;
'기술탐구' 카테고리의 다른 글
[asm] IA-32 MOV 명령어 해석 [3] (0) | 2008.09.07 |
---|---|
[asm] IA-32 MOV 명령어 해석 [2] (0) | 2008.09.07 |
[asm] IA-32 Instruction 에서 ModR/M byte 의 해석. (2) | 2008.08.28 |
[C++Builder] property 의 유용성 (0) | 2008.08.26 |
[C++Builder] www.winapi.co.kr 의 api 예제를 실행해보기. (0) | 2008.08.18 |