고급 언어의 조건부 문장이 저수준으로 구현된 코드로 어떻게 변환되는 지를 알아보자.
논리구조 특성을 구현할 때 어셈블리 언어를 어떻게 사용하는지 살펴볼건데,
cpu가 cmp 명령어와 프로세서 상태 플래그를 사용해서 명령어의 피연산자를 비교하므로, 전에 배웠던 상태 플래그를 잠깐 상기해보자.
cpu 플래그
Zero 플래그는 연산 결과가 0일 때 set 설정
Carry 플래그는 명령어가 대상 피연산자에 비해 너무 크거나 작을 때 set
Sign 플래그는 대상 피연산자가 음수이면 set, 대상 피연산자가 양수이면 clear상태로 set
명령어가 유효하지 않은 부호 있는 결과를 생성할 때 오버플로 플래그를 set
ex) 비트 7 캐리가 비트 6 캐리와 XOR됨
Parity 플래그는 명령어가 대상 피연산자의 하위 바이트에 짝수 개의 1비트를 생성할 때 set
Auxiliary Carry 플래그는 연산이 비트 3에서 비트 4로 가는 행동을 생성할 때 set
이러한 상태 플래그들은 bool 명령어를 사용할 때 영향을 받는다.
기본적인 복습을 했으니, 이제 각각의 명령어들이 수행될 때 어떤 작업이 일어나는지 알아보자.
명령어 소개
AND 명령어
두 피연산자에 대응되는 각 비트 쌍에 대해 bool AND 연산을 하고, 목적지 피연산자에 결과를 저장한다.
AND destination, source
두 비트가 모두 1이면 결과 비트는 1이고, 그렇지 않으면 결과 비트는 0이다.
AND 명령어는 다른 비트들에 영향을 주지 않고, 해당 비트들을 0으로 해제한다.
이런 기법을 비트 마스킹 masking이라고 한다.
페인트칠을 할 때 칠하지 말아야 할 부분에 마스킹 테이프를 붙이는 것과 같다.
예를 들어 아스키 코드를 비교해보면 대문자 A와 소문자 a는 비트 5만 다르다.
0 1 1 0 0 0 0 1 = 61h ('a')
0 1 0 0 0 0 0 1 = 41h ('A')
여기에 11011111 비트와 AND시킨다면 문자를 간단하게 대문자로 변환해줄 수 있다.
OR 명령어
두 피연산자에 대응되는 각 비트 쌍에 대해 bool OR 연산을 하고, 목적지 피연산자에 결과를 저장한다.
OR destination, source
두 피연산자의 대응되는 각 비트에 대해서 입력 비트 중 적어도 하나가 1일 때 출력 비트가 1이다.
OR 명령어는 다른 비트들에 영향을 주지 않고 1개 이상의 비트들을 1로 설정할 때 유용하다.
예를 들어 zero와 sign 플래그의 값을 OR 연산하여 AL의 값을 파악할 수 있다.,
zero 플래그 | sign 플래그 | AL의 값 |
0 | 0 | 0보다 크다 |
1 | 0 | 0과 같다 |
0 | 1 | 0보다 작다 |
XOR 명령어
두 피연산자에 대응되는 각 비트 쌍에 대해 비트단위로 XOR 연산을 하고, 목적지 피연산자에 결과를 저장한다.
XOR destination, source
두 비트가 같으면 결과는 0이고, 그렇지 않으면 결과는 1이다.
XOR 명령어는 항상 overflow 와 carry 플래그를 0으로 설정한다.
NOT 명령어
피연산자의 모든 비트를 반대로 바꾼다. 결과는 1의 보수라고 부른다.
NOT destination
TEST 명령어
묵시적으로 두 피연산자에 대응되는 각 비트 쌍에 대해 AND 연산을 하고, 결과에 따라서 sign, zero, parity 플래그를 설정한다.
AND와 달리 TEST 명령어의 경우 목적지 피연산자를 수정하지 않는다. 하지만 플래그는 여전히 영향받는다.
test al,00000011b
jnz ValueFound
CMP 명령어
목적지 피연산자와 소스 피연산자를 비교한다. 대상 피연산자는 변경되지 않는다.
CMP destination, source
몇몇 예시를 알아보자.
목적지와 소스가 서로 같은 경우이다.
mov al,5
cmp al,5 ; Zero flag set
목적지가 소스보다 작은 경우이다.
mov al,4
cmp al,5 ; Carry flag set
destination이 source보다 큰 경우이다.
mov al,6
cmp al,5 ; ZF = 0, CF = 0
아래 예시에서는 부호있는 정수를 사용한다.
목적지가 소스보다 큰 경우이다.
mov al,5
cmp al,-2 ; Sign flag == Overflow flag
목적지가 소스보다 작은 경우이다.
mov al,-1
cmp al,5 ; Sign flag != Overflow flag
조건부 Jump
위에서 소개했던 명령어들의 집합에는 고급 논리 구조는 없지만, 비교와 점프 명령어를 조합해서 고급 논리 구조를 구현할 수 있다.
Jcond destination
Jcond 명령어는 특정 레지스터 또는 플래그 조건이 충족되는 경우 해당 레이블로 분기된다.
다음은 carry, zero, sign, overflow, parity 플래그에 따라 동작하는 명령어다.
ex) 더블워드 메모리 edi가 짝수일 경우 라벨 L2로 점프
test DWORD PTR [edi],1
jz L2
아래는 플래그가 아닌 등호 결과에 따라서 점프하는 명령어다.
ex) ESI가 가리키는 메모리 워드가 0일 경우 라벨 L1으로 점프
cmp WORD PTR [esi],0
je L1
부호 없는 비교에 따른 점프
ex) 부호없는 EAX가 EBX보다 큰 경우
cmp eax,ebx
ja Larger
부호 있는 비교에 따른 점프
ex) 부호 있는 EAX가 Val1보다 작거나 같으면 레이블 L1으로 이동
cmp eax,Val1
jle L1
배운 것을 바탕으로 다음은 루프와 XOR 명령어를 사용하여 문자열의 모든 문자를 암호화 시킬 수 있는 프로그램이다.
KEY = 239 ; can be any byte value
BUFMAX = 128
.data
buffer BYTE BUFMAX+1 DUP(0)
bufSize DWORD BUFMAX
.code ; loop counter
mov ecx,bufSize ; index 0 in buffer
mov esi,0
L1:
xor buffer[esi],KEY ; translate a byte
inc esi ; point to next byte
loop L1
조건부 Loop 명령어
LOOPZ 와 LOOPE 명령어
LOOPE destination
LOOPZ destination
이 명령어들은 ECX가 하나씩 줄어들며, ECX가 0보다 크고 ZF가 1이면 목적지로 점프한다.
주어진 값과 일치 하지 않는 첫 번째 요소에 대한 배열을 검색할 때 유용하다.
LOOPNZ 와 LOOPNE 명령어
LOOPNZ destination
LOOPNE destination
이 명령어들은 ECX가 하나씩 줄어들며, ECX가 0보다 크고 ZF가 0이면 목적지로 점프한다.
주어진 값과 일치하는 첫 번째 요소에 대해 배열을 검색할 때 유용하다.
LOOPNZ 예시) 배열에서 첫 번째 양수 값 찾기
.data
array SWORD -3,-6,-1,-10,10,30,40,4
sentinel SWORD 0
.code
mov esi,OFFSET array
mov ecx,LENGTHOF array
next:
test WORD PTR [esi],8000h ; test sign bit
pushfd ; push flags on stack
add esi,TYPE array
popfd ; pop flags from stack
loopnz next ; continue loop
jnz quit ; none found
sub esi,TYPE array ; ESI points to value
quit:
'언어 > 어셈블리' 카테고리의 다른 글
정수 연산 소개 (산술, 논리) SHL, SAL, ROL, RCL, SHLD (0) | 2024.06.13 |
---|---|
조건부 구조 표현식과 상태 전이 다이어그램 FSM (0) | 2024.05.30 |
스택을 이용한 프로시저 실행 과정 (0) | 2024.04.21 |
데이터 전송, 주소 지정과 산술 연산 (0) | 2024.04.21 |
어셈블리 언어 기초 (0) | 2024.04.18 |