Language/Assembly
Assembly 명령어 정리
slays
2016. 10. 18. 15:35
[그림. 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 |
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 이 된다. |