본문 바로가기

Language/Assembly

Assembly 명령어 정리


[그림. 1] 어셈 명령어


디버거로 파일을 까보면 맞딱들이게 되는 어셈블리 명렁어들..
처음 보는 사람들은 당연히 "이게 도대체 뭔 소리래~" 라고 할 것이다.
나 역시도 그랬고, 지금도 햇갈리는 것 많고, 명령어만 안다고 되는 것도 아니고 인텔에서 제공되는 메뉴얼도 볼 줄 알아야 하는데, 하도 안 봐서 그건 까먹어버렸네 -_-;

옛날에 어셈블리 명령어를 이거 저거 찾아보며 정리하고 엑셀 파일로 갖고 있다가 여기에 그냥 한 번 올려본다.

다른 블로그의 글들을 참조해보고 실전에서도 해석에 도움도 되고 했었지만 사용하다 보면 잘못된 해석이거나 부족한 부분이 느껴져서 내가 나름대로 정리도 해본거라 올려본다.
뭐 나도 정리한 것에 오류가 있을 수 있으니 만약에 누군가가 보게 된다면 직접들 사용해보고 판단해야 할 것이다.


어셈블리 명령어

명령어 설명  명령어가 수행되기 위한
 플래그 레지스터와
 범용 레지스터의 상태 
PUSH 스택에 값을 넣는다.
ESP의 값이 4만큼 줄어들고 이 위치에 새로운 값이 채워진다.
 
PUSHFD EFL(EFLAG) 레지스터 값을 스택에 PUSH한다  
PUSHAD 모든 레지스터를 EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI 순서로스택에넣는다  
POP ESP 레지스터가 가리키고 있는 위치의 스택 공간에서 4byte 만큼을 Destination 피연산자에 복사하고 ESP 레지스터의 값에 4를 더한다.
POP reg16(Destination)
 
POPAD 스택에 존재하는 값을 EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP 레지스터로 POP한다.
PUSHAD 명령어로 스택에 보관해 놓은 레지스터 정보를 다시 이용할 때 사용한다.
POPAD
 
POPFD 스택에 존재하는 값을 EFL(EFLAG)레지스터로 POP한다.
PUSHFD 명령어로 스택에 보관해 놓은 레지스터 정보를 다시 이용할 때 사용한다.
POPFD
 
PUSHA, POPA PUSHAD, POPAD의 16비트 버젼  
INC 피연산자에 1을 더한다.
연산 결과에 따라 ZF(Zero Flag)나 OF(Overflow Flag)가 세트될 수 있다.
INC reg, INC mem
DEC 피연산자에 1을 뺀다.
연산 결과에 따라 ZF나 OF가 세트될 수 있다.
DEC reg, DEC mem
ADD Destination에 Source의 값을 더해서 Destination에 저장한다.
연산 결과에 따라 ZF, OF, CF(Carry Flag)가 세트될 수 있다.
ADD eax(Destination), 100(Source) : eax레지스터에 100을 더해서 eax레지스터에 저장
ADC Destination에 Source의 값과 Carry Flag 값을 더하여 Destination에 저장한다.
ADC eax(Destination), 100(Source) : eax레지스터에 100과 CF 값을 더하여 eax 레지스터에 저장
SUB Destination에 Source의 값을 빼서 Destination에 저장한다.
연산 결과에 따라 ZF, OF, CF가 세트될 수 있다.
SUB eax(Destination), 100(Source) : eax레지스터에 100을 빼서 eax레지스터에 저장
SBB Destination에 Source의 값과 CF 값을 빼서 Destination에 저장한다.
연산 결과에 따라 CF, AF, ZF, OF, CF가 세트될 수 있다.
SBB eax(Destination), 100(Source) : eax레지스터에 100과 CF 값을 빼서 eax레지스터에 저장
MUL 오퍼렌드를 eax와 곱한(MULTIPLY) 후, 그 값을 eax에 담는다.
만약 오퍼렌드가 EDX 레지스터의 값일 경우, 연산 후 EDX 값은 0으로 세트된다.
IMUL 부호 있는 al, ax, eax의 값을 피연산자와 곱한다. 연산결과에 따라 CF, OF가 세트될 수 있다.
IMUL r/m8 : 단일 피연산자이고 피연산자를 al, ax, eax에 곱한다.
IMUL r16(destination), r/m16(value) : value를 al, ax, eax와 곱해서 destination에 저장
IMUL r16(destination), r/m8(value), imm8(value) : value끼리 곱해서 destination에 저장
(연산 결과가 destination 레지스터의 크기보다 크다면 OF, CF가 세트된다.)
DIV 8, 16, 32비트 부호 없는 정수의 나눗셈을 수행한다. 연산결과에 따라 CF, OF, ZF가 세트될 수 있다.
DIV reg
MOV Source에서 Destination으로 데이터를 복사한다.
MOV reg(Destination), mem(Source)
MOVS Source에서 Destination으로 데이터를 복사한다.
MOVS Destination, Source
MOVSB SI 또는 ESI 레지스터에 의해 지정된 메모리 주소의 내용을 DI 또는 EDI 레지스터에 의해 지정되는 메모리 주소로 복사한다.
MOVSB는 BYTE 단위, MOVSW는 WORD 단위, MOVSD는 DWORD 단위로 복사한다. 방향 플래그(DF)가 1로 세트되어 있으면 ESI와 EDI는 복사 시에 감소하게 되고 DF가 0으로 세트되어 있으면 ESI와 EDI는 복사 시에 증가하게 된다.
MOVSB, MOVSW, MOVSD
MOVSW
MOVSE
MOVSX BYTE나 WORD크기의 피연산자를 WORD나 DWORD크기로 확장하고 부호는 그대로 유지.
MOVSX reg32, reg16
MOVZX BYTE나 WORD크기의 피연산자를 WORD나 DWORD크기로 확장하고 남은 비트는 0으로 채운다.
MOVZX reg32, reg16
INT 소프트웨어 인터럽트를 발생시켜 운영체제의 서브루틴을 호출한다.
INT imm
AND Destination과 Source 피연산자의 각 비트가 AND 연산된다.
AND 연산은 각 비트가 모두 1일 때만 결과 값이 1이 된다.
Destination : 10011100
Source      : 11001010
결과         : 10001000

AND reg(Destination), mem(Source) : reg와 mem을 AND 연산한 후 결과를 reg에 저장
AND 연산을 통해서 OF, CF가 0으로 세트되고 결과에 따라서 ZF가 1로 세트될 수 있다.
TEST 두 피연산자 사이에 논리적인 AND 연산을 수행하여 플래그 레지스터에 영향을 주지만 결과값은 저장하지 않는다. OF, CF는 항상 0으로 세트되고 TEST 연산 결과값이 0이면 ZF가 1로
세트, 0이 아니면 ZF가 0으로 세트된다.
TEST reg, reg
OR OR(Inclusive OR)
Destination과 Source 피연산자의 각 비트가 OR 연산된다.
OR 연산은 각 비트가 모두 0이면 결과는 0이고 모두 0이 아니면 결과는 1이 된다.
Destination : 10011100
Source      : 11001010
결과         : 11011110

OR reg(Destination), mem(Source) : reg와 mem을 OR 연산한 후 결과를 reg에 저장
OR 연산을 통해서 OF, CF가 0으로 세트되고 결과에 따라서 ZF가 1로 세트될 수 있다.]
XOR Destination과 Source 피연산자의 각 비트가 XOR 연산된다.
XOR 연산은 각 비트가 서로 다른 값일 때만 결과가 1이다. 같은 값이라면 결과는 0이 된다.
Destination : 10011100
Source      : 11001010
결과         : 01010110
XCHG
(Exchange)
두 피연산자의 내용이 서로 교환된다.
XCHG 명령은 imm 값이 피연산자로 올 수 없다.
XCHG reg, mem
XADD
(Exchange)
두 피연산자의 내용을 서로 교환 후, Destinaion 값에 Source 값을 더한다.
XADD Dest, Source
REP
(Repeat String)
ECX 레지스터를 카운터로 사용해서 문자열 관련 명령을 ECX>0인 동안 반복한다.
한번 진행될 때마다 ECX 레지스터값이 -1 된다.
REP MOVS destination, source
ECX > 0
REPE/REPZ REPNE/REPNZ
(REPeat while Equal/REPeat while Zero)
: while(!ZF)
: --> ZF = 1일 때 반복하고 ZF = 0일 때는 빠져나감. Flag 설정 명령어 CMPS, SCAS에 의해서 사용됨
      (단 ZF가 1인 상태여도 ECX 카운터가 0이 되면 빠져나온다.)
(미리 지정된 ZF와 상관은 없고, 명령 수행 시의 연산 결과에 해당되는 ZF 결과에만 반응한다.)
ECX > 0
ZF = 1
REPNE/REPNZ REPNE/REPNZ
(REPeat while Not Equal/REPeat while Not Zero)
: while(!ZF)
: --> ZF = 0일 때 반복하고 ZF = 1일 때는 빠져나감. Flag 설정 명령어 CMPS, SCAS에 의해서 사용됨
      (단 ZF가 0인 상태여도 ECX 카운터가 0이 되면 빠져나온다.)
(미리 지정된 ZF와 상관은 없고, 명령 수행 시의 연산 결과에 해당되는 ZF 결과에만 반응한다.)

ECX > 0
ZF = 0

RDTSC CPU의 64bit 레지스터인 TSC(Time Stamp Clock)에는 CPU가 매 순간 Clock Cycle 을 저장하는데, 그 값의 상위 32bit 값을 EDX에, 하위 32bit 값을 EAX 레지스터에 셋트시킨다.
LOOPD CX에 셋트된 카운트가 0이 될 때 까지 지정된 주소로 이동한다. (시간 소모용으로 쓰임)
Ex.) LOOPD short xxxxxxxx
CMD CF 레지스터의 값을 변경한다.
JA Jump if (unsigned) above  CF=0 and ZF=0
JAE Jump if (unsigned) above or equal   CF=0
JB Jump if (unsigned) below  CF=1
JBE Jump if (unsigned) below or equal  CF=1 or ZF=1
JC Jump if carry flag set  CF=1
JCXZ Jump if CX is 0  CX=0
JE Jump if equal  ZF=1
JECXZ Jump if ECX is 0  ECX=0
JG Jump if (signed) greater  ZF=0 and SF=0
JL Jump if (signed) less  SF!=OF
JGE Jump if (signed) greater or equal  SF=OF
JLE Jump if (signed) less or equal  ZF=1 and OF!=OF
JNA Jump if (unsigned) not above  CF=1 or ZF=1
JNAE Jump if (unsigned) not above or equal   CF=1
JNB Jump if (unsigned) not  below  CF=0
JNBE Jump if (unsigned) not below or equal   CF=0 and ZF=0
JNC Jump if carry flag not set  CF=0
JNE Jump if not equal  ZF=0
JNG Jump if (signed) not greater  ZF=1 or SF!=OF
JNGE Jump if (signed) not greater  or equal   SF!=OF
JNL Jump if (signed) not less  SF=OF
JNLE Jump if (signed) not less  or equal  ZF=0 and SF=OF
JNO Jump if overflow flag not set  OF=0
JNP Jump if parity flag not set   PF=0
JNS Jump if sign flag not set  SF=0
JNZ Jump if not zero  ZF=0
JO Jump if overflow flag is set  OF=1
JP Jump if parity flag set  PF=1
JPE Jump if parity is equal  PF=1
JPO Jump if parity is odd  PF=0
JS Jump if sign flag is set  SF=1
JZ Jump is zero  ZF=1
MUL 부호 없는 al, ax, eax의 값을 피연산자와 곱한다. 피연산자가 8비트이면 al과 곱해서 ax에 저장되고 16비트면 ax와 곱하고 dx(상위16비트):ax(하위16비트)에 저장된다. 연산 결과에 따라 OF, ZF 플래그가 세트될 수 있다.

MUL reg
BSWAP 피연산자의 리틀 엔디언 형식의 값을 빅 엔디언 형식처럼 스왑시켜버린다.
BSWAP eax : eax 값이 12345678 이라고 되어 있을 경우 해당 명령어는 78563412로 변경시킨다.
SHR/SAR Destination을 비트 연산하여, Source의 값 만큼 Right 방향으로 Shift 한다.
Eax가 0x10라고 가정할 때,
SHL eax(Destination), 2(Source) : eax값의 bit 값은 10000 이며, 2만큼 Right Shift 하면 "100"이 된다. 이것을 다시 Hex 로 계산하면 0x04이다.
SHL/SAL Destination을 비트 연산하여, Source의 값 만큼 Left 방향으로 Shift 한다.
Eax가 0x04라고 가정할 때,
SHL eax(Destination), 2(Source) : eax값의 bit 값은 100 이며, 2만큼 Left Shift 하면 "10000"이 된다. 이것을 다시 Hex 로 계산하면 0x10이다.
STC Cary Flag 를 1로 셋트시켜준다.
STD D Flag 를 1로 셋트시켜준다.
LODS ESI가 가리키는 주소의 데이터를 EAX로 로드한다.
이후, ESI는 다음 주소로 셋트된다.
STOS EAX의 value를 EDI가 가리키는 주소에 복사시키고 EDI는 1 증가한다.
SCAS EDI가 가리키는 곳의 데이터를 EAX와 비교 (Flag)
 *비교라는 게 아무래도 CMP 비교인 것으로 보임
SCASB (SCAn String Byte/Word/Dword)
EDI가 가리키는 곳의 데이터를 AL/AX/EAX와 비교 (Flag)
SCASW
SCASD
ROL/RCL 왼쪽으로 회전 Shift

ROL 12345678, 2 = 23456781
ROR/RCR 오른쪽으로 회전 Shift
NOT 연산 수행자로서 값을 1의 보수로 역전시킨다.
NOT 12h = FFFFFFED (모든 bit 기준으로 0은 1이 되고, 1은 0이 된다.) ,
4를 NOT 시키면 -5가 된다.
NEG 연산 수행자로서 값을 2의 보수로 역전시킨다.
NEG 12h = FFFFFFEE (첫 bit를 제외한 나머지 bit가 0은 1이 되고, 1은 0이 된다.)
4를 NEG 시키면 -4가 된다.
DIV IDIV operand (ex. IDIV ESI)
EAX 값을 EBX 나눈 , 몫은 EAX, 나머지는 EDX 셋팅된다.
다음 명령어 8비트 부호없는 나눗셈(83h /2)을 수행하여 몫 41h과 나머지 1의 결과를 만들어 낸다.
명렁이 수행되기 전, CBW, CWD, CDQ가 나옴. (부호보존을 위해)
mov ax, 0083h
mov bl, 2
div bl  ; AL = 41h, AH = 01h; (01h는 위에 CDQ 같은 명령으로 0값으로 초기화된 EDX에 들어간다)
IDIV IDIV operand (ex. IDIV ESI)
EAX의 값을 EBX로 나눈 후, 몫은 EAX로, 나머지는 EDX에 셋팅된다.
부호있는 나눗셈이다.
(signed DIVide)
: 수행 전, CBW, CWD, CDQ가 나옴. (부호보존을 위해)
CDQ EAX의 부호비트를 EDX레지스터까지 확장한다. (DWORD 를 QWORD 길이로 확장)
EAX가 10438A10 이라 하고 EDX 가 7C7DE2F1 이라 할 경우, CDQ 명령을 수행하면
EAX는 그대로 유지되고 EDX는 EAX에 확장을 당한 꼴이라서 결국 값이 00000000 이 된다.