Operation | Description |
---|---|
AND | Boolean AND operation between a source oprand and a destination operand |
OR | Boolean OR operation between a source oprand and a destination operand |
XOR | Boolean exclusive-OR operation between a source operand and destination operand |
NOT | Boolean NOT operation on a destination operand |
TEST | Implied boolean AND operation between a source and destination operand, setting the CPU flags appropriately |
Intel 명령어 세트에는 AND, OR, XOR, NOT 명령이 포함되어 있으며, 이 명령들은 바이너리 비트에 대해 직접적으로 Boolean 연산을 구현합니다.
AND: 소스 피연산자와 목적지 피연산자 사이의 불린 AND 연산을 수행합니다. 두 비트가 모두 1일 때만 결과가 1이 됩니다.
OR: 소스 피연산자와 목적지 피연산자 사이의 불린 OR 연산을 수행합니다. 두 비트 중 하나라도 1이면 결과는 1이 됩니다.
XOR: 소스 피연산자와 목적지 피연산자 사이의 불린 exclusive-OR 연산을 수행합니다. 두 비트가 다르면 결과는 1이 됩니다.
NOT: 목적지 피연산자에 대한 불린 NOT 연산을 수행합니다. 비트를 반대로 바꾸며, 1은 0으로, 0은 1로 바뀝니다.
TEST: 소스 피연산자와 목적지 피연산자 사이의 묵시적인 불린 AND 연산을 수행하고, CPU 플래그를 적절하게 설정합니다. 결과값은 버려지고, CPU 상태 플래그만 변경됩니다.
Boolean instructions affect the Zero, Carry, Sign, Overflow, and Parity flags
Boolean 명령어는 Zero, Carry, Sign, Overflow, Parity 플래그에 영향을 미칩니다.
이러한 플래그들은 조건부 분기, 즉 조건에 따라 다른 코드를 실행하는 기능을 지원하는데 중요하게 사용됩니다. 예를 들어, 특정 연산 후에 Zero 플래그가 설정되었는지를 확인함으로써 연산 결과가 0인지 아닌지를 알 수 있고, 이를 바탕으로 프로그램의 동작을 조건적으로 변경할 수 있습니다.
The AND instruction performs a boolean (bitwise) AND operation between each pair of matching bits in two operands and places the result in the destination operand
AND destination, source
AND reg, reg
AND reg, mem
AND mem, reg
AND mem, imm
AND reg, imm
X | Y | X ^ Y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Bit masking
and AL, 11110110b
Flags
Converting Characters to Upper case
0 1 1 0 0 0 0 1 = 61h ('a')
0 1 0 0 0 0 0 1 = 41h ('A')
.data
array BYTE 50 DUP (?)
.code
mov ecx, LENGTHOF array
mov esi, OFFSET array
L1: and BYTE PTR [esi],11011111b ; clear bit 5
inc esi
loop L1
AND 명령어는 두 피연산자의 일치하는 비트 각각에 대해 불린 AND 연산을 수행하고 결과를 목적지 피연산자에 위치시킵니다. 이 명령어의 기본 형태는 다음과 같습니다.
AND destination, source
다음은 허용되는 피연산자 조합입니다:
AND reg, reg
AND reg, mem
AND mem, reg
AND mem, imm
AND reg, imm
비트 단위의 AND 연산은 각각의 비트에 대해 수행되며, 두 비트가 모두 1일 때만 결과가 1이 됩니다.
X | Y | X ^ Y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
피연산자는 8, 16, 32, 또는 64비트일 수 있으며, 동일한 크기를 가져야 합니다. 즉시 피연산자(Immediate operand)는 32비트를 초과할 수 없습니다.
Bit Masking
AND 명령어를 사용하면 다른 비트에 영향을 미치지 않고 피연산자의 1개 이상의 비트를 지울 수 있습니다. 예를 들어, AL 레지스터에서 하드웨어 장치로 제어 바이트를 복사하려고 합니다. 이 장치는 제어 바이트의 0번과 3번 비트가 클리어되면 재설정된다고 가정합시다. 이때 다른 비트를 수정하지 않고 장치를 재설정하려면 다음과 같이 쓸 수 있습니다:
and AL, 11110110b
이렇게 하면 AL의 0번과 3번 비트만 클리어됩니다.
Flags
AND 명령어는 항상 Overflow와 Carry 플래그를 클리어합니다. 그리고 목적지 피연산자에 따라 Sign, Zero, Parity 플래그를 수정합니다.
Converting Characters to Upper case
AND 연산을 사용하면 소문자를 대문자로 쉽게 변환할 수 있습니다. 대문자 'A'와 소문자 'a'의 ASCII 코드를 비교하면 5번째 비트만 다른 것을 볼 수 있습니다.
0 1 1 0 0 0 0 1 = 61h ('a')
0 1 0 0 0 0 0 1 = 41h ('A')
나머지 알파벳 문자들도 같은 관계를 가지고 있습니다. 따라서 11011111 바이너리와 어떤 문자를 AND 연산하면 모든 비트는 그대로 유지되고 5번째 비트만 클리어되므로, 소문자는 대문자로 변환됩니다.
다음 예제는 배열의 모든 문자를 대문자로 변환하는 것입니다:
.data
array BYTE 50 DUP (?)
.code
mov ecx, LENGTHOF array
mov esi, OFFSET array
L1: and BYTE PTR [esi],11011111b ; clear bit 5
inc esi
loop L1
위의 코드에서, and BYTE PTR [esi],11011111b라는 명령은 각 문자(배열의 각 요소)에 대해 비트 5를 클리어합니다. 이렇게 하면 소문자 알파벳이 대문자로 변환됩니다. 이 작업이 배열의 모든 문자에 대해 반복되며, inc esi와 loop L1 명령어에 의해 배열의 다음 요소로 이동합니다. 이 과정을 배열의 모든 요소에 대해 수행하여 최종적으로 모든 문자를 대문자로 변환합니다.
The OR instruction performs a boolean OR operation between each pair of matching bits in two operands and places the result in the destination operand
OR destination, source
OR reg, reg
OR mem, reg
OR reg, mem
OR mem, imm
OR reg, imm
X | Y | X ˇ Y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
The OR instruction is particularly useful when you need to set 1 or more bits in an operand without affecting any other bits
or AL, 00000100b
Flags
OR 명령어는 두 피연산자의 일치하는 각 비트 사이에 불린 OR 연산을 수행하고 결과를 목적지 피연산자에 위치시킵니다. 이 명령어의 기본 형태는 다음과 같습니다.
OR destination, source
다음은 허용되는 피연산자 조합입니다:
OR reg, reg
OR mem, reg
OR reg, mem
OR mem, imm
OR reg, imm
비트 단위의 OR 연산은 각각의 비트에 대해 수행되며, 두 비트 중 하나라도 1일 때 결과가 1이 됩니다.
X | Y | X ˇ Y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
피연산자는 8, 16, 32, 또는 64비트일 수 있으며, 동일한 크기를 가져야 합니다.
OR 명령어는 다른 비트에 영향을 미치지 않고 피연산자의 하나 이상의 비트를 설정할 필요가 있을 때 특히 유용합니다. 예를 들어, 컴퓨터가 서보 모터에 연결되어 있고, 이는 제어 바이트의 비트 2를 설정함으로써 활성화된다고 가정합시다. AL 레지스터가 각 비트에 중요한 정보를 포함하는 제어 바이트를 포함한다고 가정하면, 다음 코드는 위치 2에 있는 비트만 설정합니다:
or AL, 00000100b
Flags
OR 명령어는 항상 Carry와 Overflow 플래그를 클리어합니다. 그리고 목적지 피연산자에 따라 Sign, Zero, Parity 플래그를 수정합니다. 이러한 플래그들은 명령어 실행 후에 발생한 상태를 나타내고, 다른 명령어의 실행 흐름을 제어하는 데 사용될 수 있습니다.
Some applications manipulate sets of items selected from a limited-sized universal set
Rather than holding pointers or references to objects in a container, an application can use a bit vector to map the bits in a binary number to an array of objects
An example
SetX = 10000000 00000000 00000000 00000111
(The byte have been separated to improve readability)
We can easily check for set membership by ANDing a particular member’s bit position with a 1
mov eax, SetX
and eax, 10000b ; is element[4] a member of SetX?
Set Complement
mov eax, SetX
not eax ; complement of SetX
Set Intersection
mov eax, SetX
and eax, SetY
Set Uniton
mov eax, SetX
or eax, SetY
비트 매핑된 집합은 제한된 크기의 유니버설 집합에서 선택된 아이템의 집합을 조작하는 일부 애플리케이션에서 사용됩니다. 예를 들어, 회사 내의 직원들이나 날씨 모니터링 스테이션에서의 환경 데이터 등이 이에 해당합니다. 이런 경우에는 이진 비트가 집합 멤버십을 나타낼 수 있습니다.
컨테이너에 객체에 대한 포인터나 참조를 보관하는 대신, 애플리케이션은 비트 벡터를 사용해 이진 숫자의 비트를 객체의 배열에 매핑할 수 있습니다.
예시
다음 이진 숫자는 오른쪽에서 0부터 왼쪽으로 31까지의 비트 위치를 사용하여 배열 요소 0, 1, 2, 그리고 31이 SetX라는 집합의 멤버임을 나타냅니다.
SetX = 10000000 00000000 00000000 00000111
(The byte have been separated to improve readability)
특정 멤버의 비트 위치를 1과 AND 연산하면 쉽게 집합 멤버십을 확인할 수 있습니다.
mov eax, SetX
and eax, 10000b ; is element[4] a member of SetX?
이 예시에서 AND 명령어가 Zero 플래그를 클리어하면, 우리는 element [4]가 SetX의 멤버임을 알 수 있습니다.
이 예제에서는 비트 맵을 사용해 집합(SetX)에서 특정 요소(element[4])의 멤버십을 테스트하는 방법을 보여줍니다. 여기서 집합은 이진 숫자로 표현되며, 각 비트 위치는 집합의 특정 요소를 나타냅니다.
먼저, mov eax, SetX 명령어를 사용하여 집합 SetX를 EAX 레지스터로 복사합니다. 이진 수 SetX의 각 비트는 배열 요소의 인덱스를 나타냅니다. 비트가 1이면 해당 인덱스의 배열 요소가 집합에 포함되어 있음을 의미합니다.
다음으로, and eax, 10000b 명령어를 사용하여 EAX 레지스터와 비트 마스크 10000b(이진수로, 이는 5번째 비트만 1인 수를 의미합니다)를 AND 연산합니다. AND 연산은 두 비트가 모두 1일 때만 1을 반환하므로, 이 명령어는 EAX 레지스터의 5번째 비트가 1인지(즉, 배열의 4번째 요소가 집합에 있는지) 확인합니다.
만약 5번째 비트가 1이라면, AND 연산의 결과는 0이 아니므로 Zero 플래그는 클리어됩니다. 이는 element[4]가 SetX의 멤버임을 나타냅니다. 그러나 5번째 비트가 0이라면, AND 연산의 결과는 0이 되어 Zero 플래그가 설정됩니다. 이는 element[4]가 SetX의 멤버가 아님을 나타냅니다.
따라서 이 코드는 배열의 특정 요소가 집합에 포함되어 있는지를 효과적으로 테스트할 수 있게 합니다. 이 방법은 고성능 애플리케이션에서 빠르게 대량의 데이터를 처리해야 할 때 유용하게 사용될 수 있습니다.
Set Complement
집합의 보수는 NOT 명령어를 사용하여 생성할 수 있으며, 이 명령어는 모든 비트를 반전시킵니다. 따라서 다음 명령어는 SetX의 보수를 EAX에 생성합니다.
mov eax, SetX
not eax ; complement of SetX
Set Intersection
AND 명령어는 두 집합의 교집합을 나타내는 비트 벡터를 생성합니다. 다음 코드는 SetX와 SetY의 교집합을 EAX에 생성하고 저장합니다.
mov eax, SetX
and eax, SetY
이 방식으로 SetX와 SetY의 교집합을 생성할 수 있습니다. 이렇게 집합 교집합을 생성하는 더 빠른 방법은 상상하기 어렵습니다. 단, 도메인이 더 크면 단일 레지스터에 저장할 수 있는 비트보다 더 많은 비트가 필요하므로, 모든 비트를 AND 연산하기 위해 루프를 사용해야 할 수도 있습니다.
Set Union
OR 명령어는 두 집합의 합집합을 나타내는 비트 맵을 생성합니다. 다음 코드는 SetX와 SetY의 합집합을 EAX에 생성합니다.
mov eax, SetX
or eax, SetY
이 방식으로 OR 명령어는 SetX와 SetY의 합집합을 생성합니다. 이것은 각각의 비트 위치에서 적어도 하나의 입력이 1일 경우, 결과가 1이 되도록 합니다. 이는 집합의 합집합에서와 같이 두 집합 중 어느 하나라도 해당 항목을 포함하고 있다면 결과 집합도 그 항목을 포함하게 됩니다.
이렇게 해서, 우리는 비트 맵을 사용하여 집합 연산을 효과적으로 수행할 수 있음을 볼 수 있습니다. 이는 간단한 이진 연산을 사용하여 빠르게 수행할 수 있으므로, 많은 양의 데이터에 대한 집합 연산을 처리해야 하는 상황에서 매우 유용합니다.
The XOR instruction performs a boolean exclusive-OR operation between each pair of matching bits in two operands and stores the result in the destination operand:
XOR destination, source
X | Y | X ⊕ Y | (X ⊕ Y) ⊕ Y |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 1 |
1 | 1 | 0 | 1 |
Flags
mov al, 10110101b ; 5 bits = odd parity
xor al, 0 ; Parity flag clear (odd)
mov al, 11001100b ; 4 bits = even parity
xor al, 0 ; Parity flag set (even)
16-Bit Parity
mov ax, 64C1h ; 0110 0100 1100 0001
xor ah, al ; Parity flag set (even)
XOR Instruction
'XOR destination, source' 라는 구문을 통해 XOR 명령어를 사용할 수 있습니다. 이 명령어는 두 피연산자의 일치하는 각 비트 쌍에 대해 XOR 연산을 수행하고 결과를 목적지 피연산자에 저장합니다.
XOR 명령어는 AND 및 OR 명령어와 동일한 피연산자 조합과 크기를 사용합니다. 즉, 두 피연산자는 동일한 크기를 가져야 합니다. 각각의 비트에 대해서, 두 비트가 같으면(모두 0 또는 모두 1) 결과는 0이고, 그렇지 않으면 결과는 1입니다.
비트를 0과 XOR 연산하면 비트 값이 그대로 유지되며, 비트를 1과 XOR 연산하면 비트가 토글(보수)됩니다. 즉, 1은 0으로, 0은 1로 바뀝니다.
XOR의 대칭성
XOR는 동일한 피연산자에 두 번 적용하면 원래의 값으로 돌아가는 특성이 있습니다. 즉, X XOR Y XOR Y는 X의 결과를 제공합니다. 이 "가역성" 속성은 XOR를 간단한 형태의 대칭 암호화에 이상적인 도구로 만듭니다.
Flags
XOR 명령어는 항상 Overflow와 Carry 플래그를 클리어합니다. XOR는 목적지 피연산자에 따라 Sign, Zero, Parity 플래그를 수정합니다.
Parity Flag 확인
Parity 확인은 숫자 내의 1 비트의 수를 세는 이진 숫자에서 수행됩니다. 결과 카운트가 짝수인 경우 데이터는 짝수 패리티를 가지며, 카운트가 홀수인 경우 데이터는 홀수 패리티를 가집니다. x86 프로세서에서는, 비트별 또는 산술 연산의 목적지 피연산자의 최하위 바이트가 짝수 패리티를 가질 때 Parity 플래그가 설정됩니다.
16-Bit Parity
16비트 정수의 패리티를 확인하는 것은 상위 바이트와 하위 바이트 사이에서 XOR 연산을 수행하는 것으로 가능합니다. 이 결합의 패리티는 전체 16비트 정수의 패리티와 동일하게 됩니다.
예를 들어, 다음과 같은 코드에서:
mov ax, 64C1h ; 0110 0100 1100 0001
xor ah, al ; Parity flag set (even)
먼저 mov ax, 64C1h라는 명령어로 ax 레지스터에 16비트 값인 64C1h (이진수로 0110 0100 1100 0001)를 저장합니다. ax 레지스터는 ah (상위 8비트)와 al (하위 8비트) 두 개의 8비트 레지스터로 구성되어 있습니다.
그런 다음 xor ah, al 명령어를 사용하여 ah와 al 레지스터의 값을 XOR 연산합니다. 이 때, 결과의 패리티가 짝수일 경우 패리티 플래그는 설정되고, 홀수일 경우에는 클리어됩니다.
이 경우, ah의 값 0110 0100와 al의 값 1100 0001를 XOR 연산하면 결과는 1010 0101이 되며, 이는 짝수 패리티를 가지므로 패리티 플래그는 설정됩니다.
이렇게 XOR 연산을 활용하면 효율적으로 정수의 패리티를 확인할 수 있습니다.
The NOT instruction toggles (inverts) all bits in an operand
The result is called the one’s complement
NOT reg
NOT mem
mov al,11110000b
not al ; AL = 00001111b
Flags
NOT reg
NOT mem
예를 들어, F0h의 1의 보수는 0Fh입니다.
mov al,11110000b
not al ; AL = 00001111b
이 경우, 'mov al,11110000b' 명령어를 통해 al 레지스터에 이진수 11110000b를 할당합니다. 이후 'not al' 명령어는 al 레지스터의 모든 비트를 반전시켜, al 레지스터에 00001111b를 저장합니다.
플래그: NOT 명령어는 어떠한 플래그도 영향을 주지 않습니다.
The TEST instruction performs an AND operation, but does not modify the destination operand
The TEST instruction permits the same operand combinations as the AND instruction
TEST is particularly valuable for finding out whether individual bits in an operand are set
Example: Testing Multiple Bits
test al, 00001001b; test bits 0 and 3
(The value 00001001 in this example is called a bit mask)
0 0 1 0 0 1 0 1 <- input value
0 0 0 0 1 0 0 1 <- test value
0 0 0 0 0 0 0 1 <- result: ZF = 0
0 0 1 0 0 1 0 0 <- input value
0 0 0 0 1 0 0 1 <- test value
0 0 0 0 0 0 0 0 <- result: ZF = 1
Flags
TEST 명령어는 AND 연산을 수행하지만, 목적 피연산자를 수정하지는 않습니다. TEST 명령어는 AND 명령어와 같은 피연산자 조합을 허용합니다. TEST는 피연산자의 개별 비트가 설정되어 있는지 확인하는 데 매우 유용합니다.
예시: 여러 비트 테스트
test al, 00001001b; test bits 0 and 3
(이 예제에서의 값 00001001을 비트 마스크라고 합니다.)
0 0 1 0 0 1 0 1 <- input value
0 0 0 0 1 0 0 1 <- test value
0 0 0 0 0 0 0 1 <- result: ZF = 0
0 0 1 0 0 1 0 0 <- input value
0 0 0 0 1 0 0 1 <- test value
0 0 0 0 0 0 0 0 <- result: ZF = 1
플래그: TEST 명령어는 AND 명령어와 동일한 방식으로 부호(Sign), 제로(Zero), 그리고 패리티(Parity) 플래그를 수정합니다.
플래그는 프로그램의 실행 상태를 나타내는 데 사용되는 특별한 레지스터의 비트입니다. 이들은 종종 연산 결과의 특성을 나타냅니다.
예를 들어, 'test al, 00001001b' 명령어는 AL 레지스터의 비트 0과 비트 3를 테스트합니다. 이 비트가 모두 클리어되면(즉, 값이 0이면) 제로 플래그는 설정되고, 그렇지 않으면 클리어됩니다.
테스트의 결과가 음수이면 부호 플래그가 설정되지만, 이 경우에는 AND 연산의 결과이므로 항상 0 또는 양수이므로 부호 플래그는 클리어됩니다.
마지막으로, 테스트 결과에서 낮은 바이트의 1 비트의 수가 짝수이면 패리티 플래그가 설정되고, 홀수이면 클리어됩니다. 이는 명령어 실행 후 패리티를 확인하는 데 유용할 수 있습니다.
The most common boolean expressions involve some type of comparison
if A > B ...
while X > 0 and X < 200 ...
if check_for_error( N ) = true
We use the CMP instruction to compare integers
CMP performs an implied subtraction of a source operand from a destination operand
CMP destination, source
Flags
Examples: how flags are affected by the CMP instruction
mov ax, 5
cmp ax, 10 ; ZF = 0 and CF = 1
mov ax,1000
mov cx,1000
cmp cx,ax ; ZF = 1 and CF = 0
mov si, 105
cmp si, 0 ; ZF = 0 and CF = 0
"CMP" 명령어는 "Compare"의 줄임말로, 두 피연산자를 비교하는 데 사용됩니다. 이 명령어는 일반적으로 if나 while과 같은 조건부 실행에 사용되는 불리언 표현식에서 활용됩니다. 예를 들어, 'A > B', 'X > 0 and X < 200'와 같은 표현식들이 있습니다.
CMP 명령어는 목적지 피연산자에서 출발지 피연산자를 빼는 것처럼 동작하지만 실제로는 두 피연산자를 수정하지 않습니다. AND 명령어와 마찬가지로 CMP 명령어도 같은 피연산자 조합을 사용합니다.
다음은 명령어의 구조입니다:
CMP destination, source
플래그에 대한 CMP 명령어의 영향은 다음과 같습니다:
다음은 CMP 명령어가 플래그에 어떤 영향을 미치는지에 대한 몇 가지 예입니다:
mov ax, 5
cmp ax, 10 ; ZF = 0 and CF = 1
mov ax,1000
mov cx,1000
cmp cx,ax ; ZF = 1 and CF = 0
mov si, 105
cmp si, 0 ; ZF = 0 and CF = 0
How can you easily set or clear the Zero, Sign, Carry, and Overflow flags?
There are several ways, some of which require modifying the destination operand
test al, 0 ; set Zero flag
and al, 0 ; set Zero flag
or al, 0 ; clear Zero flag
TEST does not modify the operand, whereas AND does
or al, 80h ; set Sign flag
and al, 7Fh ; clear Sign flag
stc ; set Carry flag
clc ; clear Carry flag
mov al, 7Fh ; AL = +127
inc al ; AL = 80h (-128), OF = 1
or eax, 0 ; clear Overflow flag
여기에서는 특정 CPU 플래그를 설정하거나 클리어하는 방법에 대해 설명하고 있습니다. 이 방법들 중 일부는 목적지 피연산자를 수정하는 것을 필요로 합니다.
test al, 0 ; set Zero flag
and al, 0 ; set Zero flag
or al, 0 ; clear Zero flag
or al, 80h ; set Sign flag
and al, 7Fh ; clear Sign flag
stc ; set Carry flag
clc ; clear Carry flag
mov al, 7Fh ; AL = +127
inc al ; AL = 80h (-128), OF = 1
or eax, 0 ; clear Overflow flag
이들 명령어는 개발자가 플래그를 통해 프로그램의 로직을 제어할 수 있게 해줍니다. 플래그의 상태에 따라 프로그램의 동작이 결정되기 때문에, 이들을 적절하게 설정하고 클리어하는 것이 중요합니다.
There are no explicit high-level logic structures in the x86 instruction set, but you can implement them using a combination of comparisons and jumps
Two steps:
Example 1
cmp eax, 0
jz L1 ; jump if ZF = 1
.
.
L1:
Example 2
and dl, 10110000b
jnz L2 ; jump if ZF = 0
.
.
L2:
조건부 점프는 높은 수준의 프로그래밍 언어에서 보통 볼 수 있는 if-then-else나 while 문과 같은 제어 구조를 구현하는 데 사용됩니다. 이러한 구조는 x86 명령어 세트에 명시적으로는 포함되어 있지 않지만, 비교 및 점프 조합을 사용하여 이들을 구현할 수 있습니다.
조건부 점프를 수행하는 데는 두 단계가 있습니다:
이를 통해 논리적인 조건을 사용하여 프로그램의 흐름을 제어할 수 있게 됩니다.
예시 1에서는 CMP 명령어를 사용하여 EAX와 0을 비교하고 있습니다. 이 비교의 결과에 따라 Zero 플래그가 설정됩니다. JZ (Jump if Zero) 명령어는 Zero 플래그가 설정된 경우(즉, EAX가 0인 경우) 레이블 L1로 점프하게 됩니다.
예시 2에서는 AND 명령어를 사용하여 DL 레지스터의 비트에 대한 AND 연산을 수행합니다. 이 연산의 결과에 따라 Zero 플래그가 설정됩니다. JNZ (Jump if Not Zero) 명령어는 Zero 플래그가 클리어된 경우(즉, AND 연산의 결과가 0이 아닌 경우) 레이블 L2로 점프하게 됩니다.
이러한 조건부 점프는 복잡한 로직을 구현하는 데 필요한 중요한 기능입니다.
A conditional jump instruction branches to a destination label when a status flag condition is true
The syntax:
Jcond destination
cond refers to a flag condition identifying the state of one or more flags
JC | Jump if carry (Carry flag set) |
JNC | Jump if not carry (Carry flag clear) |
JZ | Jump if zero (Zero flag set) |
JNZ | Jump if not zero (Zero flag clear) |
CPU status flags are most commonly set by arithmetic, comparison, and boolean instructions
Conditional jump instructions evaluate the flag states, using them to determine whether or not jumps should be taken
Using the CMP Instruction
cmp eax, 5
je L1 ; jump if equal
mov ax, 5
cmp ax, 6
jl L1 ; jump if less
mov ax, 5
cmp ax, 4
jg L1 ; jump if greater
조건부 점프 명령어는 CPU 상태 플래그의 상태에 따라 프로그램 실행의 흐름을 제어합니다. 만약 조건이 참이면 명령어는 목적지 레이블로 분기하며, 그렇지 않으면 바로 다음 명령어가 실행됩니다.
Jcond 명령어의 구문은 다음과 같습니다: Jcond destination
여기서 "cond"는 하나 이상의 플래그의 상태를 식별하는 플래그 조건을 참조합니다. 예를 들어 JC는 Carry 플래그가 설정된 경우 점프하고, JNC는 Carry 플래그가 클리어된 경우 점프합니다. JZ와 JNZ는 각각 Zero 플래그가 설정되거나 클리어된 경우에 점프합니다.
이러한 CPU 상태 플래그는 대부분 산술, 비교, 논리 명령어에 의해 설정됩니다. 조건부 점프 명령어는 이 플래그 상태를 평가하여 점프를 실행할지 여부를 결정합니다.
CMP 명령어를 사용하는 예제들을 살펴봅시다:
이런 식으로 조건부 점프 명령어를 사용하면 복잡한 제어 흐름을 구현할 수 있습니다.
Mnemonic | Description | Flags/Registers |
---|---|---|
JZ | Jump if zero | ZF = 1 |
JNZ | Jump if not zero | ZF = 0 |
JC | Jump if carry | CF = 1 |
JNC | Jump if not carry | CF = 0 |
JO | Jump if overflow | OF = 1 |
JNO | Jump if not overflow | OF = 0 |
JS | Jump if signed | SF = 1 |
JNS | Jump if not signed | SF = 0 |
JP | Jump if parity(even) | PF = 1 |
JNP | Junp if not parity(odd) | PF = 0 |
조건부 점프 명령어는 부호가 있는 정수와 부호가 없는 정수를 비교하고, 개별 CPU 플래그의 값에 따라 동작을 수행할 수 있습니다. 이들 조건부 점프 명령어는 다음과 같이 네 가지 그룹으로 나눌 수 있습니다:
이 중 특정 플래그 값에 기반한 점프를 표로 정리해보면 다음과 같습니다:
이렇게 조건부 점프 명령어는 CPU의 플래그 상태에 따라 프로그램의 실행 흐름을 제어하는 데 사용됩니다. 이를 통해 복잡한 제어 구조를 구현할 수 있습니다.
Mnemonic | Description |
---|---|
JE | Jump if equal (leftOp = rightOp) |
JNE | Jump if not equal (leftOp ≠ rightOp) |
JCXZ | Jump if CX = 0 |
JECXZ | Jump if ECX = 0 |
JRCXZ | Jump if RCX = 0 (64-bit mode) |
등식 비교에 사용되는 조건부 점프 명령어는 다음과 같습니다:
일부 경우에서는 두 피연산자를 비교하고, 다른 경우에서는 (E)CX 값에 따라 점프가 발생합니다. 여기서 사용되는 leftOp와 rightOp는 CMP 명령어에서 왼쪽(대상) 피연산자와 오른쪽(원본) 피연산자를 가리킵니다: CMP leftOp, rightOp. 피연산자 이름은 대수학에서 관계 연산자의 피연산자 순서를 반영합니다. 예를 들어, X < Y 표현식에서 X는 leftOp, Y는 rightOp로 불립니다.
JE 명령어는 JZ와 동일하며, JNE는 JNZ와 동일합니다. 두 피연산자를 비교하려는 의도인지, 특정 상태 플래그를 검사하려는 의도인지를 가장 잘 나타내는 기호(JE 또는 JZ)를 선택하는 것이 가장 좋습니다. 이들 명령어를 사용하면 피연산자 간의 동등성이나 레지스터 (E)CX의 값에 따라 프로그램의 실행 흐름을 제어할 수 있습니다.
Example 1
mov edx, 0A523h
cmp edx, 0A523h
jne L5 ; jump not taken
je L1 ; jump is taken
Example 2
mov bx, 1234h
sub bx, 1234h
jne L5 ; jump not taken
je L1 ; jump is taken
Example 3
mov cx, 0FFFFh
inc cx
jcxz L2 ; jump is taken
Example 4
xor ecx, ecx
jecxz L2 ; jump is taken
여기에는 여러 가지 예제가 있습니다. 모든 예제에서는 cmp 명령어가 두 피연산자를 비교하고, 이후에 나오는 조건부 점프 명령어가 그 비교의 결과에 따라 프로그램의 실행 흐름을 제어합니다.
예제1:
이 예제에서, EDX 레지스터에는 -1이 저장되고, 이 값은 0과 비교됩니다. -1 >= 0과 -1 > 0이 거짓이므로 jnl과 jnle 명령어에 의해 점프가 발생하지 않습니다. 반면, -1 < 0은 참이므로 jl 명령어에 의해 L1로 점프가 발생합니다.
예제 2:
BX 레지스터에는 +32가 저장되고, 이 값은 -35와 비교됩니다. 그러나 여기에는 문제가 있는데, jng와 jnge에 해당하는 주석이 잘못되었습니다. +32 >= -35와 +32 > -35 모두 참이므로 점프가 이루어져야 합니다. +32 < -35는 거짓이므로 jge 명령어로 인한 점프는 이루어지지 않아야 합니다.
예제 3:
ECX 레지스터에는 0이 저장되고, 이 값은 0과 비교됩니다. 0 > 0은 거짓이므로 jg 명령어에 의해 점프가 발생하지 않습니다. 반면, 0 >= 0은 참이므로 jnl 명령어에 의해 L1로 점프가 발생합니다.
예제 4:
마지막 예제에서, 0 < 0은 거짓이므로 jl 명령어에 의해 점프가 발생하지 않습니다. 반면, 0 <= 0은 참이므로 jng 명령어에 의해 L1로 점프가 발생합니다.
각 예제에서, 특정 비교가 참이면 특정 레이블로 점프하는 조건부 점프 명령어를 볼 수 있습니다. 이것은 x86 어셈블리에서 프로그램의 실행 흐름을 제어하는 주요 방법입니다.
Mnemonic | Description |
---|---|
JA | Jump if above(if leftOp > rightOp) |
JNBE | Jump if not below or equal(same as JA) |
JAE | Jump if above or equal(if leftOp ≥ rightOp) |
JNB | Jump if not below(same as JAE) |
JB | Jump if below (if leftOp < rightOp) |
JNAE | Jump if not above or equal (same as JB) |
JBE | Jump if below or equal (if leftOp ≤ rightOp) |
JNA | Jump if not above(same as JBE) |
먼저, "unsigned"는 부호가 없다는 뜻으로, 음수나 양수를 가질 수 없는 정수를 가리킵니다. 따라서, 'unsigned comparisons'은 부호가 없는 정수 값을 비교하는 것을 말합니다.
다음은 각 mnemonic에 대한 자세한 설명입니다:
이런 방식으로, 이러한 명령어들은 조건부 점프를 수행하면서 프로그램의 실행 흐름을 제어합니다.
Mnemonic | Description |
---|---|
JG | Jump if greater(if leftOp > rightOp) |
JNLE | Jump if less than or equal(same as JG) |
JGE | Jump if greater than or equal(if leftOp ≥ rightOp) |
JNL | Jump if not less(same as JGE) |
JL | Jump if less(if leftOp < rightOp) |
JNGE | Jump if not greater than or eqaul(same as JL) |
JLE | Jump if less than or equal(if leftOp ≤ rightOp) |
JNG | Jump if not greater(same as JLE) |
mov al, + 127 ; hexadecimal value is 7Fh
cmp al, -128 ; hexadecimal value is 80h
ja IsAbove ; jump not taken, because 7Fh < 80h
jg IsGreater ; jump taken, because +127 > -128
"Signed comparisons"는 부호 있는 정수를 비교하는 조건부 점프입니다. 즉, 양수와 음수 값을 비교합니다.
각 mnemonic에 대한 자세한 설명은 다음과 같습니다:
예시에서 보시면, al 레지스터에 +127(16진수로는 7Fh)를 할당하고, 이를 -128(16진수로는 80h)과 비교합니다. 그 다음에는 'JA'와 'JG' 명령어를 사용하여 두 가지 다른 결과를 얻습니다:
이런 방식으로, 이러한 명령어들은 조건부 점프를 수행하면서 프로그램의 실행 흐름을 제어합니다.
Example 1
mov edx, -1
cmp edx, 0
jnl L5 ; jump not taken (-1 >= 0 is false )
jnle L5 ; jump not taken ( -1 > 0 is false )
jl L1 ; jump is taken ( -1 < 0 is true )
Example 2
mov bx, +32
cmp bx, -35
jng L5 ; jump not taken (+32 >= -35 is false )
jnge L5 ; jump not taken ( +32 > -35 is false )
jge L1 ; jump is taken ( +32 < -35 is true )
Example 3
mov ecx, 0
cmp ecx, 0
jg L5 ; jump not taken (0 > 0 is false )
jnl L1 ; jump is taken ( 0 >= 0 is true )
Example 4
mov ecx, 0
cmp ecx, 0
jl L5 ; jump not taken (0 < 0 is false )
jng L1 ; jump is taken ( 0 <= 0 is false )
주어진 예제들은 조건부 점프 명령어가 어떻게 사용되는지 보여줍니다.
Example 1:
이 예제에서는 EDX 레지스터에 -1을 할당하고, 이를 0과 비교합니다.
Example 2:
이 예제에서는 BX 레지스터에 +32를 할당하고, 이를 -35와 비교합니다.
Example 3:
이 예제에서는 ECX 레지스터에 0을 할당하고, 이를 0과 비교합니다.
Example 4:
mov al, status
test al, 00100000b ; test bit 5
jnz DeviceOffline
mov al,status
test al, 00010011b ; test bit 0, 1, 4
jnz InputDataByte
mov al,status
and al,10001100b ; mask bits 2, 3, 7
cmp al,10001100b ; all bits set?
je ResetMachine ; yes: jump to label
위에서 제공된 내용은 조건부 점프 명령어가 상태 비트를 테스트하는 데 어떻게 사용되는지를 보여줍니다. CPU 상태 플래그는 종종 조건부 점프 명령어가 코드 레이블로 제어를 전송할지 여부를 결정하는 데 사용됩니다.
Testing Status Bits
1.상태 정보가 포함된 8비트 메모리 피연산자 :
여기서는 8비트 메모리 피연산자인 'status'가 외부 디바이스의 상태 정보를 포함하고 있다고 가정합니다. test 명령어는 AL 레지스터에 있는 비트 5(2진수로 00100000)를 테스트합니다. 비트 5가 설정되어 있다면(즉, 1이라면), 디바이스가 오프라인 상태라는 것을 나타내고, jnz(Jump if Not Zero) 명령어를 통해 'DeviceOffline' 라벨로 점프하게 됩니다.
2.특정 비트가 설정되어 있는지 확인 :
위의 예시에서는 test 명령어가 비트 0, 1, 4를 테스트합니다. 만약 이 비트 중 하나라도 설정되어 있다면(즉, 1이라면), 'InputDataByte' 라벨로 점프하게 됩니다.
3.모든 비트가 설정되어 있는지 확인 :
이 경우, 'and' 명령어를 통해 비트 2, 3, 7을 마스킹하고, 'cmp' 명령어를 통해 모든 비트가 설정되어 있는지 확인합니다. 모든 비트가 설정되어 있다면(즉, 모두 1이라면), 'je'(Jump if Equal) 명령어를 통해 'ResetMachine' 라벨로 점프하게 됩니다.
이러한 방법으로, 조건부 점프 명령어는 상태 플래그를 테스트하고, 해당 결과에 따라 특정 코드 블록으로 제어를 전송하는 데 사용됩니다.
mov edx, eax ; assume EAX is larger
cmp eax, ebx ; if EAX is >= EBX
jae L1 ; jump to L1
mov edx, ebx ; else move EBX to EDX
L1: ; EDX contains the larger integer
두 정수 중 큰 값 찾기
아래의 코드는 EAX와 EBX에 있는 부호 없는 정수를 비교하고, 둘 중 더 큰 값을 EDX로 옮깁니다.
이 코드는 처음에 edx 레지스터에 eax의 값을 저장하여 eax가 더 큰 값을 가지고 있다고 가정합니다. 그 다음, cmp 명령어로 eax와 ebx를 비교합니다. 만약 eax가 ebx보다 크거나 같다면, jae (Jump if Above or Equal) 명령어로 L1 레이블로 점프합니다. 그렇지 않다면, ebx의 값을 edx로 이동합니다. 따라서 edx는 두 정수 중 더 큰 값을 가지게 됩니다.
.data
char BYTE ?
.code
L1: mov eax,10 ; create 10 ms delay
call Delay
call ReadKey ; check for key
jz L1 ; repeat if no key
mov char, AL ; save the character
키 입력까지 반복
다음 32비트 코드에서는 사용자가 표준 알파벳이나 숫자 키를 누를 때까지 반복적으로 루프를 실행합니다.
이 코드는 Irvine32 라이브러리의 ReadKey 메서드를 사용합니다. 이 메서드는 입력 버퍼에 키가 없을 경우 Zero 플래그를 설정합니다. 코드는 MS-Windows가 이벤트 메시지를 처리할 시간을 주기 위해 루프에 10밀리초의 딜레이를 삽입합니다. 이 딜레이를 생략하면 키 입력이 무시될 수 있습니다. jz (Jump if Zero) 명령어는 키가 없을 경우 L1 레이블로 점프하여 루프를 반복합니다. 키가 눌리면 해당 문자를 'char' 변수에 저장합니다.
; Scanning an Array (ArrayScan.asm)
; Scan an array for the first nonzero value.
INCLUDE Irvine32.inc
.data
int Array SWORD 0,0,0,0,1,20,35,-12,66,4,0
;int Array SWORD 1,0,0,0 ; alternate test data
;int Array SWORD 0,0,0,0 ; alternate test data
;int Array SWORD 0,0,0,1 ; alternate test data
noneMsg BYTE "A non-zero value was not found",0
.code
main PROC
mov ebx,OFFSET intArray ; point to the array
mov ecx,LENGTHOF intArray ; loop center
L1: cmp WORD PTR [ebx], 0 ; compare value to zero
jnz found ; found a value
add ebx, 2 ; point to next
loop L1 ; continue the loop
jmp notFound ; none found
found: ; display the value
movsx eax, WORD PTR[ebx] ; sign-extend into EAX
call WriteInt
jmp quit
notFound: ; display "not found" message
mov edx, OFFSET noneMsg
call WriteString
quit:
call Crlf
exit
main ENDP
END main
이 프로그램은 16비트 정수의 배열에서 첫 번째 0이 아닌 값을 찾습니다. 만약 찾게 된다면 그 값을 출력하고, 그렇지 않다면 0이 아닌 값이 발견되지 않았다는 메시지를 출력합니다.
INCLUDE Irvine32.inc
.data
intArray SWORD 0,0,0,0,1,20,35,-12,66,4,0 ; 검색할 배열 정의
noneMsg BYTE "A non-zero value was not found",0 ; 찾지 못했을 때 출력할 메시지
.code
main PROC
mov ebx,OFFSET intArray ; EBX 레지스터에 배열의 시작 주소를 저장
mov ecx,LENGTHOF intArray ; ECX 레지스터에 배열의 길이를 저장 (루프의 반복 횟수로 사용)
L1: cmp WORD PTR [ebx], 0 ; 현재 원소를 0과 비교
jnz found ; 원소가 0이 아니면 found로 점프
add ebx, 2 ; 다음 원소로 이동 (2바이트 증가)
loop L1 ; 루프 반복
jmp notFound ; 루프가 끝난 후 0이 아닌 값이 없으면 notFound로 점프
found: ; 0이 아닌 값을 찾았을 때 수행
movsx eax, WORD PTR[ebx] ; 원소 값을 EAX 레지스터로 옮김 (부호 확장)
call WriteInt ; EAX에 있는 값을 출력
jmp quit ; 프로그램 종료 부분으로 점프
notFound: ; 0이 아닌 값을 찾지 못했을 때 수행
mov edx, OFFSET noneMsg ; noneMsg의 주소를 EDX 레지스터로 옮김
call WriteString ; noneMsg 문자열 출력
quit:
call Crlf ; 새로운 라인 출력
exit ; 프로그램 종료
main ENDP
END main
이 프로그램은 Assembly에서 배열을 스캔하고 조건에 따라 특정 작업을 수행하는 방법을 잘 보여줍니다. 배열의 각 원소를 순차적으로 검사하고, 검사한 원소가 0이 아닌지 확인합니다. 0이 아닌 원소를 찾는 즉시, 그 값을 출력하고 프로그램을 종료합니다. 배열의 모든 원소를 검사한 후에도 0이 아닌 원소를 찾지 못하면, "A non-zero value was not found"라는 메시지를 출력합니다.
(( X ⊗ Y ) ⊗ Y ) = X
INCLUDE Irvine32.inc
KEY = 239 ; any value between 1~255
BUFMAX = 128 ; maximum buffer size
.data
sPrompt BYTE "Enter the plain text:",0
sEncrypt BYTE "Cipher text: ", 0
sDescrpt BYTE "Decrypted : ", 0
buffer BYTE BUFMAX+1 DUP (0)
bufSize DWORD ?
.code
main PROC
call InputTheString ; input the plain text
call TranslateBuffer ; encrypt the buffer
mov edx, OFFSET sEncrypt ; display encrypted message
call DisplayMessage
call TranslateBuffer ; decrypt the buffer
mov edx,OFFSET sDecrypt ; display decrypted message
call DisplayMessage
exit
main ENDP
;--------------------------------------------------------
InputTheString PROC
;
; Prompts user for a plaintext string. Saves the string
; and its length.
; Receives: nothing
; Returns: nothing
;--------------------------------------------------------
pushed
mov edx, OFFSET sPrompt ; save 32-bit registers
call WriteString
mov ecx,BUFMAX ; maximum character count
call Crlf
popad
ret
InputTheString ENDP
;--------------------------------------------------------
DisplayMessage PROC
; Displays the encrypted or decrypted message.
; Receives: EDX points to the message
; Returns: nothing
;--------------------------------------------------------
pushed
call WriteString
mov edx, OFFSET buffer ; display the buffer
call WriteString
call Crlf
call Crlf
popad
ret
DisplayMessage ENDP
;--------------------------------------------------------
TranslateBufer PROC
; Translates the string by exclusive-ORing each
; byte with the encryption key byte
; Receives: nothing
; Returns: nothing
;--------------------------------------------------------
pushad
mov ecx, bufSize ; loop counter
mov esi, 0 ; index 0 in buffer
L1:
xor buffer[esi], KEY ; translate a byte
inc esi ; point to next byte
loop L1
popad
ret
TranslateBuffer ENDP
END main
이 프로그램은 XOR 연산을 사용하여 텍스트를 단순하게 암호화하고 복호화하는 과정을 보여줍니다. XOR 연산은 같은 값을 두 번 XOR하면 원래의 값이 나오는 특성을 가지고 있습니다. 즉, ((X XOR Y) XOR Y) = X가 됩니다. 이 특성을 이용하여 원본 데이터를 암호화하고 복호화하는 작업을 수행할 수 있습니다.
이 프로그램의 주요 부분을 살펴보면 다음과 같습니다:\
즉, 이 프로그램은 입력받은 원본 텍스트를 KEY와 XOR 연산하여 암호화하고, 암호화된 텍스트를 다시 KEY와 XOR 연산하여 원본 텍스트를 복원하는 과정을 보여줍니다. 이렇게 XOR 연산을 통해 데이터를 암호화하고 복호화하는 방법을 "대칭키 암호화"라고 합니다. 대칭키 암호화는 암호화와 복호화에 동일한 키를 사용하는 방식입니다.
The LOOPZ (loop if zero) instruction
The LOOPE (loop if equal) instruction
They perform the following tasks:
LOOPZ and LOOPE do not affect any of the status flags
LOOPNZ destination
ECX = ECX - 1
if ECX > 0 and ZF = 0, jump to destination
.data
array SWORD -3, -6, -1, -10, 10, 30, 40, 4
sentinel SWORD 0
.code
mov esi,OFFSET array
mov ecx,LENGTHOF array
L1: test WORD PTR [esi],8000h ; test sign bit
pushfd ; push flags on stack
add esi, TYPE array ; move to next position
popfd ; pop flags from stack
loopnz L1 ; continue loop
jnz quit ; none found
sub esi, TYPE array ; ESI points to value
quit:
if( boolean-expression )
statement-list-1
else
statement-list-2
if ( op1 == op2 )
{
X = 1;
Y = 2;
}
mov eax, op1
cmp eax, op2 ; op1 == op2?
jne L1 ; no: skip next
mov X, 1 ; yes: assign X and Y
mov Y, 2
L1:
mov eax, op1
cmp eax, op2 ; op == op2?
je L1 ; yes: jump to L1
jmp L2 ; no: skip assignments
L1: mov X, 1 ; assign X and Y
mov Y, 2
L2:
clusterSize = 8192;
if terrabytes < 16
clusterSize = 4096;
mov clusterSize, 8192 ; assume larger cluster
cmp terrabytes, 16 ; smaller than 16 TB?
jae next
mov clusterSize, 4096 ; switch to smaller cluster
next:
if op1 > op2
call Routine1
else
call Routine2
end if
mov eax,op2 ; move op1 to a register
cmp eax,op2 ; op1 > op2?
jg A1 ; yes: call Routine1
jmp A2 ; no: call Routine2
A1: call Routine1 ; exit the IF statement
A2:
if op1 == op2
if X > Y
call Routine1
else
call Routine2
end if
else
call Routine3
end if
1: mov eax, op1
2: cmp eax, op2 ; op1 == op2?
3: jne L2 ; no: call Routine3
;processing the inner IF-ELSE statement.
4: mov eax, X
5: cmp eax, Y ; X > Y?
6: jg L1 ; yes: call Routine1
7: call Routine2 ; no: call Routine2
8: jmp L3 ; and exit
9: L1: call Routine1 ; call Routine1
10: jmp L3 ; and exit
11: L2: call Routine3
12: L3:
op1 | op2 | X | Y | Line Execution Sequence | Calls |
---|---|---|---|---|---|
10 | 20 | 30 | 40 | 1, 2, 3, 11, 12 | Routine3 |
10 | 20 | 40 | 30 | 1, 2, 3, 11, 12 | Routine3 |
10 | 10 | 30 | 40 | 1, 2, 3, 4, 5, 6, 7, 8, 12 | Routine2 |
10 | 10 | 40 | 30 | 1, 2, 3, 4, 5, 6, 9, 10, 12 | Routine1 |
if (al > bl) AND (bl > cl)
X = 1
end if
cmp al,bl ; fist expression...
ja L1
jmp next
L1: cmp bl,cl ; second expression...
ja L2
jmp next
L2: mov X,1 ; both true: set X to 1
next:
cmp al,bl ; first expression
jbe next ; quit if false
cmp bl,cl ; second expression
jbe next ; quit if false
mov X,1 ; both are true
next:
if (al > bl) OR (bl > cl)
X = 1
cmp al, bl ; 1: compare AL to BL
ja L1 ; if true, skip second expression
cmp bl, cl ; 2: compare BL to CL
jbe next ; false: skip next statement
L1: mov X,1 ; true: set X = 1
next:
mov eax, val1 ; copy variable to EAX
beginWhile:
cmp eax, val2 ; if not (val1 < val2)
jnl endWhile ; exit the loop
inc eax ; val1++;
dec val2 ; val2--;
jmp beginWhile ; repeat the loop
endWhile:
mov val1,eax ; save new value for val1
int array[] = {10, 60, 20, 33, 72, 89, 45, 65, 72, 18};
int sample = 50;
int ArraySize = sizeof array / sizeof sample;
int index = 0;
int sum = 0;
while( index < ArraySize )
{
if( array[index] > sampe )
{
sum += array[index];
}
index++;
}
To simplify the translation and speed up execution by reducing the number of memory accesses, registers have been substituted for variables
Assembly Code
.data
sum DWORD 0
sample DWORD 50
array DWORD 10, 60, 20, 33, 72, 89, 45, 65, 72, 18
ArraySize = ($ - Array) / TYPE array
.code
main PROC
mov eax, 0 ; sum
mov edx, sample
mov esi, 0
mov ecx, ArraySize
L1: cmp esi, ecx ; if esi < ecx
jl L2
jmp L5
L2: cmp array[esi*4], edx ; if array[esi] > edx
jg L3
jmp L4
L3: add eax,array[esi*4]
L4: inc esi
jmp L1
L5: mov sum,eax
.data
CaseTable BYTE 'A' ; lookup value
DWORD Process_A ; address of procedure
BYTE 'B'
DWORD Process_B
(etc.)
INCLUDE Irvine32.inc
.data
CaseTable BYTE 'A' ; lookup value
DWORD Process_A ; address of procedure
EntrySize = ($ - CaseTable)
BYTE 'B'
DWORD Process_B
BYTE 'C'
DWORD Process_C
BYTE 'D'
DWORD Process_D
NumberOfEntries = ($ - CaseTable) / EntrySize
prompt BYTE "Press capital A, B, C or D: ",0
msgA BYTE "Process_A", 0
msgB BYTE "Process_B", 0
msgC BYTE "Process_C", 0
msgD BYTE "Process_D", 0
.code
main PROC
mov edx, OFFSET prompt ; ask user for input
call WriteString
call ReadChar ; read character into AL
mov ebx, OFFSET CaseTable ; point EBX to the table
mov ecx, NumberOfEntries ; loop counter
L1:
cmp al, [ebx] ; match found?
jne L2 ; no: continue
call NEAR PTR [ebx + 1] ; yes: call the procedure
call WriteString ; display message
call Crlf
jmp L3 ; exit the search
L2:
add ebx, EntrySize ; point to the next entry
loop L1
L3:
exit
main ENDP
Process_A PROC
mov edx,OFFSET msgA
ret
Process_A ENDP
Process_B PROC
mov edx, OFFSET msgB
ret
process_B ENDP
Process_C PROC
mov edx,OFFSET msgC
ret
process_C ENDP
Process_D PROC
mov edx,OFFSET msgD
ret
process_D ENDP
END main
xaabcdefgz
xz
xyyqqrrstuvz
Input consists of an optional leading sign followed by a sequence of digits
There is no maximum number of digits implied by the diagram
StateA:
call Getnext ; read next char into AL
cmp al, '+' ; leading + sign?
je StateB ; go to State B
cmp al, '-' ; leading - sign?
je StateB ; go to State B
call IsDigit ; ZF = 1 if AL contains a digit
jz StateC ; go to State C
call DisplayErrorMsg ; invalid input found
jmp Quit
INCLUDE Irvine32.inc
ENTER_KEY
.data
InvalidInputMsg BYTE "Invalid input", 13, 10, 0
.code
main PROC
call Clrscr
StateA:
call Getnext ; read next char into AL
cmp al, '+' ; leading + sign?
je StateB ; go to State B
cmp al, '-' ; leading - sign?
je StateB ; go to State B
call IsDigit ; ZF = 1 if AL contains a digit
jz StateC ; go to State C
call DisplayErrorMsg ; invalid input found
jmp Quitl,'+'
StateB:
call Getnext ; read next char into AL
call IsDigit ; ZF = 1 if AL contains a digit
jz StateC
call DisplayErrorMsg ; invalid input found
jmp Quit
StateC:
call Getnext ; read next char into AL
call IsDigit ; ZF = 1 if AL contains a digit
jz StateC
cmp al, ENTER_KEY ; Enter key pressed?
je Quit ; yes: quit
call DisplayErrorMsg ; no: invalid input found
jmp Quit
Quit:
call Crlf
exit
main ENDP
;----------------------------------------------------------
Getnext PROC
; Reads a character from standard input.
; Receives: nothing
; Returns: AL contains the character
;----------------------------------------------------------
call ReadChar ; input from keyboard
call WriteChar ; echo on screen
ret
Getnext ENDP
;----------------------------------------------------------
DisplayError Msg PROC
;
; Displays an error message indicating that
; the input stream contains illegal input.
; Receives: nothing
; Returns: nothing
;----------------------------------------------------------
push edx
mov edx,OFFSET InvalidInputMsg
call WriteString
pop edx
ret
DisplayErrorMsg ENDP
END main
;----------------------------------------------------------
IsDigit PROC
;
; Determines whether the character in AL is a valid decimal digit
; Receives: AL = character
; Returns: ZF = 1 if AL contains a valid decimal digit; otherwise, ZF = 9
;----------------------------------------------------------
cmp al, '0'
jb ID1 ; ZF = 0 when jump taken
cmp al,'9'
ja ID1 ; ZF = 0 when jump taken
test ax,0 ; set ZF = 1
ID1: ret
IsDigit: ENDP
Directive | Description |
---|---|
.BREAK | Generates code to terminate a .WHILE or .REPEAT block |
.CONTINUE | Generates code to jump to the top of a .WHILE of .REPEAT block |
.ELSE | Begins block of statements to execute when the .IF condition is false |
.ELSEIF condition | Generates code that tests condition and executes statements that follow, untill an .ENDIF directive or another .ELSEIF directive is found |
.ENDIF | Terminates a block of statements following an .IF, .ELSE, or .ELSEIF directive |
.ENDW | Terminates a block of statements following a .WHILE directive |
.IF condition | Generates code that executes the block of statements if condition is true |
.REPEAT | Generates code that repeats exrcution of the block of statements untill condition becomes true |
.UNTIL condition | Generates code that repeats the block of statement between .REPEAT and .UNTIL until condition becomes true |
.UNTILCXZ | Generate code that repeats the block of statement between .REPEAT and . UNTILCXZ untile CX equals zero |
.WHILE condition | Generates code that executes the block of statements between .WHILE and .ENDW as long as condition is true |
.IF condition1
statements
[.ELSEIF condition2
statements ]
[.ELSE
statements ]
.ENDIF
(eax > 0) && (eax > 10000h)
(val1 <= 100) || (val2 <= 100)
(val2 != ebx) && !CARRY?
;--------------------------
; Before changing
;--------------------------
mov eax, 6
.IF eax > val1
mov result,1
.ENDIF
;--------------------------
; After changing
;--------------------------
mov eax, 6
cmp eax,val1
jbe @C0001
mov result,1
@C0001:
.data
val1 DWORD 5
result DWORD ?
.code
mov eax, 6
.IF eax > val1
mov result,1
.ENDIF
↓
mov eax, 6
cmp eax, val1
jbe @C0001
mov result, 1
@C0001:
.data
val2 SDWORD 5
result DWORD ?
.code
mov eax, 6
.IF eax > val2
mov result,1
.ENDIF
↓
mov eax, 6
cmp eax, val2
jle @C0001
mov result, 1
@C0001:
mov eax, 6
mov evx,val2
.IF eax > ebx
mov result,1
.ENDIF
↓
mov eax, 6
mov ebx, val2
cmp eax, ebx
jbe @C0001
mov result, 1
@C0001:
.IF expression1 || expression2
statements
.ENDP
↓
.IF expression1 && expression2
statements
.ENDIF
SetCursorPosition PROC
.data
BadXCoordMSG BYTE "X-Coordinate out of range!", 0Dh, 0Ah, 0
BadYCoordMSG BYTE "Y-Coordinate out of range!", 0Dh, 0Ah, 0
.code
.IF (dl > 0) || (dl > 79)
mov edx, OFFSET BadXCoordMsg
call WriteString
jmp quit
.ENDIF
.IF (dh < 0) || (dh > 24)
mov edx, OFFSET BadYCoordMsg
call WriteString
jmp quir
.ENDIF
call Gotoxy
quit:
ret
SetCursorPosition ENDP
↓
.code
; .IF (dl > 0) || (dl > 79)
cmp dl, 00h
jb @C0002
cmp dl, 04Fh
jbe @C0001
@C0002:
mov edx, OFFSET BadXCoordMsg
call WriteString
jmp quit
; .ENDIF
@C0001:
; .IF (dh < 0) || (dh > 24)
cmp dh, 000h
jb @C0005
cmp dh, 018h
jbe @C0004
@C0005
mov edx, OFFSET BadYCoordMsg
call WriteString
jmp quir
l .ENDIF
@C0004
call Gotoxy
quit:
ret
.data
TRUE = 1
FALSE = 0
gradeAverage WORD 275 ; test value
credits WORD 12 ; test value
OkToRegister BYTE ?
.code
mov OkToRegister,FALSE
.IF gradeAverage > 350
mov OkToRegister,TRUE
.ELSEIF (gradeAverage > 250) && (credits <= 16)
mov OkToRegister,TRUE
.ELSEIF (credits <= 12)
mov OkToRegister,TRUE
.ENDIF
↓
mov byte ptr OkToRegister,FALSE
cmp word ptr gradeAverage, 350
jbe @C0006
mov byte ptr OkToRegister, True
jmp @C0008
@C0006:
cmo word ptr gradeAverage,250
jbe @C0009
cmp word ptr credits,16
ja @C0009
mov byte ptrOkToRegister,TRUE
jmp @C0008
@C0009:
cmp word ptr credits,12
ja @C0008
mov byte ptr OkToRegister,TRUE
@C0008:
while( op1 < op2 )
{
op1++;
if( op1 == op3 )
X = 2;
else
X = 3;
}
.data
X DWORD 0
op1 DWORD 2
op2 DWORD 4
op3 DWORD 5
.code
mov eax, op1
mov ebx, op2
mov ecx, op3
.WHILE eax < ebx
inc eax
.IF eax == ecx
mov X,2
.ELSE
mov X,3
.ENDIF
.ENDW