System Progaramming -6- Conditional Processing

Shy·2023년 5월 31일
0

시스템프로그래밍

목록 보기
4/5

Boolean and Comparison Instructions

  • The Intel instruction set contains the AND, OR, XOR, and NOT instructions, which directly implement boolean operations on binary bits
OperationDescription
ANDBoolean AND operation between a source oprand and a destination operand
ORBoolean OR operation between a source oprand and a destination operand
XORBoolean exclusive-OR operation between a source operand and destination operand
NOTBoolean NOT operation on a destination operand
TESTImplied 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 상태 플래그만 변경됩니다.

1. The CPU Status Flags

Boolean instructions affect the Zero, Carry, Sign, Overflow, and Parity flags

  • The Zero flag is set when the result of an operation equals zero
  • The Carry flag is set when an operation generates a carry out of the highest bit of the destination operand
  • The Sign flag is a copy of the high bit of the destination operand
  • The Overflow flag is set when an instruction generates a result that is outside the signed range of the destination operand
  • The Parity flag is set when an instruction generates an even number of 1 bits in the low byte of the destination operand

Boolean 명령어는 Zero, Carry, Sign, Overflow, Parity 플래그에 영향을 미칩니다.

  1. Zero flag: 연산의 결과가 0일 때 Zero 플래그가 설정됩니다. 즉, 연산 결과가 없다는 것을 나타냅니다.
  2. Carry flag: 연산이 목적지 피연산자의 가장 높은 비트에서 carry를 생성하면 Carry 플래그가 설정됩니다. 이는 보통 정수 연산에서 오버플로우를 나타내는 데 사용됩니다.
  3. Sign flag: Sign 플래그는 목적지 피연산자의 높은 비트의 복사본입니다. 이는 보통 결과가 양수인지 음수인지를 나타내는 데 사용됩니다. 만약 최상위 비트가 1이면, Sign 플래그는 음수를 나타냅니다. 반면에, 최상위 비트가 0이면, Sign 플래그는 양수를 나타냅니다.
  4. Overflow flag: Overflow 플래그는 명령어가 목적지 피연산자의 signed 범위 밖에 결과를 생성할 때 설정됩니다. 즉, 연산 결과가 너무 크거나 작아서 목적지 피연산자가 표현할 수 있는 범위를 벗어나면 Overflow 플래그가 설정됩니다.
  5. Parity flag: Parity 플래그는 명령어가 목적지 피연산자의 낮은 바이트에서 짝수 개의 1 비트를 생성할 때 설정됩니다. 이는 피연산자의 비트 수가 짝수인지 홀수인지를 나타냅니다.

이러한 플래그들은 조건부 분기, 즉 조건에 따라 다른 코드를 실행하는 기능을 지원하는데 중요하게 사용됩니다. 예를 들어, 특정 연산 후에 Zero 플래그가 설정되었는지를 확인함으로써 연산 결과가 0인지 아닌지를 알 수 있고, 이를 바탕으로 프로그램의 동작을 조건적으로 변경할 수 있습니다.

2. AND Instruction

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
  • The following operand combinations are permitted:
AND reg, reg
AND reg, mem
AND mem, reg
AND mem, imm
AND reg, imm
XYX ^ Y
000
010
100
111
  • The operands can be 8, 16, 32, or 64 bits, and they must be the same size
  • Immediate operands can be no larger than 32 bits

Bit masking

  • The AND instruction lets you clear 1 or more bits in an operand without affecting other bits
  • E.g.) A control byte is about to be copied from the AL register to a hardware device. Further, we will assume that the device resets itself when bits 0 and 3 are cleared in the control byte. Assuming that we want to reset the device without modifying any other bits in AL, we can write the following:
and AL, 11110110b

Flags

  • The AND instruction always clears the Overflow and Carry flags
  • It modifies the Sign, Zero, and Parity flags according to the destination operand

Converting Characters to Upper case

  • The AND instruction provides an easy way to translate a letter from lowercase to uppercase
  • If we compare the ASCII codes of capital A and lowercase a, it becomes clear that only bit 5 is different

    0 1 1 0 0 0 0 1 = 61h ('a')
    0 1 0 0 0 0 0 1 = 41h ('A')

  • The rest of the alphabetic characters have the same relationship
  • If we AND any character with 11011111 binary, all bits are unchanged except for bit 5, which is cleared
  • In the following example, all characters in an array are converted to uppercase
.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이 됩니다.

XYX ^ Y
000
010
100
111

피연산자는 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 명령어에 의해 배열의 다음 요소로 이동합니다. 이 과정을 배열의 모든 요소에 대해 수행하여 최종적으로 모든 문자를 대문자로 변환합니다.

3. OR Instruction

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

  • The following operand combinations are permitted:

    OR reg, reg
    OR mem, reg
    OR reg, mem
    OR mem, imm
    OR reg, imm

  • The operands can be 8, 16, 32, or 64 bits, and they must be the same size
  • For each matching bit in the two operands, the output bit is 1 when at least one of the input bits is 1
XYX ˇ Y
000
011
101
111

The OR instruction is particularly useful when you need to set 1 or more bits in an operand without affecting any other bits

  • E.g.) Suppose that your computer is attached to a servo motor, which is activated by setting bit 2 in its control byte. Assuming that the AL register contains a control byte in which each bit contains some important information, the following code only sets the bit in position 2

    or AL, 00000100b

Flags

  • The OR instruction always clears the Carry and Overflow flags
  • It modifies the Sign, Zero, and Parity flags according to the destination operand

OR 명령어는 두 피연산자의 일치하는 각 비트 사이에 불린 OR 연산을 수행하고 결과를 목적지 피연산자에 위치시킵니다. 이 명령어의 기본 형태는 다음과 같습니다.

OR destination, source

다음은 허용되는 피연산자 조합입니다:

OR reg, reg
OR mem, reg
OR reg, mem
OR mem, imm
OR reg, imm

비트 단위의 OR 연산은 각각의 비트에 대해 수행되며, 두 비트 중 하나라도 1일 때 결과가 1이 됩니다.

XYX ˇ Y
000
011
101
111

피연산자는 8, 16, 32, 또는 64비트일 수 있으며, 동일한 크기를 가져야 합니다.

OR 명령어는 다른 비트에 영향을 미치지 않고 피연산자의 하나 이상의 비트를 설정할 필요가 있을 때 특히 유용합니다. 예를 들어, 컴퓨터가 서보 모터에 연결되어 있고, 이는 제어 바이트의 비트 2를 설정함으로써 활성화된다고 가정합시다. AL 레지스터가 각 비트에 중요한 정보를 포함하는 제어 바이트를 포함한다고 가정하면, 다음 코드는 위치 2에 있는 비트만 설정합니다:

or AL, 00000100b

Flags
OR 명령어는 항상 Carry와 Overflow 플래그를 클리어합니다. 그리고 목적지 피연산자에 따라 Sign, Zero, Parity 플래그를 수정합니다. 이러한 플래그들은 명령어 실행 후에 발생한 상태를 나타내고, 다른 명령어의 실행 흐름을 제어하는 데 사용될 수 있습니다.

4. Bit-Mapped Sets

Some applications manipulate sets of items selected from a limited-sized universal set

  • E.g.) Employees within a company, environmental readings from a weather monitoring station
  • In such cases, binary bits can indicate set membership

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

  • The following binary number uses bit positions numbered from 0 on the right to 31 on the left to indicate that array elements 0, 1, 2, and 31 are members of the set named SetX

    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?
  • If the AND instruction in this example clears the Zero flag, we know that element [4] is a member of SetX

Set Complement

  • The complement of a set can be generated using the NOT instruction, which reverses all bits
  • Therefore, the complement of the SetX is generated in EAX using the following instructions:
mov eax, SetX
not eax			; complement of SetX

Set Intersection

  • The AND instruction produces a bit vector that represents the intersection of two sets
  • The following code generates and stores the intersection of SetX and SetY in EAX:
mov eax, SetX
and eax, SetY
  • This is how the intersection of SetX and SetY is produced:
  • It is hard to imagine any faster way to generate a set intersection
  • A larger domain would require more bits than could be held in a single register, making it necessary to use a loop to AND all of the bits together

Set Uniton

  • The OR instruction produces a bit map that represents the union of two sets
  • The following code generates the union of SetX and SetY in EAX
mov eax, SetX
or 	eax, SetY
  • This is how the union of SetX and SetY is generated by the OR instruction:

비트 매핑된 집합은 제한된 크기의 유니버설 집합에서 선택된 아이템의 집합을 조작하는 일부 애플리케이션에서 사용됩니다. 예를 들어, 회사 내의 직원들이나 날씨 모니터링 스테이션에서의 환경 데이터 등이 이에 해당합니다. 이런 경우에는 이진 비트가 집합 멤버십을 나타낼 수 있습니다.

컨테이너에 객체에 대한 포인터나 참조를 보관하는 대신, 애플리케이션은 비트 벡터를 사용해 이진 숫자의 비트를 객체의 배열에 매핑할 수 있습니다.

예시
다음 이진 숫자는 오른쪽에서 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이 되도록 합니다. 이는 집합의 합집합에서와 같이 두 집합 중 어느 하나라도 해당 항목을 포함하고 있다면 결과 집합도 그 항목을 포함하게 됩니다.

이렇게 해서, 우리는 비트 맵을 사용하여 집합 연산을 효과적으로 수행할 수 있음을 볼 수 있습니다. 이는 간단한 이진 연산을 사용하여 빠르게 수행할 수 있으므로, 많은 양의 데이터에 대한 집합 연산을 처리해야 하는 상황에서 매우 유용합니다.

5. XOR Instruction

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

  • The XOR instruction uses the same operand combinations and sizes as the AND and OR instructions
  • For each matching bit in the two operands, the following applies
    • If both bits are the same (both 0 or both 1), the result is 0; otherwise, the result is 1
  • A bit exclusive-ORed with 0 retains its value, and a bit exclusive-ORed with 1 is toggled (complemented)
  • XOR reverses itself when applied twice to the same operand
  • The truth table shows that when bit x is exclusive-ORed with bit y twice, it reverts to its original value
    • This “reversible” property of XOR makes it an ideal tool for a simple form of symmetric encryption
XYX ⊕ Y(X ⊕ Y) ⊕ Y
0000
0110
1011
1101

Flags

  • The XOR instruction always clears the Overflow and Carry flags
  • XOR modifies the Sign, Zero, and Parity flags according to the destination operand
    Checking the Parity Flag
  • Parity checking is performed on a binary number that counts the number of 1 bits contained in the number
    • If the resulting count is even, we say that the data has even parity; if the count is odd, the data has odd parity
  • In x86 processors, the Parity flag is set when the lowest byte of the destination operand of a bitwise or arithmetic operation has even parity
    • Conversely, when the operand has odd parity, the flag is cleared
  • An effective way to check the parity of a number without changing its value is to exclusive-OR the number with zero
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

  • You can check the parity of a 16-bit integer by performing an XOR between the upper and lower bytes
  • The parity of this union will be the same as the parity of the entire 16-bit integer:
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 연산을 활용하면 효율적으로 정수의 패리티를 확인할 수 있습니다.

6. NOT Instruction

The NOT instruction toggles (inverts) all bits in an operand
The result is called the one’s complement

NOT reg
NOT mem

  • For example, the one’s complement of F0h is 0Fh
mov al,11110000b
not al				; AL = 00001111b

Flags

  • No flags are affected by the NOT instruction
  1. NOT 명령어
    NOT 명령어는 피연산자의 모든 비트를 토글 (또는 반전)합니다. 이 결과는 1의 보수(one's complement)라고 불립니다.
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 명령어는 어떠한 플래그도 영향을 주지 않습니다.

7. TEST Instruction

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

  • The TEST instruction can check several bits at once
  • Suppose we want to know whether bit 0 or bit 3 is set in the AL register
  • We can use the following instruction to find this out:

    test al, 00001001b; test bits 0 and 3
    (The value 00001001 in this example is called a bit mask)

  • From the following example data sets, we can infer that the Zero flag is set only when all tested bits are clear:

    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

  • The TEST instruction always clears the Overflow and Carry flags
  • It modifies the Sign, Zero, and Parity flags in the same way as the AND instruction

TEST 명령어는 AND 연산을 수행하지만, 목적 피연산자를 수정하지는 않습니다. TEST 명령어는 AND 명령어와 같은 피연산자 조합을 허용합니다. TEST는 피연산자의 개별 비트가 설정되어 있는지 확인하는 데 매우 유용합니다.

예시: 여러 비트 테스트

  • TEST 명령어는 한 번에 여러 비트를 검사할 수 있습니다.
  • 예를 들어, AL 레지스터의 비트 0 또는 비트 3이 설정되어 있는지 알고 싶다고 가정합시다.
  • 다음 명령어를 사용하여 이를 확인할 수 있습니다:

    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) 플래그를 수정합니다.

플래그는 프로그램의 실행 상태를 나타내는 데 사용되는 특별한 레지스터의 비트입니다. 이들은 종종 연산 결과의 특성을 나타냅니다.

  • 부호(Sign) 플래그: 명령어의 결과가 음수이면 설정되고, 그렇지 않으면 클리어됩니다.
  • 제로(Zero) 플래그: 명령어의 결과가 0이면 설정되고, 그렇지 않으면 클리어됩니다.
  • 패리티(Parity) 플래그: 명령어의 결과에서 낮은 바이트의 1 비트의 수가 짝수이면 설정되고, 홀수이면 클리어됩니다.

예를 들어, 'test al, 00001001b' 명령어는 AL 레지스터의 비트 0과 비트 3를 테스트합니다. 이 비트가 모두 클리어되면(즉, 값이 0이면) 제로 플래그는 설정되고, 그렇지 않으면 클리어됩니다.

테스트의 결과가 음수이면 부호 플래그가 설정되지만, 이 경우에는 AND 연산의 결과이므로 항상 0 또는 양수이므로 부호 플래그는 클리어됩니다.

마지막으로, 테스트 결과에서 낮은 바이트의 1 비트의 수가 짝수이면 패리티 플래그가 설정되고, 홀수이면 클리어됩니다. 이는 명령어 실행 후 패리티를 확인하는 데 유용할 수 있습니다.

8. CMP Instruction

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

  • Character codes are also integers, so they work with CMP as well

CMP performs an implied subtraction of a source operand from a destination operand

  • Neither operand is modified
  • CMP uses the same operand combinations as the AND instruction

    CMP destination, source

Flags

  • CMP changes the Overflow, Sign, Zero, Carry, Auxiliary Carry, and Parity flags according to the value the destination operand would have had if actual subtraction had taken place

Examples: how flags are affected by the CMP instruction

  • When AX equals 5 and is compared to 10, the Carry flag is set because subtracting 10 from 5 requires a borrow:
mov ax, 5
cmp ax, 10		; ZF = 0 and CF = 1
  • Comparing 1000 to 1000 sets the Zero flag because subtracting the source from the destination produces zero:
mov ax,1000
mov cx,1000
cmp cx,ax		; ZF = 1 and CF = 0
  • Comparing 105 to 0 clears both the Zero and Carry flags because subtracting 0 from 105 generates a positive, nonzero value:
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 명령어는 실제로 뺄셈이 발생했을 경우 목적지 피연산자가 가졌을 값을 바탕으로 Overflow, Sign, Zero, Carry, Auxiliary Carry, 그리고 Parity 플래그를 변경합니다.

다음은 CMP 명령어가 플래그에 어떤 영향을 미치는지에 대한 몇 가지 예입니다:

  • AX가 5이고 10과 비교할 때, 5에서 10을 빼려면 대출이 필요하기 때문에 Carry 플래그가 설정됩니다.
mov ax, 5
cmp ax, 10		; ZF = 0 and CF = 1
  • 1000과 1000을 비교하면, 출발지에서 목적지를 빼면 0이 되므로 Zero 플래그가 설정됩니다.
mov ax,1000
mov cx,1000
cmp cx,ax		; ZF = 1 and CF = 0
  • 105와 0을 비교하면, 0에서 105를 빼면 양의 비제로 값이 생성되므로 Zero와 Carry 플래그가 모두 클리어됩니다.
mov si, 105
cmp si, 0		; ZF = 0 and CF = 0

9. Setting and Clearing Individual CPU Flags

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

  • To set the Zero flag, TEST or AND an operand with Zero. To clear the Zero flag, OR an operand with 1:
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

  • To set the Sign flag, OR the highest bit of an operand with 1. To clear the Sign flag, AND the highest bit with 0:
or 		al, 80h		; set Sign flag
and		al, 7Fh		; clear Sign flag
  • To set the Carry flag, use the STC instruction; to clear the Carry flag, use CLC:
stc					; set Carry flag
clc					; clear Carry flag
  • To set the Overflow flag, add two positive values that produce a negative sum. To clear the Overflow flag, OR an operand with 0:
mov 	al, 7Fh		; AL = +127
inc 	al			; AL = 80h (-128), OF = 1
or 		eax, 0		; clear Overflow flag

여기에서는 특정 CPU 플래그를 설정하거나 클리어하는 방법에 대해 설명하고 있습니다. 이 방법들 중 일부는 목적지 피연산자를 수정하는 것을 필요로 합니다.

  1. Zero 플래그 설정 및 클리어
    Zero 플래그를 설정하려면, TEST 또는 AND 명령어를 사용해 피연산자와 0을 함께 처리합니다.
    Zero 플래그를 클리어하려면, OR 명령어를 사용해 피연산자와 1을 함께 처리합니다.
    TEST 명령어는 피연산자를 변경하지 않지만, AND 명령어는 피연산자를 변경합니다.
test 	al, 0		; set Zero flag
and 	al, 0		; set Zero flag
or		al, 0		; clear Zero flag
  1. Sign 플래그 설정 및 클리어
    Sign 플래그를 설정하려면, 피연산자의 최상위 비트를 1로 OR 처리합니다.
    Sign 플래그를 클리어하려면, 최상위 비트를 0으로 AND 처리합니다.
or 		al, 80h		; set Sign flag
and		al, 7Fh		; clear Sign flag
  1. Carry 플래그 설정 및 클리어
    Carry 플래그를 설정하려면, STC 명령어를 사용합니다.
    Carry 플래그를 클리어하려면, CLC 명령어를 사용합니다.
stc					; set Carry flag
clc					; clear Carry flag
  1. Overflow 플래그 설정 및 클리어
    Overflow 플래그를 설정하려면, 음수 합계를 생성하는 두 개의 양수 값을 더합니다.
    Overflow 플래그를 클리어하려면, 피연산자와 0을 OR 처리합니다.
mov 	al, 7Fh		; AL = +127
inc 	al			; AL = 80h (-128), OF = 1
or 		eax, 0		; clear Overflow flag

이들 명령어는 개발자가 플래그를 통해 프로그램의 로직을 제어할 수 있게 해줍니다. 플래그의 상태에 따라 프로그램의 동작이 결정되기 때문에, 이들을 적절하게 설정하고 클리어하는 것이 중요합니다.

Conditional Jumps

1. Conditional Structures

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:

  1. An operation such as CMP, AND, or SUB modifies the CPU status flags
  2. A conditional jump instruction tests the flags and causes a branch to a new address

Example 1

  • The CMP instruction compares EAX to Zero
  • The JZ (Jump if zero) instruction jumps to label L1 if the Zero flag was set by the CMP instruction
	cmp		eax, 0
	jz		L1				; jump if ZF = 1
	.
	.
L1:

Example 2

  • The AND instruction performs a bitwise AND on the DL register, affecting the Zero flag
  • The JNZ (jump if not Zero) instruction jumps if the Zero flag is clear
	and 	dl, 10110000b
    jnz		L2				; jump if ZF = 0
    .
    .
 L2:

조건부 점프는 높은 수준의 프로그래밍 언어에서 보통 볼 수 있는 if-then-else나 while 문과 같은 제어 구조를 구현하는 데 사용됩니다. 이러한 구조는 x86 명령어 세트에 명시적으로는 포함되어 있지 않지만, 비교 및 점프 조합을 사용하여 이들을 구현할 수 있습니다.

조건부 점프를 수행하는 데는 두 단계가 있습니다:

  1. CMP, AND, SUB 등의 명령어가 CPU 상태 플래그를 변경합니다. 이러한 명령어는 두 값을 비교하거나 연산하여 그 결과에 따라 CPU의 상태 플래그를 설정하게 됩니다.
  2. 조건부 점프 명령어는 이 플래그를 검사하고, 플래그의 상태에 따라 프로그램의 실행을 다른 주소로 이동시킵니다.

이를 통해 논리적인 조건을 사용하여 프로그램의 흐름을 제어할 수 있게 됩니다.

예시 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로 점프하게 됩니다.

이러한 조건부 점프는 복잡한 로직을 구현하는 데 필요한 중요한 기능입니다.

2. Jcond Instruction

A conditional jump instruction branches to a destination label when a status flag condition is true

  • Otherwise, if the flag condition is false, the instruction immediately following the conditional jump is executed

The syntax:

Jcond destination

cond refers to a flag condition identifying the state of one or more flags

JCJump if carry (Carry flag set)
JNCJump if not carry (Carry flag clear)
JZJump if zero (Zero flag set)
JNZJump 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

  • Example 1
    • Suppose you want to jump to label L1 when EAX equals 5
    • If EAX equals 5, the CMP instruction sets the Zero flag; then, the JE instruction jumps to L1 because the Zero flag is set:
cmp	eax, 5
je	L1				; jump if equal
  • The JE instruction always jumps based on the value of the Zero flag
  • If EAX were not equal to 5, CMP would clear the Zero flag, and the JE instruction would not jump
  • Example 2
    • The JL instruction jumps to label L1 because AX is less than 6
mov	ax, 5
cmp	ax, 6
jl	L1				; jump if less
  • Example 3
    • The jump is taken because AX is greater than 4
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 명령어를 사용하는 예제들을 살펴봅시다:

  • 예제 1: EAX가 5일 때 레이블 L1로 점프하려고 합니다. 이 경우, EAX가 5이면 CMP 명령어는 Zero 플래그를 설정하고, JE 명령어는 Zero 플래그가 설정되었으므로 L1로 점프합니다. 만약 EAX가 5가 아니라면, CMP는 Zero 플래그를 클리어하고, JE 명령어는 점프하지 않습니다.
  • 예제 2: AX가 6보다 작으므로 JL 명령어는 레이블 L1로 점프합니다.
  • 예제 3: AX가 4보다 크므로 JG 명령어는 레이블 L1로 점프합니다.

이런 식으로 조건부 점프 명령어를 사용하면 복잡한 제어 흐름을 구현할 수 있습니다.

3. Types of Conditional Jump Instructions

  • Conditional jump instructions are able to compare signed and unsigned integers and perform actions based on the values of individual CPU flags
  • The conditional jump instructions can be divided into four groups:
    • Jumps based on specific flag values
    • Jumps based on equality between operands or the value of (E)CX
    • Jumps based on comparisons of unsigned operands
    • Jumps based on comparisons of signed operands
  • Jumps based on specific flag values
MnemonicDescriptionFlags/Registers
JZJump if zeroZF = 1
JNZJump if not zeroZF = 0
JCJump if carryCF = 1
JNCJump if not carryCF = 0
JOJump if overflowOF = 1
JNOJump if not overflowOF = 0
JSJump if signedSF = 1
JNSJump if not signedSF = 0
JPJump if parity(even)PF = 1
JNPJunp if not parity(odd)PF = 0

조건부 점프 명령어는 부호가 있는 정수와 부호가 없는 정수를 비교하고, 개별 CPU 플래그의 값에 따라 동작을 수행할 수 있습니다. 이들 조건부 점프 명령어는 다음과 같이 네 가지 그룹으로 나눌 수 있습니다:

  1. 특정 플래그 값에 기반한 점프
  2. 피연산자 간의 동등성 또는 (E)CX 값에 기반한 점프
  3. 부호가 없는 피연산자 비교에 기반한 점프
  4. 부호가 있는 피연산자 비교에 기반한 점프

이 중 특정 플래그 값에 기반한 점프를 표로 정리해보면 다음과 같습니다:

이렇게 조건부 점프 명령어는 CPU의 플래그 상태에 따라 프로그램의 실행 흐름을 제어하는 데 사용됩니다. 이를 통해 복잡한 제어 구조를 구현할 수 있습니다.

Equality Comparisons

MnemonicDescription
JEJump if equal (leftOp = rightOp)
JNEJump if not equal (leftOp ≠ rightOp)
JCXZJump if CX = 0
JECXZJump if ECX = 0
JRCXZJump if RCX = 0 (64-bit mode)
  • In some cases, two operands are compared; in other cases, a jump is taken based on the value of (E)CX
  • The notations leftOp and rightOp refer to the left (destination) and right (source) operands in a CMP instruction: CMP leftOp, rightOp
    • The operand names reflect the ordering of operands for relational operators in algebra
    • For example, in the expression X < Y, X is called leftOp and Y is called rightOp
  • The JE instruction is equivalent to JZ and JNE is equivalent to JNZ
    • It’s best to select the mnemonic (JE or JZ) that best indicates your intention to either compare two operands or examine a specific status flag

등식 비교에 사용되는 조건부 점프 명령어는 다음과 같습니다:

일부 경우에서는 두 피연산자를 비교하고, 다른 경우에서는 (E)CX 값에 따라 점프가 발생합니다. 여기서 사용되는 leftOp와 rightOp는 CMP 명령어에서 왼쪽(대상) 피연산자와 오른쪽(원본) 피연산자를 가리킵니다: CMP leftOp, rightOp. 피연산자 이름은 대수학에서 관계 연산자의 피연산자 순서를 반영합니다. 예를 들어, X < Y 표현식에서 X는 leftOp, Y는 rightOp로 불립니다.

JE 명령어는 JZ와 동일하며, JNE는 JNZ와 동일합니다. 두 피연산자를 비교하려는 의도인지, 특정 상태 플래그를 검사하려는 의도인지를 가장 잘 나타내는 기호(JE 또는 JZ)를 선택하는 것이 가장 좋습니다. 이들 명령어를 사용하면 피연산자 간의 동등성이나 레지스터 (E)CX의 값에 따라 프로그램의 실행 흐름을 제어할 수 있습니다.

Example

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 어셈블리에서 프로그램의 실행 흐름을 제어하는 주요 방법입니다.

Unsigned Comparisons

  • These jumps are only meaningful when comparing unsigned values
MnemonicDescription
JAJump if above(if leftOp > rightOp)
JNBEJump if not below or equal(same as JA)
JAEJump if above or equal(if leftOp ≥ rightOp)
JNBJump if not below(same as JAE)
JBJump if below (if leftOp < rightOp)
JNAEJump if not above or equal (same as JB)
JBEJump if below or equal (if leftOp ≤ rightOp)
JNAJump if not above(same as JBE)

먼저, "unsigned"는 부호가 없다는 뜻으로, 음수나 양수를 가질 수 없는 정수를 가리킵니다. 따라서, 'unsigned comparisons'은 부호가 없는 정수 값을 비교하는 것을 말합니다.

다음은 각 mnemonic에 대한 자세한 설명입니다:

  1. JA (Jump if Above): 이 명령어는 왼쪽 피연산자가 오른쪽 피연산자보다 클 때 점프합니다.
  2. JNBE (Jump if Not Below or Equal): 'JA'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 클 때 점프합니다.
  3. JAE (Jump if Above or Equal): 왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같을 때 점프합니다.
  4. JNB (Jump if Not Below): 'JAE'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같을 때 점프합니다.
  5. JB (Jump if Below): 왼쪽 피연산자가 오른쪽 피연산자보다 작을 때 점프합니다.
  6. JNAE (Jump if Not Above or Equal): 'JB'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 작을 때 점프합니다.
  7. JBE (Jump if Below or Equal): 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같을 때 점프합니다.
  8. JNA (Jump if Not Above): 'JBE'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같을 때 점프합니다.

이런 방식으로, 이러한 명령어들은 조건부 점프를 수행하면서 프로그램의 실행 흐름을 제어합니다.

Signed Comparisons

MnemonicDescription
JGJump if greater(if leftOp > rightOp)
JNLEJump if less than or equal(same as JG)
JGEJump if greater than or equal(if leftOp ≥ rightOp)
JNLJump if not less(same as JGE)
JLJump if less(if leftOp < rightOp)
JNGEJump if not greater than or eqaul(same as JL)
JLEJump if less than or equal(if leftOp ≤ rightOp)
JNGJump 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에 대한 자세한 설명은 다음과 같습니다:

  1. JG (Jump if Greater): 왼쪽 피연산자가 오른쪽 피연산자보다 클 때 점프합니다.
  2. JNLE (Jump if Not Less or Equal): 'JG'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 클 때 점프합니다.
  3. JGE (Jump if Greater or Equal): 왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같을 때 점프합니다.
  4. JNL (Jump if Not Less): 'JGE'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같을 때 점프합니다.
  5. JL (Jump if Less): 왼쪽 피연산자가 오른쪽 피연산자보다 작을 때 점프합니다.
  6. JNGE (Jump if Not Greater or Equal): 'JL'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 작을 때 점프합니다.
  7. JLE (Jump if Less or Equal): 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같을 때 점프합니다.
  8. JNG (Jump if Not Greater): 'JLE'와 동일한 동작을 수행합니다. 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같을 때 점프합니다.

예시에서 보시면, al 레지스터에 +127(16진수로는 7Fh)를 할당하고, 이를 -128(16진수로는 80h)과 비교합니다. 그 다음에는 'JA'와 'JG' 명령어를 사용하여 두 가지 다른 결과를 얻습니다:

  • JA IsAbove는 점프하지 않습니다. 왜냐하면 이 경우에는 부호 없는 값으로 비교되며, 16진수로 보면 7Fh는 80h보다 작습니다.
  • 반면에, JG IsGreater는 점프합니다. 이 경우에는 부호 있는 값으로 비교되며, +127은 -128보다 크기 때문입니다.

이런 방식으로, 이러한 명령어들은 조건부 점프를 수행하면서 프로그램의 실행 흐름을 제어합니다.

Example

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과 비교합니다.

  • jnl 명령어는 "Jump if Not Less"로, 왼쪽 피연산자가 오른쪽 피연산자보다 작지 않다면 점프하는 명령어입니다. 하지만 여기서 -1은 0보다 작으므로 점프는 발생하지 않습니다.
  • jnle 명령어는 "Jump if Not Less or Equal"로, 왼쪽 피연산자가 오른쪽 피연산자보다 크다면 점프하는 명령어입니다. -1은 0보다 크지 않으므로 점프는 발생하지 않습니다.
  • jl 명령어는 "Jump if Less"로, 왼쪽 피연산자가 오른쪽 피연산자보다 작다면 점프하는 명령어입니다. -1은 0보다 작으므로 L1로 점프하게 됩니다.

Example 2:

이 예제에서는 BX 레지스터에 +32를 할당하고, 이를 -35와 비교합니다.

  • jng 명령어는 "Jump if Not Greater"로, 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같다면 점프하는 명령어입니다. 여기서 +32는 -35보다 크므로 점프는 발생하지 않습니다.
  • jnge 명령어는 "Jump if Not Greater or Equal"로, 왼쪽 피연산자가 오른쪽 피연산자보다 작다면 점프하는 명령어입니다. +32는 -35보다 크므로 점프는 발생하지 않습니다.
  • jge 명령어는 "Jump if Greater or Equal"로, 왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같다면 점프하는 명령어입니다. +32는 -35보다 크므로 L1로 점프하게 됩니다.

Example 3:

이 예제에서는 ECX 레지스터에 0을 할당하고, 이를 0과 비교합니다.

  • jg 명령어는 "Jump if Greater"로, 왼쪽 피연산자가 오른쪽 피연산자보다 크다면 점프하는 명령어입니다. 하지만 0은 0보다 크지 않으므로 점프는 발생하지 않습니다.
  • jnl 명령어는 "Jump if Not Less"로, 왼쪽 피연산자가 오른쪽 피연산자보다 작지 않다면 점프하는 명령어입니다. 0은 0보다 작지 않으므로 L1로 점프하게 됩니다.

Example 4:

  • jl 명령어는 "Jump if Less"로, 왼쪽 피연산자가 오른쪽 피연산자보다 작다면 점프하는 명령어입니다. 하지만 0은 0보다 작지 않으므로 점프는 발생하지 않습니다.
  • jng 명령어는 "Jump if Not Greater"로, 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같다면 점프하는 명령어입니다. 0은 0보다 작거나 같으므로 L1로 점프하게 됩니다.

4. Conditional Jump Applications

Testing Status Bits

  • Often, we do not want to change the values of the bits we’re testing, but we do want to modify the values of CPU status flags
  • Conditional jump instructions often use these status flags to determine whether or not to transfer control to code labels
  • Suppose that an 8-bit memory operand named status contains status information about an external device attached to the computer
    • The following instructions jump to a label if bit 5 is set, indicating that the device is offline:
    mov	al, status
    test	al, 00100000b		; test bit 5
    jnz		DeviceOffline
    • The following statements jump to a label if any of the bits 0, 1, or 4 are set:
    mov 	al,status
    test	al, 00010011b		; test bit 0, 1, 4
    jnz 	InputDataByte
    • Jumping to a label if bits 2, 3, and 7 are all set requires both the AND and CMP instructions:
    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' 라벨로 점프하게 됩니다.

이러한 방법으로, 조건부 점프 명령어는 상태 플래그를 테스트하고, 해당 결과에 따라 특정 코드 블록으로 제어를 전송하는 데 사용됩니다.

Larger of Two Integers

  • The following code compares the unsigned integers in EAX and EBX and moves the larger of the two to EDX:
	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는 두 정수 중 더 큰 값을 가지게 됩니다.

Loop until Key Pressed

  • In the following 32-bit code, a loop runs continuously until the user presses a standard alphanumeric key
  • The ReadKey method from the Irvine32 library sets the Zero flag if no key is present in the input buffer
    • The code inserts a 10-millisecond delay in the loop to give MS-Windows time to process event messages
    • If you omit the delay, keystrokes may be ignored
.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' 변수에 저장합니다.

Application: Sequential Search of an Array

  • The following program looks for the first nonzero value in an array of 16-bit integers
    • If it finds one, it displays the value
    • Otherwise, it displays a message stating that a nonzero value was not found
; 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"라는 메시지를 출력합니다.

Application: Simple String Encryption

  • If an integer X is XORed with Y and the resulting value is XORed with Y again, the value produced is X:

    (( X ⊗ Y ) ⊗ Y ) = X

    • This reversible property of XOR provides an easy way to perform a simple form of data encryption:
      • A plain text message is transformed into an encrypted string called cipher text by XORing each of its characters with a character from a third string called a key
      • The intended viewer can use the key to decrypt the cipher text and produce the original plain text
  • Example Program
    • We will demonstrate a simple program that uses symmetric encryption, a process by which the same key is used for both encryption and decryption
    • The following steps occur in order at runtime:
      1.The user enters the plain text
      2.The program uses a single-character key to encrypt the plain text, producing the cipher text, which is displayed on the screen
      3.The program decrypts the cipher text, producing and displaying the original plain text
  • Here is sample output from the program
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 = 239 : 텍스트를 암호화하고 복호화하는 데 사용되는 키 값입니다.
  • BUFMAX = 128 : 버퍼의 최대 크기를 정의합니다.

이 프로그램의 주요 부분을 살펴보면 다음과 같습니다:\

  • main PROC: 사용자로부터 원본 텍스트를 입력받아 암호화하고, 암호화된 텍스트를 출력하고, 다시 복호화하여 원본 텍스트를 출력하는 주요 루틴입니다.
  • InputTheString PROC: 사용자로부터 원본 텍스트를 입력받는 부분입니다.
  • DisplayMessage PROC: 암호화된 텍스트나 복호화된 텍스트를 출력하는 부분입니다.
  • TranslateBuffer PROC: 실제로 텍스트를 암호화하고 복호화하는 부분입니다. 이 함수는 주어진 텍스트의 각 바이트를 암호화 키와 XOR 연산하여 암호화하거나 복호화합니다.

즉, 이 프로그램은 입력받은 원본 텍스트를 KEY와 XOR 연산하여 암호화하고, 암호화된 텍스트를 다시 KEY와 XOR 연산하여 원본 텍스트를 복원하는 과정을 보여줍니다. 이렇게 XOR 연산을 통해 데이터를 암호화하고 복호화하는 방법을 "대칭키 암호화"라고 합니다. 대칭키 암호화는 암호화와 복호화에 동일한 키를 사용하는 방식입니다.

Conditional Loop Instructions

1. LOOPZ and LOOPE Instructions

The LOOPZ (loop if zero) instruction

  • This instruction works like the LOOP instruction, but the Zero flag must be set in order for control to transfer to the destination label

The LOOPE (loop if equal) instruction

  • Equivalent to LOOPZ, and they share the same opcode

They perform the following tasks:

  • Otherwise, no jump occurs, and control passes to the next instruction

LOOPZ and LOOPE do not affect any of the status flags

2. LOOPNZ and LOOPNE Instructions

The LOOPNZ (loop if not zero) instruction

  • The counterpart of LOOPZ
  • The loop continues while the unsigned value of ECX is greater than zero (after being decremented) and the Zero flag is clear

    LOOPNZ destination

The LOOPNE (loop if not equal) instruction

  • Equivalent to LOOPNZ, and they share the same opcode

They perform the following tasks:

ECX = ECX - 1
if ECX > 0 and ZF = 0, jump to destination
  • Otherwise, nothing happens, and control passes to the next instruction

Example

  • The following code scans each number in an array until a nonnegative number is found
  • Notice that we push the flags on the stack before the ADD instruction because ADD will modify the flags
  • Then the flags are restored by POPFD just before the LOOPNZ instruction executes
.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:

Conditional Structures

Conditional structure

  • One or more conditional expressions that trigger a choice between different logical branches
  • Each branch causes a different sequence of instructions to execute

1. Block-Structured IF Statements

  • If structure in HLL
if( boolean-expression )
	statement-list-1
else
	statement-list-2
  • In assembly language
    • First, we evaluate the boolean expression in such a way that one of the CPU status flags is affected
    • Second, we construct a series of jumps that transfer control to the two lists of statements, based on the value of the relevant CPU status flag

Example

if ( op1 == op2 )
{
	X = 1;
    Y = 2;
}
  • We can translate this IF statement into assembly language with a CMP instruction followed by conditional jumps
	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:
  • If we implemented the == operator using JE, the resulting code would be slightly less compact (six instructions rather than five)
	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:

Example2

  • In the NTFS file storage system, the size of a disk cluster depends on the disk volume’s overall capacity
  • In the following pseudocode, we set the cluster size to 4,096 if the volume size is less than 16 Tbytes
  • Otherwise, we set the cluster size to 8,192
clusterSize = 8192;
if terrabytes < 16
	clusterSize = 4096;
  • We can implement the pseudocode in assembly language
	mov clusterSize, 8192		; assume larger cluster
    cmp terrabytes, 16			; smaller than 16 TB?
    jae	next
    mov clusterSize, 4096		; switch to smaller cluster
next:

Example3

if op1 > op2
	call Routine1
else
	call Routine2
end if
  • In the following assembly language translation of the pseudocode, we assume that op1 and op2 are signed doubleword variables
  • When comparing variables, one must be moved to a register
	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:

White Box Testing

  • Complex conditional statements may have multiple execution paths, making them hard to debug
  • Programmers often implement a technique known as white box testing, which verifies a subroutine’s inputs and corresponding outputs
    • White box testing requires you to have a copy of the source code
    • You assign a variety of values to the input variables
    • For each combination of inputs, you manually trace through the source code and verify the execution path and outputs produced by the subroutine
if op1 == op2
	if X > Y
    	call Routine1
    else
    	call Routine2
    end if
else
	call Routine3
end if
  • The following code reverses the initial condition (op1 == op2) and immediately jumps to the ELSE portion
  • All that is left to translate is the inner IF-ELSE statement
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:
op1op2XYLine Execution SequenceCalls
102030401, 2, 3, 11, 12Routine3
102040301, 2, 3, 11, 12Routine3
101030401, 2, 3, 4, 5, 6, 7, 8, 12Routine2
101040301, 2, 3, 4, 5, 6, 9, 10, 12Routine1

2. Compound Expressions

Logical AND Operator

if (al > bl) AND (bl > cl)
	X = 1
end if
  • Short-Circuit Evaluation
    • The following is a straightforward implementation using short-circuit evaluation
      • The second expression is not evaluated if the first expression is false
      	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:
    • We can reduce the code to five instructions by changing the initial JA instruction to JBE
	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:

Logical OR Operator

if (al > bl) OR (bl > cl)
	X = 1
  • In the following implementation, the code branches to L1 if the first expression is true
    • otherwise, it falls through to the second CMP instruction
  • The second expression reverses the > operator and uses JBE instead
	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:

3. WHILE Loops

  • It is convenient to reverse the loop condition and jump to endwhile if a condition becomes true
  • Assuming that val1 and val2 are variables, we must copy one of them to a register at the beginning and restore the variable’s value at the end
	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
  • EAX is a substitute for val1 inside the loop
  • References to val1 must be through EAX
  • JNL is used, implying that val1 and val2 are signed integers

Example: IF statement Nested in a Loop

  • The following code calculates the sum of all array elements greater than the value in sample
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

    • EDX = sample, EAX = sum, ESI = index, and ECX = ArraySize
  • 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

4. Table-Driven Selection

A way of using a table lookup to replace a multiway selection structure

  • You must create a lookup table, and then you must use a loop to search the table
    • The table must contain lookup values and the offsets of labels or procedures
  • E.g.) The following is part of a table containing single-character lookup values and addresses of procedures
.data
CaseTable BYTE 'A'			; lookup value
	DWORD Process_A			; address of procedure
    BYTE 'B'
    DWORD Process_B
     (etc.)
  • Assume that Process_A, Process_B, Process_C, and Process_D are located at addresses 120h, 130h, 140h, and 150h, respectively

Example Program

  • The user inputs a character from the keyboard
  • Using a loop, the character is compared to each entry in a lookup table
  • The 1st match found causes a call to the procedure offset stored immediately after the lookup value
  • Each procedure loads EDX with the offset of a different string, which is displayed during the loop
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

Cons

  • The table-driven selection method involves some initial overhead

Pros

  • The table-driven selection method can reduce the amount of code you write
  • A table can handle a large number of comparisons, and it can be more easily modified than a long series of compare, jump, and CALL instructions
  • A table can even be reconfigured at runtime

Application: Finite-State Machines

A finite-state machine (FSM)

  • A machine or program that changes state based on some input
  • A graph which represents an FSM
    • A node: a program state
    • An edge: a transition from one state to another
    • One node is designated as the initial state
    • One or more states are designated as terminal states
      • A terminal state represents a state in which the program might stop without producing an error
  • A FSM is a specific instance of a more general type of structure called a directed graph

1. Validating an Input String

  • Programs that read input streams often must validate their input
    • E.g.) A programming language compiler can use a FSM to scan source programs and convert words and symbols into tokens, which are usually keywords, arithmetic operators, and identifiers
  • A FSM for checking the validity of an input string
    • Read the input character by character
      • Each character is represented by an edge in the diagram
  • A FSM detects illegal input sequences in one of two ways:
    • The next input character does not correspond to any transitions from the current state
    • The end of input is reached and the current state is a nonterminal state

Character String Example

  • Let’s check the validity of an input string according to the following two rules:
    • The string must begin with the letter “x” and end with the letter “z”
    • Between the first and last characters, there can be zero or more letters within the range {‘a’...‘y’}
  • Each transition is identified with a particular type of input
    • The transition from state A to state B can only be accomplished if the letter x is read from the input stream
    • A transition from state B to itself is accomplished by the input of any letter of the alphabet except z
    • A transition from state B to state C occurs only when the letter z is read from the input stream
  • If the end of the input stream is reached while the program is in state A or B, an error condition results because only state C is marked as a terminal state
  • The following input strings would be recognized by this FSM:
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

Translating finite-state machines into assembly language code

  • Each state in the diagram (A, B, C, . . . ) is represented in the program by a label
  • The following actions are performed at each label
    • 1.A call to an input procedure reads the next character from input
    • 2.If the state is a terminal state, check to see whether the user has pressed the Enter key to end the input
    • 3.One or more compare instructions check for each possible transition leading away from the state. Each comparison is followed by a conditional jump instruction
  • E.g.) At state A, the following code reads the next input character and checks for a possible transition to state B
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

Complete Finite-State Machine Program

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

2. Validating a Signed Integer

IsDigit Procedure

  • The Finite-State Machine sample program calls the IsDigit procedure, which belongs to the Irvine32 library
  • IsDigit receives the AL register as input, and the value it returns is the setting of the Zero flag
;----------------------------------------------------------
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

Conditional Control Flow Directives

  • MASM includes a number of high-level conditional control flow directives that help to simplify the coding of conditional statements
  • In the preprocessing step, the assembler recognizes directives such as .CODE, .DATA, as well as conditional control flow directives
DirectiveDescription
.BREAKGenerates code to terminate a .WHILE or .REPEAT block
.CONTINUEGenerates code to jump to the top of a .WHILE of .REPEAT block
.ELSEBegins block of statements to execute when the .IF condition is false
.ELSEIF conditionGenerates code that tests condition and executes statements that follow, untill an .ENDIF directive or another .ELSEIF directive is found
.ENDIFTerminates a block of statements following an .IF, .ELSE, or .ELSEIF directive
.ENDWTerminates a block of statements following a .WHILE directive
.IF conditionGenerates code that executes the block of statements if condition is true
.REPEATGenerates code that repeats exrcution of the block of statements untill condition becomes true
.UNTIL conditionGenerates code that repeats the block of statement between .REPEAT and .UNTIL until condition becomes true
.UNTILCXZGenerate code that repeats the block of statement between .REPEAT and . UNTILCXZ untile CX equals zero
.WHILE conditionGenerates code that executes the block of statements between .WHILE and .ENDW as long as condition is true

1. Creating IF Statements

.IF, .ELSE, .ELSEIF, and .ENDIF directives

  • They make it easy for you to code multiway branching logic
  • They cause the assembler to generate CMP and conditional jump instructions in the background, which appear in the output listing file
.IF condition1
	statements
[.ELSEIF condition2
	statements ]
[.ELSE
	statements ]
.ENDIF
  • The square brackets show that .ELSEIF and .ELSE are optional, whereas .IF and .ENDIF are required
  • A condition is a boolean expression involving the same operators used in C (such as <, >, ==, and !=)
    • The expression is evaluated at runtime
(eax > 0) && (eax > 10000h)
(val1 <= 100) || (val2 <= 100)
(val2 != ebx) && !CARRY?

Generating ASM CODE

;--------------------------
; 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:
  • You can view expanded assembly language instructions if you run the program in the Visual Studio debugger, right-click, and select Go to Disassembly

2. Signed and Unsigned Comparisons

  • When you use the .IF directive to compare values, you must be aware of how MASM generates conditional jumps
    • If the comparison involves an unsigned variable, an unsigned conditional jump instruction is inserted in the generated code
.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:
  • Comparing a Signed Integer
.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:
  • Comparing Registers
    • The assembler cannot determine whether the values are signed or unsigned
    • The assembler defaults to an unsigned comparison (note the use of the JBE instruction)
	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:

3. Compound Expressions

  • Using the .IF directive with logical OR and AND operators
.IF expression1 || expression2
	statements
.ENDP

.IF expression1 && expression2
	statements
.ENDIF
  • SetCursorPosition Example
    • The SetCursorPosition procedure performs range checking on its two input parameters, DH and DL
      • The Y-coordinate (DH) must be between 0 and 24
      • The X-coordinate (DL) must be between 0 and 79
      • If either is found to be out of range, an error message is displayed
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
  • College Registration Example
    • Suppose a college student wants to register for courses
    • We will use two criteria to determine whether or not the student can register
      • The first is the person’s grade average, based on a 0 to 400 scale, where 400 is the highest possible grade
      • The second is the number of credits the person wants to take
    • A multiway branch structure can be used, involving .IF, .ELSEIF, and .ENDIF
.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:

4. Creating Loops with .REPEAT and .WHILE

The .REPEAT and .WHILE directives

  • They offer alternatives to writing your own loops with CMP and conditional jump instructions
  • The .REPEAT directive executes the loop body before testing the runtime condition following the .UNTIL directive
  • The .WHILE directive tests the condition before executing the loop
  • E.g.) displaying the values 1 through 10

Example: Loop Containing an IF Statement

  • A pseudocode for an IF statement nested inside a WHILE loop:
while( op1 < op2 )
{
	op1++;
    if( op1 == op3 )
    	X = 2;
    else
    	X = 3;
}
  • An assembly language version
.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

profile
스벨트 자바스크립트 익히는중...

0개의 댓글