조건분기 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 기준으로 JE
는 JZ
와 같은 기계어를 공유한다. 따라서 둘다 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, JB
는C(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의 보수법
상태 플래그, 특히 CARRY와 OVERFLOW 플래그의 차이
https://asukim.tistory.com/m/13
https://dhhd-goldmilk777.tistory.com/m/31
https://ko.m.wikipedia.org/wiki/%EC%83%81%ED%83%9C_%EB%A0%88%EC%A7%80%EC%8A%A4%ED%84%B0
'Programming Tools > Assembly_어셈블리' 카테고리의 다른 글
어셈블리어 정리노트 3 - 주소 참조 연산자 [], 오프셋, 인덱스 (dereference, offset, index) (0) | 2021.05.26 |
---|---|
어셈블리어 정리노트 3 - JMP, INC, DEC, ADD, SUB (0) | 2021.05.19 |
어셈블리어 정리노트 2 (0) | 2021.05.10 |
어셈블리어 정리노트 1 (0) | 2021.05.09 |