어셈블리 – CMP 명령 MASM32

어셈블리 – CMP 명령 MASM32

CMP 명령은 비교 명령으로, 이를 하기전에 플래그라는 개념을 이해할 필요가 있다. (앞서 EFLAGS 레지스터로 설명하였지만 다시 설명 하도록 하겠다.)

플래그는 비교적 간단하다. 플래그는 CPU 의 (E)FLAGS 레지스터에 저장되는 처리 데이터로, (E)FLAGS 의 한 비트가 한 플래그가 된다. 명령어들을 실행하면서 각 실행 결과에 따라서 플래그가 변경된다. (xor eax, eax 를 실행하면 Z(Zero) 플래그가 설정된다.) 이렇게 CMP명령을 이용하여 비교 결과를 플래그에 남기고 J로 시작하는 조건 분기 명령들을 이용하여, 각 플래그의 상태에 따라서 점프를 할 수 있는 분기점을 만드는 것이다.

CMP의 경우 첫번째 연산자가 두번째 연산자보다 작을 경우(즉 첫번째 연산자 – 두번째 연산자가 마이너스일 경우) CF(캐리 플래그)가 설정(1)된다.

첫번째 연산자에서 두번째 연산자를 뺀 결과가 0 일 경우 ZF(제로 플래그)가 설정(1)된다. (프로그래밍에서도 1은 TRUE와 같은 의미를 가진다. FALSE의 경우 0과 혼용하여 설정할 수 있다.)

조건 분기 명령은 아래와 같다.

JE:

두 피연산자의 내용이 같을 경우 지정 주소로 점프 (ZF=1)

JA:

부호가 없는 비교에서 첫번째 피연산자가 더 큰경우 지정 주소로 점프 (CF=0 and ZF=0)

JB:

부호가 없는 비교에서 두번째 피연산자가 더 큰경우 지정 주소로 점프 (CF=1)

JAE:

부호가 없는 비교에서 첫번째 피연산자가 더 크거나 같은 경우 지정 주소로 점프 (CF=0)

JBE:

부호가 없는 비교에서 두번째 피연산자가 더 크거나 같은 경우 지정 주소로 점프 (CF=1 and ZF=1)

JG:

부호가 있는 비교에서 첫번째 피연산자가 더 큰경우 지정 주소로 점프 (ZF=0 and SF=OF)

JL:

부호가 있는 비교에서 두번째 피연산자가 더 큰경우 지정 주소로 점프 (SF!=OF)

JGE:

부호가 있는 비교에서 첫번째 피연산자가 더 크거나 같은 경우 지정 주소로 점프 (SF=OF)

JLE:

부호가 있는 비교에서 두번째 피연산자가 더 크거나 같은 경우 지정 주소로 점프 (ZF=1 and SF!=OF)

* N이 들어가면 조건이 반대가 된다. 예) JNG : 크지 않으면 지정 주소로 점프

JC:

CARRY 플래그 값이 설정(1)되어 있으면 지정 주소로 점프 (CF=1)

JNC:

CARRY 플래그 값이 설정되어 있지 않으면 지정 주소로 점프 (CF=0)

JO:

OVERFLOW 플래그 값이 설정(1)되어 있으면 지정 주소로 점프 (OF=1)

JNO:

OVERFLOW 플래그 값이 설정되어 있지 않으면 지정 주소로 점프 (OF=0)

JP(JPE):

PARITY 플래그 값이 설정(1)되어 있으면 지정 주소로 점프 (PF=1)

JNP(JPO):

PARITY 플래그 값이 설정되어 있지 않으면 지정 주소로 점프 (PF=0)

JS:

SIGNAL 플래그 값이 설정(1)되어 있으면 지정 주소로 점프 (SF=1)

JNS:

SIGNAL 플래그 값이 설정되어 있지 않으면 지정 주소로 점프 (SF=0)

JCXZ:

CX레지스터 값이 설정되어 있지 않으면 지정 주소로 점프 (CX=0)

플래그 레지스터(제어/상태 표시 레지스터)

어셈블리는 조건 분기를 이 플래그 레지스터를 이용하여 변경하게 된다.

[그림] Ollydbg에서 확인할 수 있는 플래그 레지스터

O
D T
S
Z
A
P
C

모든 산술연산 및 논리연산이 끝난후에 결과값에 대해 상태 플래그를 설정(1)하게 된다.

D T: 제어 플래그

O
S
Z
C

P
A: 상태 플래그

이중 많이 사용되는 플래그인 상태 플래그는 연산결과가 아래와 같을 때 설정(1)된다.

S : Sign Flag: 연산 결과가 1일 때 설정(1) 됨

Z : Zero Flag: 연산 결과가 0일 때 설정(1) 됨

C : Carry Flag: 연산 결과가 저장공간을 벗어날경우 값이 1일때 설정(1) 됨 (부호가 없는 경우)

O : Overflow Flag: 연산된 결과값이 1비트를 넘어셨을때 설정(1) 됨(부호가 있을 경우)

[내용] 조건 분기 명령

이제 CMP명령과 조건 분기 명령을 이용하여, EAX 레지스터 값이 EBX의 레지스터 값과 같을시 루프(Loop)를 빠져나오는 예제이다.

masm4.asm
.586

.model flat, stdcall

option casemap:none

.code

main    proc

; 스택 프롤로그 부분이다.

push ebp

mov ebp, esp

sub esp, 8h

; 생성한 스택공간에 10, 20이라는 값을 넣는다.

mov dword ptr [ebp-4], 10h

mov dword ptr [ebp-8], 20h

; 스택 공간에 넣은 값을 EAX와 EBX 레지스터에 복사한다.

mov eax, dword ptr [ebp-4]

mov ebx, dword ptr [ebp-8]

; 반목문을 실행한다. 이 반복문은 CMP 명령을 이용하여 EAX, EBX 레지스터를 비교하고, JE(값이 같거나,) JA(EAX 레지스터 값이 큰경우) 조건에 맞는 경우 빠져나가는 반복문이다.

Start:

inc eax

cmp eax, ebx

je Exit

ja Exit

jmp Start

Exit:

pop ebp

retn

main endp

end main

[그림] 비교문과 조건문 사용 예제

위 프로그램을 컴파일한후 분석을 진행해 보자.

앞서 분석에 설명한 내용들은 생략하고, 비교문과 조건문에 대해서 분석을 해 보도록 하겠다.

// 스택 프롤로그, 앞서 진행한 내용들로 스택에 2개의 데이터를 저장한다.
00401000 m>/$ 55 PUSH EBP

00401001 |. 8BEC MOV EBP,ESP

00401003 |. 83EC 08 SUB ESP,8

00401006 |. C745 FC 10000000 MOV [LOCAL.1],10

0040100D |. C745 F8 20000000 MOV [LOCAL.2],20

// EAX 레지스터에 10, EBX레지스터에 20의 값을 복사한다.

00401014 |. 8B45 FC MOV EAX,[LOCAL.1]

00401017 |. 8B5D F8 MOV EBX,[LOCAL.2]

// 아래 내용이 코드로 작성한 Start의 반복문이다.

// INC명령을 통해 EAX 레지스터의 값을 1증가시킨다.

0040101A |> 40 /INC EAX

0040101B |. 3BC3 |CMP EAX,EBX

// CMP 결과, Z 플래그 레지스터의 값이 1이면 401023으로 점프한다.

0040101D |. 74 04 |JE SHORT masm4.00401023

// CMP 결과, C 플래그 레지스터의 값이 0이고, Z 플래그 레지스터 값이 0이면 401023으로 점프한다.

0040101F |. 77 02 |JA SHORT masm4.00401023

// 위 결과와 맞지 않다면 040101A로 이동한다.

00401021 |.^ EB F7 \JMP SHORT masm4.0040101A

[그림] CMP문을 실행하면 FLAG레지스터가 설정된다

// 함수 에필로그 부분이다.

00401023 |> 5D POP EBP

00401024 \. C3 RETN

[내용] CMP 명령 예제

TEST 명령
내부적으로 AND연산을 수행하고, Dest, Sour를 AND한 후 결과값의 상태 정보만 플래그 레지스터에 저장하게된다. 자신의 값의 상태를 확인하고 싶을 때 주로 이용되며, MOV명령으로는 플래그 레지스트리 정보 갱신을 하지 않으므로, 이 명령을 통해 플래그 레지스터를 갱신하여 조건을 설정하게 된다. 즉 플래그 값을 이용하기 위해 사용하는 명령어이다.

OF, CF는 초기화되고, ZF는 설정 될 수 있다.

Facebook Comments

Leave A Reply

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.