Computer Security

#15 어셈블리 - 분기명령어 본문

컴퓨터구조&어셈블리어

#15 어셈블리 - 분기명령어

쿠리 Kuri 2022. 5. 29. 18:30

프로그램 실행 흐름 제어

-IP(Instruction Pointer): 다음에 실행할 명령어의 (오프셋) 주소를 저장하는 레지스터

-IP의 값을 변경하여 프로그램의 흐름을 제어할 수 있다.

-프로세서는 이런 프로그램 제어를 위한 일련의 명령어들을 제공한다.(점프(무조건분기),조건부 분기, 서브루틴 호출명령어등등,,)

 

 

조건부 분기의 원리

-조건부 분기는 특정 조건에 따라 프로그램의 실행 흐름을 제어하는 명령어 집합을 의미한다.

-고급 언어의 if, while, for 등의 문법 구조를 구현할 때 조건부 분기 명령어를 사용한다.

-조건부 분기는 상태 플래그 값을 검사해서 분기 여부를 결정한다.

-기본적으로 조건 분기 명령어를 실행하기 전에 산술 및 논리 연산을 실행하지만, 두 값을 단순 비교하기 위해서 비교 명령어를 제공한다.

-비교 명령어는 기본적으로 뺄셈과 같은 효과를 내지만, 레지스터에 들어있는 데이터는 변경하지 않고 상태 플래그에만 영향을 미친다.


 

단거리, 근거리, 원거리 주소

-어셈블러는 현재의 주소로부터 떨어진 거리, 즉 변위(displacement)에 따라 세가지 유형의 주소를 지원한다.

1.단거리(short)주소: -128(80H)~127(7Fh) 바이트 까지의 거리에 제한(8비트 길이)
2.근거리(near)주소: 동일 세그먼트 내에서 -32768(8000H)~32767(7FFFH)바이트까지의 거리제한(16비트 길이)

3.원거리(far)주소: 동일 세그먼트 내에서 32K를 초과한 거리나 다른 세그먼트에 속한 주소

 

제어 명령어들의 거리에 대한 규칙

JMP  : 단거리, 근거리, 원거리

Jnnn: 단거리, 근거리(80386+)

LOOP: 단거리

CALL: 근거리, 원거리

 

 

무조건 분기

JMP 명령어

-지정된 주소로 점프한다.

-단거리(1바이트), 근거리(2바이트) 및 원거리 주소를 지원한다.

-플래그: 아무것도 영향을 미치지 않는다.

  

JMP  reg/mem

 


조건부 분기

-기본적으로 조건부 분기 명령어는 CPU의 상태 플래글르 검사하여 점프 여부를 결정한다.

-분기문을 실행하기 직전에 조건 검사가 필요한 산술 및 논리 연산을 수행하는 경우가 많다.(상태 플래그는 연산을 반영)

-두 값을 비교하는 가장 간단한 방법은 뺄셈이다.

-다음과 같이 op1에서 op2를 빼는 연산을 수행한다면, 그 결과값에 따라 두 값의 대소를 비교할 수 있을 것이다.

      SUB  op1, op2

결과: 양수 -> 상태: op1>op2   (상태플래그에 반영)

결과:  0    -> 상태: op1=op2

결과: 음수 -> 상태: op1<op2

 

비교 명령어

-x86을 포함한 다양한 프로세서들은 레지스터의 데이터를 변경시키지 않으면서도 뺄셈 연산을 한 것과 같은 효과를 상태 플래그에만 반영하는 비교 명령어를 제공한다.

CMP 명령어

-두 피연산자의 값을 비교한다. 플래그 값만 변경시키는 SUB 명령어와 같다.

-플래그:AF, CF, OF, PF, SF, ZF

             CMP reg/mem , reg/mem/imm

 

대소 관계         CF         SF          ZF

op1>op2          0          0            0

op1=op2          0          0            1

op1<op2          1          1            0

 


동등 비교에 따르는 점프

 

JE 명령어: Jump if equal(op1 = op2)

-분기 조건: ZF=1

-플래그: 아무것도 영향을 미치지 않는다.

 

JE label

 

JNE 명령어: Jump if not equal (op1 /= op2)

-분기 조건: ZF=0

-플래그: 아무것도 영향을 미치지 않는다.

 

JNE label

 

JC 명령어: Jump if carry

-분기조건: CF=1

-플래그: 아무것도 영향을 미치지않는다.

 

JC  label

 

JNC 명령어: Jump if not carry

-분기조건: CF=0

-플래그: 아무것도 영향을 미치지 않는다.

 

JNC label

 

JZ 명령어: Jump if zero

-분기조건: ZF=1

-JE와 동일

-플래그: 아무것도 영향을 미치지 않는다.

 

JZ label

 

JNZ명령어: Jump if not zero

-분기조건: ZF = 0

-JNE와 동일

-플래그: 아무것도 영향을 미치지 않는다.

 

JO 명령어: Jump if overflow

-분기조건: OF=1

-플래그: 아무것도 영향을 미치지 않는다.

 

JO label

 

JNO 명령어: Jump if not overflow

-분기조건: OF=0

-플래그: 아무것도 영향을 미치지 않는다.

 

JNO label

 

JS 명령어: Jump if sign (연산의 결과값이 부호비트(SF)가 음수(1)이면 점프)

-분기조건: SF=1

-플래그: 아무것도 영향을 미치지 않는다.

 

JS label

 

JNS 명령어: Jump if not sign

-분기조건: SF=0

-플래그: 아무것도 영향을 미치지 않는다.

 

JNS label

 

JP 명령어: Jump if even parity (짝수 페리티)

-분기조건: PF=1

-플래그: 아무것도 영향을 미치지 않는다.

 

JP/JPE label

 

JNP 명령어: Jump if odd parity (홀수 페리티)

-분기조건: PF=0

-플래그: 아무것도 영향을 미치지 않는다.

 

JNP/JPO label

 

 


 

부호 없는 비교에 따르는 점프

JA 명령어: Jump if above (op1>op2)

-분기 조건: CF=0, ZF=0

-JNBE와 동일

-플래그: 아무것도 영향을 미치지 않는다.

 

JA label

 

JAE 명령어: Jump if above or equal (op1 >= op2)

-분기 조건: CF=0

-JNB와 동일

-플래그: 아무것도 영향을 미치지 않는다.

 

JAE label

 

 

JNA 명령어: Jump if not above (op1<=op2)

-분기 조건: CF=1 or ZF=1

-JBE(below or equal)와 동일

-플래그: 아무것도 영향을 미치지 않는다.

 

JNA label

 

JNAE 명령어: Jump if not above or equal (op1 < op2)

-분기 조건: CF=1

-JB(below)와 동일

-플래그: 아무것도 영향을 미치지 않는다.

 

JNAE label

 

JB 명령어: Jump if below(op1<op2)

-분기조건: CF=1

-JNAE와 동일

-플래그: 아무영향 x

 

JB label

 

JBE 명령어:Jump if below or equal(op1<=op2)

-분기조건: CF=1 or AF=1

-JNA와 동일

-플래그: 아무영향 x

 

JBE label

 

JNB 명령어: Jump if not below(op1>=op2)

-분기조건: CF=0

-JAE와 동일

-플래그: 아무영향 x

 

JNB label

 

JNBE 명령어:Jump if not below or equal(op1>op2)

-분기조건: CF=0, AF=0

-JA와 동일

-플래그: 아무영향 x

 

JNBE label

 


 

부호 있는 비교에 따르는 점프

 

JG 명령어: Jump if greater(op1>op2)

-분기조건:ZF=0, SF=OF

-JNLE 와 동일

-플래그: 아무영향 x

 

JG label

 

JGE 명령어: Jump if greater or equal(op1>=op2)

-분기조건: SF=OF

-JNL과 동일

-플래그: 아무영향x

 

JGE label

 

JNG 명령어: Jump if not greater(op1<=op2)

-분기조건:ZF=1 or SF /=OF

-JLE 와 동일

-플래그: 아무영향 x

 

JNG label

 

JNGE 명령어: Jump if not greater and not equal(op1<op2)

-분기조건: SF/=OF

-JL과 동일

-플래그: 아무영향 x

 

JNGE label

 

JL 명령어: Jump if less(op1<op2)

-분기조건: SF/=OF

-JNGE와 동일

-플래그:아무영향 x

 

JL label

 

JLE 명령어: Jump if less or equal(op1<=op2)

-분기조건: ZF=1 or SF<=OF

-JNG와 동일

-플래그:아무영향 x

 

JLE label

 

 

JNL 명령어: Jump if not less(op1>=op2)

-분기조건: SF=OF

-JGE와 동일

-플래그:아무영향 x

 

JNL label

 

JNLE 명령어: Jump if not less and not equal(op1>op2)

-분기조건: ZF=0, SF=OF

-JG와 동일

-플래그:아무영향 x

 

JNLE label

 


루프 명령어

-고급언어의 for, while 등의 반복문은 분기 명령어와 비교 명령어를 조합하여 구현할 수 있다.

-x86은 루프 카운터(CX,ECX(386+))를 자동 감소 시키는 루프 명령어를 별도로 제공한다.

-루프 명령어 역시 일종의 분기문이라고 할 수 있다.

-x86은 루프 카운터로 CX레지스터 또는 ECX(80386+) 레지스터를 사용한다.

 

LOOP명령어

-CX는 루프 카운터로서 루프 횟수를 지정할 때 사용한다.

-LOOP 명령어는 매 루프마다 루프 카운터 CX를 1씩 자동 감소시킨다.

-80386이상에서 LOOP는 CX를 16비트 모드에서, ECX를 32비트 모드에서 사용한다.

-레이블로 지정 가능한 주소는 단거리 주소(-128~127)로 제한된다.

-플래그: 아무영향 x

 

LOOP label

 

-LOOPW는 16비트 CX를 지정하고, LOOPD는 32비트 ECX를 지정할 수 있다.

 

MOV CX, loop_count 

LOOPW label

W(Word) 의 W사용

 

MOV ECX, loop_count

LOOPD label

D(Double word) 의 D사용

 

LOOPE/LOOPZ 명령어

-LOOP 명령어와 다르게 CX가 0인지 검사하는 대신, ZF=1 인지를 검사한다.

-플래그: 아무영향 x

 

LOOPE / LOOPZ  label

 

LOOPNE/LOOPNZ 명령어

-LOOPE/LOOPZ와 반대로, ZF=0 인지를 검사한다.

-플래그: 아무영향x

 

LOOPNE/LOOPNZ  label

 

 

ex) 

.model small

.stack 100h

.data

arr1 db 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

arr2 dw 197, 254, 242, 236, 326, 627, -1

sum1 db 0

sum2 db 0

 

.code

main proc

   mov ax, @data

   mov ds, ax

   mov ax, 0

 

  mov ax, 0  // ax : 합을 저장할 레지스터로 사용

  lea si, arr1   //si는 arr1의 주소를 가져옴

 mov cx, 10

 

arrSum1:

    add al, [si]    // si = arr1 인상태에서 al안에 si 0번째인 1 추가

    inc si   // si 1증가

    loop arrSum1  //cx 가 10이므로, arrSum1 로 다시 돌아가면서 1감소 : cx=9 ... 반복  cx=0까지)

//10회 실행되면  결과 값 : al = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

   mov sum1, al   // al을 sum1에 넣어준다.

 

 

   mov ax, 0  //ax : 합을 저장할 레지스터로 사용 초기화

   lea si, arr2  //si는 arr2의 주소를 가져옴

 

arrSum2:

  add ax, [si]  //si의 0번째 index 197 을 ax에 추가

  add si, 2 

//si 의 주소값 2씩 증가 (arr2는 Word이므로 2바이트 증가는 옆으로 한칸씩 값나옴. 197->254. db에서 inc랑 같은 역할)

  mov bx, [si]  // 현재 si 값 부분을 bx에 넣는다.

  cmp bx, -1  //bx= -1이 되면(si 값이 -1) , 즉 루프로 회전하다가 si 값이 -1이 되면 멈춤

  loopne arrSum2  //조건 검사 루프 명령어 (loop not equal)  si가 -1이 아니면 루프를 돌린다.

  mov sum2, ax

//결과 값 : sum2 = [197, 254, 242, 236, 326, 627, -1]

Comments