[asm] IA-32 MOV 명령어 해석 [1]

어셈블리어에서 제일 많이 쓰는 명령어는 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 0 1 00 REG R/M
10001001 = 89

Byte1 Byte2 Byte3      
100010 0 1 01 REG R/M Disp1
10001001 = 89

Byte1 Byte2 Byte3 Byte4 Byte5 Byte6
100010 0 1 10 REG R/M Disp1 Disp2 Disp3 Disp4
10001001 = 89

Byte1 Byte2        
100010 0 1 11 REG R/M
10001001 = 89



8B/r  MOV r32, r/m32
Byte1 Byte2        
100010 1 1 00 REG R/M
10001011 = 8B
Byte1 Byte2 Byte3      
100010 1 1 01 REG R/M Disp1
10001011 = 8B

Byte1 Byte2 Byte3 Byte4 Byte5 Byte6
100010 1 1 10 REG R/M Disp1 Disp2 Disp3 Disp4
10001011 = 8B

Byte1 Byte2        
100010 1 1 11 REG R/M
10001011 = 8B



mov eax, [ecx] 는 변위가 없는 메모리 모드이다. 메모리에 접근하지만 변위는 없다.
Byte1 Byte2        
100010 1 1 00 000 001
10001011 00000001 = 8B 01


mov eax, ecx 와 같은 경우 operand 가 둘 다 32비트 레지스터이고 메모리에서 읽지 않으므로 변위(Dislacement) 는 필요가 없다. 따라서 2바이트 로만 구성된다. 둘다 레지스터 이므로 Mod = 11 이다.
 
Byte1 Byte2        
100010 0 1 11 001 000
10001001 11001000 = 89 C8


변위(Displacement)가 있고, 메모리를 접근해야 하는 경우는 다음과 같다. 변위가 8비트 일경우 Mod = 01 이다.

Mod field 를 읽는 법을 알아보자.
 
Mod 설명
00 변위(Displacement) 없는 메모리 모드
01 8비트 변위(+disp8) 메모리 모드
10 32비트 변위(+disp32) 메모리 모드
11 레지스터 모드

mov [ebp-0x08], eax 의 해석은 다음과 같다.

Byte1 Byte2 Byte3      
100010 0 1 01 000 101 11111000
10001001 01000101 11111000 = 89 45 F8

첫번째 operand 가 메모리에 쓰는 형태이므로 명령은 89/r  MOV r/m32, r32 임을 알 수 있다. 첫번째 operand 는 ebp, 두번째 operand 는 eax 이다. 변위는 -0x08 이므로 11111000 = F8 이 된다.


mov eax, [ebp+0x08] 과 같은 명령의 해석은 다음과 같다.

Byte1 Byte2 Byte3      
100010 1 1 01 000 101 00001000
10001011 01000101 00001000 = 8B 45 08

두번째 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 1 1 01 000 001 01111111
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
        a 번지                         a+1 번지                  a+2 번지                  a+3 번지                   a+4 번지


P.S. 어드레싱 방법이 엄청나게 복잡하다. 보는 사람도 어지러운데, 만든 사람은 더 어지럽겠지? -_-;