Programming Tools/Assembly_어셈블리

어셈블리어 정리노트 4 - 조건 분기 명령어

LiDARian 2021. 5. 26. 22:58
반응형

조건분기 JZ

jmp [주소] 이명령어는 무조건분기다.

jz [주소]의 경우, 이전 명령이 결과가 0이면 작동한다.

예를들면

mov eax, 1
inc eax // 2
jz 401005 // 작동ㄴ
dec eax // 1
dec eax // 0
jz 401009 // 작동 ㅇ

상태 레지스터 ZF(Z FLAG)

더 정확히 표현하기 위해 상태레지스터를 소개한다.

CPAZSTDO 등의 1비트 상태레지스터(플래그)를 이용해 조건을 이용하는 명령어들의 동작 여부를 결정한다.
JZ의 경우, Z 플래그가 1이어야 작동한다. Z플래그는 연산의 결과가 0이 되었을 때 1이 된다.

인텔 CPU 기준으로 JEJZ와 같은 기계어를 공유한다. 따라서 둘다 Z플래그가 1일 때 동작한다.

모든 명령어가 플래그를 바꾸는 것은 아니다.
위의 예로는 MOV로는 플래그 불변하지만, INC로는 플래그가 변한다.

JE 명령어

JE는 JUMP IF EQUAL이다.
위의 명령어가 같은 경우(CMP의 계산 결과가 참인 경우) 동작한다.

CMP EAX, 0에서 볼 수 있듯이 CMP명령어는 MOV랑 들어올 수 있는 인자 종류가 같다. 그리고 크기가 같아야 작동한다.

MOV EAX, 0
CMP EAX, 0

같으면 Z 플래그가 1이 된다.

CMP는 내부적으로 빼기(SUB)연산을 이용해서 검사한다. 그래서 Z플래그를 작동시킨다는 것.

조건분기명령어 JNE JNZ JA JB

JNE JNZ는 jump not equal/zero. 이 둘은 같은 기계어를 공유한다. Z플래그가 0일 때 jump한다

mov eax,1
cmp eax,1 // 00401005 // Z = 1
jne 401005 // 동작 ㄴㄴ
cmp eax,0 // Z = 0
jne 401005 // 동작!
// 마지막 줄에서 계속 순환할 것이다

JA JB는 JUMP ABOVE/BELOW라는 뜻이다.
JA는 앞에있는게 뒤에있는 것보다 크면 점프한다. JB는 반대.

MOV EAX, 1
cmp eax,0 //40100F //32비트를 넘어서 올림,빌림이 생기면 C flag 1된다.
jb 40100F // 동작 ㄴㄴ
ja 40100F // 여기서 점프

JA, JBC(carry) Flag로 작동한다. 기준 자리수 넘어갈 때 써주는 그 캐리 맞다. 자리 올림의 의미
borrow도 C FLAG를 통해 표현된다.

JA는 C=0 AND Z=0일 때 작동한다.
JB는 C=1에서 동작한다. Z는 상관없다.

각 분기명령어에 대한 분기 조건은 이곳 그리고 이곳에서 볼 수 있다.

조건분기명령어 JNA JNB

JA, JB가 A>B, A<B 라면
JNA, JNB는 그 반대다. 즉 A<=B, A>=B이다.
JNA, JNB는 Z,C 플래그에 의해서 움직인다.
JAE=JNB는 C=0,Z=0 혹은 C=0,Z=1일때, JBE=JNA는 C=1 혹은 Z=1일때 작동한다.

MOV EAX, 1
CMP EAX, 2 // 40100F, C=1 Z=0
JNB SHORT 40100F // 미작동
JNA SHORT 40100F // 작동

JAE=JNB는 C=0,Z=0 혹은 C=0,Z=1일때, JBE=JNA는 C=1 혹은 Z=1일때 작동한다. 이 조건에 충실하다.

MOV EAX, 1 // 40100F
CMP EAX, 1 // C=0, Z=0
JNB SHORT 40100F // 동작

물론이상황에서는 분기하는 것이 맞지만(C=0,Z=0이므로) 만약 일부러 플래그를 C=1,Z=1으로 만들거나 C=1,Z=0으로 만들면, JNB는 작동하지 않는다.

다른 분기 명령어에서는,
JZ는 Z=1에서, JC는 C=1 일 때 분기한다.
JNZ Z=0, JNC는 C=0 일 때 분기한다.

JG JL

JA, JB는 UNSIGN를 가정하고 동작한다.
JG, JL은 SIGNED를 가정한다.

따라서 두 명령어는 동작 여부를 판단하는데 사용하는 상태플래그가 다르다.

CMP 1010, 0001 // -4, 1라고하면
JAJB면 양수(B1001=9), JGJL은 음수(-5)인 결과라고 생각한다

JGE, JLE, JS, JO

JS, JO는 각 플래그가 1이면 점프.

S는 계산결과가 음수면 1, O는 계산결과가 오버플로에서 1로 뜬다.

JG는 Z=0 그리고 S(SIGN FLAG)=O(OVERFLOW FLAG)이면동작한다.

 

OVERFLOW와 CARRY

0001 // 1
1100 // -4
-
0101 // 5

이 경우 캐리는 발생 오버플로는 ㄴㄴ

1-(-4)를 1+4로 바꿔서

0001 // 1
0100 // 4
+
0101 // 5

즉 앞이 더 큰 경우는 오버플로우 안나오고, S는 0이다

만약

0001 // 1
0111 // 7
+
1000 // -8

이면 S=1,O=1이다. 오버플로 때문에 음수된거라는 표시다.
이런 경우에도 JG는 동작해야한다.
따라서 JG는 S=0(OVERFLOW)이고, Z=0인 경우에 동작해야한다.

JL은 S != O인 경우에 동작한다.

오버플로 없는 경우 음수
오버플로인 경우 양수

사인은 0인데 오버플로가 1일 때, 0이 결과인 경우는 없다.
따라서 JG와는 다르게 Z FLAG를 신경쓰지 않아도 된다.

0
0
-
0

..

1
1
-
0

오버플로는 캐리와는 다르다. 캐리는 올림으로 맨위(최상단)비트를 넘어가면 발생.
오버플로는 사인비트와 관계. UNSIGNED에서는 오버플로우와 사인 플래그를 신경쓰지 않아도 된다.
그 표현범위를 넘어가는 다른 표현이 발생하면 생긴다. 같은 부호의 연산을 했는데 다른 부호가 나온 것으로 판별할 수 있다.

0111
0001
+
1000

오버플로 발생. 캐리는 아니다.

1111
1111
0000

오버플로우, 캐리 모두 발생

1111
0001
10000

캐리만 발생 오버플로우 아님


참고

각 분기 명령어에 따른 검사 대상 플래그

https://www.tutorialspoint.com/assembly_programming/assembly_conditions.htm

http://unixwiz.net/techtips/x86-jumps.html

컴푸터가 음수를 만드는 방법 : 2의 보수법

https://m.blog.naver.com/PostView.naver?blogId=sunnuk&logNo=140200174195&proxyReferer=https:%2F%2Fwww.google.com%2F)

상태 플래그, 특히 CARRY와 OVERFLOW 플래그의 차이

https://asukim.tistory.com/m/13

https://dhhd-goldmilk777.tistory.com/m/31

https://m.blog.naver.com/PostView.naver?blogId=window__han&logNo=80166632434&proxyReferer=https:%2F%2Fwww.google.com%2F

https://m.blog.naver.com/PostView.naver?blogId=qbxlvnf11&logNo=221349604639&proxyReferer=https:%2F%2Fwww.google.com%2F

https://ko.m.wikipedia.org/wiki/%EC%83%81%ED%83%9C_%EB%A0%88%EC%A7%80%EC%8A%A4%ED%84%B0

 

 

 

반응형