시스템/리버싱

어셈블리 산술 연산 명령어

enable7997 2025. 6. 22. 14:57
반응형

산술 연산 명령

ADD 명령어 (add)
ADD [피연산자1] [피연산자2]
[피연산자1]에 [피연산자2]를 더하고 그 값을 저장하라
ADD EAX, 1
EAX에 1을 더한 값을 저장

 

SUB 명령어 (substract)
SUB [피연산자1] [피연산자2]
[피연산자1]에 [피연산자2]를 빼고 그 값을 저장하라
SUB EAX, 1
EAX에 1을 뺀 값을 저장

 

CMP 명령어 (compare)
CMP [피연산자1] [피연산자2]
[피연산자1]과 [피연산자2] 비교하고 두 값이 같은지 비교한다. [피연산자1]에 [피연산자2]를 빼고 그 값이 0이면 참이다.
CMP EAX, 1
EAX와 1의 값이 같은지 비교한다. EAX-1이 0이라면 참이고 아니라면 거짓이다. 

 

ADC 명령어 (add with carry)
ADC [피연산자1] [피연산자2]
[피연산자1]에 [피연산자2]와 캐리를 포함하여 더하고 그 값을 저장하라
4비트 처리에 8비트를 처리하려면 상위 4비트와 하위 4비트로 나누어 저장하고 하위 4비트에서 연산하는데 이를 4비트가 저장할 수 있는 범위(2진수 1111, 10진수 15)를 넘어서면(자리올림) CF(캐리 플래그)가 1이 된다.
ADC 9, 8 ; 4비트 환경이라고 가정할때
9는 2진수(0000 1001), 8은 2진수(0000 1000)이다. 4비트 환경 컴퓨터는 상위 4비트와 하위 4비트로 나누어 계산한다.
하위 4비트부터 ADD 연산을 하게 되고 계산값은 1001 + 1000 = (1) 0001으로 자리올림(CF) 1이 발생한다.
이후 상위 4비트를 더하는데 이전에 계산한 CF값도 포함하여 계산하면 0000 + 0000 + 1(CF) = 0001이 계산된다.
이제 상위 4비트와 하위 4비트를 합치면 0001 0001 (10진수 17)로 계산이 되는 것을 확인할 수 있다. 

 

SBB 명령어 ( subtraction with borrow)
SBB [피연산자1] [피연산자2]
[피연산자1]에 [피연산자2]를 캐리를 포함하여 빼고 그 값을 저장하라
4비트 처리에 8비트를 처리하려면 상위 4비트와 하위 4비트로 나누어 저장하고 하위 4비트에서 연산하는데 이를 4비트가 저장할 수 있는 범위(2진수 1111, 10진수 15)를 넘어서면(자리내림) CF(캐리 플래그)가 1이 된다.
SBB 17, 9 ; 4비트 환경이라고 가정할때
17은 2진수(0001 0001), 9는 2진수(0000 1001)이다. 4비트 환경 컴퓨터는 상위 4비트와 하위 4비트로 나누어 계산한다.
하위 4비트를 계산하게 되면 0001 - 1001 = (1) 1000으로 1에서 9를 뺄 수 없으므로 자리내림(CF) 1이 발생하고 2의 보수 연산으로 1000이 계산된다.
이후 상위 4비트 계산하는데 이전에 계산한 CF를 포함하여 계산하면 0001 - 0000 - 1(CF) = 0000이 되는 것을 알 수 있다
이제 상위 4비트와 하위 4비트를 더하여 0000 1000 (10진수 8)로 계산되는 것을 알 수 있다.

 

DEC 명령어 (decrement)
DEC [피연산자1]
[피연산자1] 값을 하나 1 감소시킨다.
DEC EAX
EAX 값을 1 감소시킨다. EAX의 값이 4라면 DEC EAX의 값은 3이 된다. 

 

NEG 명령어 (change sign)
NEG [피연산자1]
[피연산자1]의 값을 2의 보수 계산을 한다 / 부호를 반전시킨다. 
NEG EAX
EAX의 값을 2의 보수 계산을 한다. 
예시로 EAX의 값이 5라면 5의 2진수는 0000 0101이다.
NEG EAX는 먼저 비트를 반전시키고 1111 1010,
다음에 1을 더하는 계산을 한다. 1111 1010 + 1 = 1111 1011 (10진수 -5) 계산값으로 컴퓨터가 인식하는 -5가 된다.

 

INC 명령어 (increment)
INC [피연산자1] 
[피연산자1]의 값을 1 증가시킨다.
INC EAX
EAX의 값을 1 증가시킨다.  EAX가 4라면 INC EAX의 값은 5가 된다.

 

PACK BSD, UNPACK BSD 차이
이진화 십진 코드(BCD)를 표현하는 두 가지 방식. 차이는 각 십진수를 표현하는데 필요한 비트 수
Packed BCD는 4비트(니블)를 사용하여 각 십진수를 표현하는 반면, unpacked BCD는 8비트(바이트)를 사용
특징 Packed BSD UnPacked BSD
비트 수  4비트(니블) 8비트(바이트)
표현 예시(87) 1000 0111 00001000 00000111
메모리 효율성 높음 낮음
구현 용이성 낮음 높음
사용 예시 데이터 저장 및 연산 입출력 

 

AAA 명령어 (ASCII adjust for add)
AAA 
비압축 BCD 덧셈값(unpacked BSD) 덧셈 결과의 AL 값을 UNPACK 10진수로 보정한다. 
덧셈 후 AL 레지스터의 값이 9를 초과하면, AL에는 십진수 단위(0~9)를 남기고 AH에 자리올림(1)을 더한다.
mov ah, 0       ; AH를 0으로 초기화
mov al, 5       ; AL에 비압축 BCD 값 5를 저장
add al, 8       ; AL에 8을 더함 (AL = 13, 즉 0Dh(줄끝문자))

aaa             ; 덧셈 결과 보정
; 결과: AX = 0x0103
; AH = 1 (자리올림), AL = 3 (단위) -> 즉, 십진수 13을 의미

 

AAS 명령어 (ASCII adjust for substract)
AAS
비압축 BCD 덧셈값(unpacked BSD) 뺄셈 결과의 AL 값을 UNPACK 10진수로 보정한다. 
비압축 BCD 뺄셈 후 결과를 보정한다. 뺄셈 시 자리내림이 발생하면 AL 값을 보정하고 AH에서 1을 뺀다.
mov ah, 0       ; AH를 0으로 초기화
mov al, 3       ; AL에 3을 저장
sub al, 5       ; AL에서 5를 뺌 (AL = -2, 즉 0xFE(2진수 111111111 11111110), CF=1)

aas             ; 뺄셈 결과 보정
; 결과: AX = 0xFF08
; AH = -1 (자리내림), AL = 8 -> 십진수 연산에서의 자리내림을 표현

 

DAA 명령어 (decimal adjust for add)
DAA 
압축 BCD(packed BCD) 덧셈 결과의 AL값을 PACK 10진수로 보정한다.
AL의 각 4비트(니블)가 9를 초과하거나 자리올림이 발생하면 6을 더해 십진수 형식에 보정한다.
mov al, 0x25    ; 압축 BCD 값 25를 AL에 저장
add al, 0x38    ; 38을 더함 (AL = 0x5D)

daa             ; 덧셈 결과 보정
; AL의 하위 니블(D)이 9보다 크므로, AL에 6을 더함: 0x5D + 0x06 = 0x63
; 결과: AL = 0x63 (십진수 63)

 

DAS 명령어 (decimal adjust for substract)
DAS
압축 BCD(packed BCD) 뺄셈 결과의 AL값을 PACK 10진수로 보정한다.
뺄셈 시 자리내림이 발생하면 AL에서 6을 빼서 십진수 형식에 맞춥니다.
mov al, 0x52    ; 압축 BCD 값 52를 AL에 저장
sub al, 0x29    ; 29를 뺌 (AL = 0x29, CF=0, AF=1) -> 하위 니블에서 자리내림 발생

das             ; 뺄셈 결과 보정
; 하위 니블에서 자리내림(AF=1)이 발생했으므로, AL에서 6을 뺌: 0x29 - 0x06 = 0x23
; 결과: AL = 0x23 (십진수 23)

 

MUL 명령어 (multiply(unsigned) )
MUL [피연산자1] [피연산자2] ...
부호 없는 정수의 곱셈을 수행한다.
mov ax, 100     ; 피연산자1 (AX)
mov bx, 200     ; 피연산자2 (BX)

mul bx          ; AX = AX * BX
; 결과: 32비트 결과가 DX:AX에 저장된다.
; 20000은 16진수로 0x4E20 이므로,
; DX = 0x0000, AX = 0x4E20이 된다.

 

IMUL 명령어 (integer multiply(signed) )
IMUL [피연산자1] [피연산자2] [피연산자3] ...
부호 있는 정수의 곱셈을 수행한다.
; 예시: -10 * 20 = -200
mov bx, -10     ; 피연산자1
mov cx, 20      ; 피연산자2

imul ax, bx, 20 ; AX = BX * 20
; 결과: AX = -200 (0xFF38)

; 다른 예시 (피연산자 1개)
mov al, -5
mov bl, 10
imul bl         ; AX = AL * BL = -50 (0xFFCE)

 

AAM 명령어 (ASCII adjust for multiply)
AAM 
두 비압축 BCD 값의 곱셈 후 AX에 저장된 이진수 결과를 두 개의 비압축 BCD 값으로 변환한다.
AX를 10으로 나눈 몫을 AH에, 나머지를 AL에 저장합니다.
; 예시 5 * 9 = 45
mov al, 5
mov bl, 9

mul bl          ; AL * BL -> AX에 저장 (AX = 45, 즉 0x002D)

aam             ; 곱셈 결과 보정
; AX를 10으로 나눔: 45 / 10 = 몫 4, 나머지 5
; 결과: AX = 0x0405
; AH = 4 (십의 자리), AL = 5 (일의 자리)

 

AAD 명령어 (ASCII adjust for divide)
AAD 
나눗셈 전에 두 자리 UNPACK BCD 값(AH, AL)을 하나의 이진수로 변환하여 AX에 저장한다.
AX = AH * 10 + AL 연산을 수행한다.
; 예시 십진수 72 나누기
mov ax, 0x0702  ; 두 자리 비압축 BCD 값 72 (AH=7, AL=2)

aad             ; 나눗셈 전 보정
; AX = AH * 10 + AL = 7 * 10 + 2 = 72 (0x0048)
; 결과: AX = 0x0048, AH = 0x00, AL = 0x48

mov bl, 9
div bl          ; 72 / 9 -> AL = 8 (몫), AH = 0 (나머지)

 

DIV 명령어 (divide(unsigned))
DIV [피연산자1]
부호 없는 정수의 나눗셈을 수행한다.
; 예시 32비트 나눗셈 100000 / 300
mov dx, 1       ; 100000은 65535보다 크므로 DX:AX 사용
mov ax, 0x86A0  ; DX:AX = 0x000186A0 = 100000
mov cx, 300     ; 나눌 수 

div cx          ; DX:AX / CX
; 결과:
; AX = 몫 (100000 / 300 = 333 -> 0x014D)
; DX = 나머지 (100000 % 300 = 100 -> 0x0064)

 

IDIV 명령어 (integer divide(signed))
IDIV [피연산자1]
부호 있는 정수의 나눗셈을 수행한다.
; 예시 -500 / 7
mov ax, -500    ; 나누어야 하는 수(-500은 0xFE0C)
cwd             ; AX의 부호를 DX로 확장 (DX = 0xFFFF)

mov bx, 7       ; ax를 나눌 수

idiv bx         ; DX:AX / BX
; 결과:
; AX = 몫 (-500 / 7 = -71 -> 0xFFB9)
; DX = 나머지 (-500 % 7 = -3 -> 0xFFFD)

 

CBW 명령어 (convert byte to word)
CBW
AL 레지스터의 8비트 부호 있는 값(바이트)을 AX 레지스터의 16비트 값(워드)으로 부호 확장한다. 
AL의 최상위 비트(부호 비트)를 AH의 모든 비트에 복사한다.
; 양수 확장
mov al, 100     ; AL = 100 (0x64), 부호 비트는 0
cbw             ; AL의 부호를 AH로 확장
; 결과: AX = 0x0064 (100)

; 음수 확장
mov al, -2      ; AL = -2 (0xFE), 부호 비트는 1
cbw             ; AL의 부호를 AH로 확장
; 결과: AX = 0xFFFE (-2)

 

CWD 명령어 (convert byte to double word)
CWD 
AX 레지스터의 16비트 부호 있는 값을 DX:AX의 32비트 값으로 부호 확장한다. 
AX의 최상위 비트(부호 비트)를 DX의 모든 비트에 복사한다. IDIV 전에 나누어야 할 값을 준비하는 데 필수적
; 양수 확장
mov ax, 5000    ; AX = 5000 (0x1388), 부호 비트는 0
cwd             ; AX의 부호를 DX로 확장
; 결과: DX = 0x0000, AX = 0x1388

; 음수 확장
mov ax, -5000   ; AX = -5000 (0xEC78), 부호 비트는 1
cwd             ; AX의 부호를 DX로 확장
; 결과: DX = 0xFFFF, AX = 0xEC78
반응형