반응형
MASM(Microsoft Macro Assembler) : 저급 언어
어셈블리어의 장점
- 소량의 코드로 작성하는 경제적인 프로그램(임베디드 시스템 등)
- 실행 코드의 실행 속도를 정확히 측정 가능
- 소프트웨어 최적화 및 컴퓨터 구조의 이해 가능
문자 표현
- 따옴표로 둘러싸인 한 문(문자 상수) 또는 문자열(문자열 상수)
- 문자(열)을 2진 ASCII 코드로 메모리에 저장
- 일반적인 문자열은 Null Byte로 끝남("Gyeori World",0)
예약어 : 특별한 목적을 가지고 사전에 저장된 것
- 명령어 니모닉 : mov, add, mul 등
- 레지스터 이름
- 디렉티브(Directive) : 어셈블러에게 실행 방법을 지시
- 속성 : 변수와 피연산자의 크기와 사용 정보를 제공(Byte, Word ...)
- 연산자 : 수식에서 사용
- 미리 정의된 기호 : 어셈블할 때 상수 정수 값을 반환하는 @data와 같은 기호
식별자 : 프로그래머가 선택한 이름으로, 변수/상수/프로시저/코드 레이블 등에 사용됨
- 1~247개 사이의 문자를 사용할 수 있고 대소문자를 구분하지 않음
- 어셈블러의 예악어와 같을 수 없음
- 첫번째 문자는 알파벳(A~Z,a~z), 밑줄(_), @, ?, $이어야 하며(숫자 X), 이후에는 숫자를 사용 가능
- @는 어셈블러가 미리 정의된 기호의 접두사로 많이 사용되므로 피하는 것이 좋음
디렉티브 : 어셈블러가 인식하여 그에 따라 동작하는 소스 코드에 포함되는 명령어(지시 역할)
- 실행 시간에 실행되지 않음
- 변수, 매크로, 프로시저를 정의할 수 있음
- 메모리 세그먼트에 이름을 부여하고 어셈블러와 관련된 많은 기타 관리 작업을 수행
- .code ~ ; .data ~ ; .code ~; 형태로 병행하여 여러 번 사용 가능
- DATA 디렉티브(.data) : 변수를 포함하는 프로그램 영역을 표시함
- DATA?(.data?) : 비초기화 데이터를 선언(상황에 따라 컴파일된 프로그램의 크기를 줄여줌)
- CODE 디렉티브(.code) : 실행 가능한 명령어를 포함하는 영역을 표시함
- 분기나 루프 명령어의 목적지로 사용됨
- 명령어가 위치한 프로그램의 코드 영역에 있는 레이블은 콜론(:)으로 끝나야 함
- STACK 디렉티브(.stack) : 스택의 크기를 설정하면서(.stack 4096 등) 실행 스택을 가진 프로그램 영역을 표시함
- INCLUDE 디렉티브 : 필요한 정의와 설정 정보를 지시
- PROC 디렉티브(PROC ~ ENDP) : 시작 부분에 넣을 수 있는 정보, 프로시저가 수행하는 작업들에 대한 설명
- .386 : 최소 CPU(386)을 표시
- .model 메모리 모델을 명시(small, flat)하고 (매개 변수 전달에 사용되는 규약 지정
- stdcall : MS-window 함수 호출
- PROTO 프로시저에 대한 원형을 선언(ExitProcess PROTO / DumpRegs PROTO 등, 프로시저명 뒤에 삽입)
- INVOKE :프로서지 또는 함수를 호출
- COUNT : 등호 디렉티브(COUNT = 500), COUNT를 500이라는 값과 동일하게(대입)
- EQU : 기호를 정수 수식이나 임의의 텍스트와 연관시킴(상수를 정의)
- name EQU expression(수식, 문법에 맞는 표현)
- name EQU symbol(= 또는 EQU로 이미 정의된 기호)
- name EQU <...임의의 텍스트...>
- matrix EQU 100 과 같은 형태
- ALIGN : 다음 변수를 지정한 bound(1,2,4,16 중에 지정 가능)만큼 뒤에 주소에 저장(메모리 간의 간격 지정)
- LABEL : 저장 공간을 할당하지 않으면서 레이블을 넣고 크기 속성을 주는 기능을 함(모든 표준 크기 속성이 사용될 수 있음)
피연산자(Operand)
- 유형 : 상수, 상수 수식, 레지스터, 메모리 등
- 어셈블리 언어 명령어는 0에서 3개의 피연산자를 가질 수 있음
- 피연산자를 갖지 않는 명령어 : stc(set carry flag)
- 한 개의 피연산자를 갖는 명령 : inc eax(add 1 to eax)
- 두 개의 피연산자를 갖는 명령 : mov count, ebx(move ebx to count)
- 세 개의 피연산자를 갖는 명령 : imul eax, ebx, 5(ebx에 5를 곱하여 eax에 저장)
- 유형 : 즉시 값, 레지스터(CPU에 있는 명명된 레지스터를 사용), 메모리(메모리 위치)
피연산자 표기법
피연산자 | 설명 |
reg8 | 8비트 범용 레지스터 : AH, AL, BH, BL, CH, CL, DH, DL |
reg16 | 16비트 범용 레지스터 : AX, BX, CX, DX, SI, DI, SP, BP |
reg32 | 32비트 범용 레지스터 : EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP |
reg | 임의의 범용 레지스터 |
sreg | 16비트 세그먼트 레지스터 : CS, DS, SS, ES, FS, GS |
imm | 8, 16 또는 32비트 즉시 값(숫자 수식을 사용) |
imm8 | 8비트, 바이트 즉시 값 |
imm16 | 16비트, 워드 즉시 값 |
imm32 | 32비트, 더블 워드 즉시 값 |
주석 : 프로그램 작성자가 프로그램 소스 코드를 읽는 사람에게 프로그램 설계에 대한 정보를 제공
- 한 줄 주석 : 세미 콜론(;) 뒤의 글자를 주석으로 처리
- 블록 주석 : COMMENT 디렉티브와 사용자 정의 기호로 시작(예 : COMMENT ! ~ !)
주요 명령어
명령어 | 역할 | 활용 | 피연산자 | 비고 |
MOV | 피연산자의 이동(대입) | mov eax, 10000h | 2개 | 피연산자 크기가 같아야 함 모두 메모리 피연산자일 수 없음 CS, EIP, IP를 목적지로 지정 불가 즉시 값이 세그먼트 레지스터로 이동될 수 없음 |
ADD | 피연산자의 덧셈 | add eax, 40000h | 2개 | |
SUB | 피연산자의 뺄셈 | sub eax, 20000h | 2개 | |
CALL | 현재 값을 화면에 표시 | call DumpRegs | 1개 | |
EXIT | 프로그램 종료 | exit | 0개 | |
END | 어셈블된 프로그램의 마지막 줄 | END main | 1개 | |
DUP | 상수 수식 반복 카운터 (여러 개의 저장 공간을 확보) |
BYTE 4 DUP("STACK") | "STACKSTACKSTACKSTACKSTACK"(20 Bytes) | |
MOVZX | 소스를 목적지로 복사하고 값을 16/32비트로 제로 확장 |
movzx reg32, reg/mem8 movzx reg32, reg/mem16 movzx reg16, reg/mem8 |
2개 | 확장된 비트들은 0으로 채워짐 부호 없는 정수에서 사용 |
MOVSX | 소스를 목적지로 복사하고 값을 16/32비트로 부호 확장 |
movsx reg32, reg/mem8 movsx reg32, reg/mem16movsx reg16, reg/mem8 |
2개 | 확장 비트들은 부호 비트(0,1)로 채워짐 부호 있는 정수에서 사용 |
XCHG | 두 피연산자의 내용을 교환 | XCHG reg, reg XCHG reg, mem XCHG mem, reg |
2개 | 즉시 값을 사용 가능 메모리끼리는 사용 불가 (레지스터를 임시저장소로 사용하는 형태로 우회 활용) |
INC | 피연산자에 1을 더함 | INC reg/mem | 1개 | 플래그는 피연산자 값에 따라 변화 (캐리 플래그에는 영향을 주지 않음, 보조 캐리 플래그에는 영향) |
DEC | 피연산자에 1을 뺌 | DEC reg/mem | 1개 | |
NEG | 숫자를 2의 보수로 변환하고 부호를 바꿈 | NEG reg./mem |
1개 | |
OFFSET | 이 연산자를 포함하는 세그먼트의 시작부터 변수 간의 거리를 반환 | OFFSET Val | 1개 | OFFSET Val 자체가 하나의 값처럼 다른 연산자에 사용됨 -> mov esi, OFFSET Val |
PTR | 지정한 자료형만큼 뒤에서부터 식별하여 ax로 이동 | mov ax, WORD PTR myDouble | 1개 | 레지스터 출력에서는 WORD는 하위 4개 숫자(16진수이므로)를 반환함 변수에 1을 더할 수록 2자리 앞으로 이동하여 출력 |
TYPE | 단일 원소 크기를 바이트 단위로 반환 | mov eax, TYPE var 1 | 1개 | BYTE = 1 WORD = 2 DWORD = 4 QWORD = 8 |
LENGTHOF | 레이블과 같은 줄에 있는 값들로 정의되는 배열에 포함된 원소의 개수를 반환 | byte1 BYTE 10, 20, 30 => LENGTHOF array1 ; 3 |
베열 | DUP가 중첩된 경우 중첩된 값의 곱을 반환 30 DUP(?) => 30 5 DUP(3 DUP(?)) => 15(5*3) |
SIZEOF | LENGTHOF와 TYPE의 곱을 반환 | SIZEOF intArray | 배열 | |
PUSH | ESP를 감소시키고 피연산자를 스택에 복사 |
PUSH reg/mem16 PUSH reg.mem32 PUSH imm32 |
1개 | *ESP : 스택 최상단 값의 주소를 가짐 16비트 피연산자는 ESP를 2 감소 32비트 피연산자는 ESP를 4 감소 |
POP | ESP를 증가시키고 스택 원소를 목적지에 복사 |
POP reg/mem16 POP reg/mem32 |
1개 | 16비트 피연산자는 ESP를 2 증가 32비트 피연산자는 ESP를 4 증가 |
PUSHFD | 32비트 EFLAGS 레지스터를 스택에 PUSH | |||
POPFD | 스택을 32비트 EFLAGS 레지스터로 POP | |||
PUSHAD | 모든 32비트 범용 레지스터를 순서대로 스택에 PUSH | *순서 : EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI | ||
POPAD | PUSHAD 반대 순서로 스택에서 POP | |||
PUSHA | 16비트 범용 레지스터를 순서대로 스택에 저장 | *순서 : AX, CX, DX, BX, SP, BP, SI, DI | ||
POPA | PUSHA 반대 순서로 스택에서 POP | |||
CMP | 정수(문자 코드 포함)를 비교(뺄셈) | CMP destination, source | 목적지 피연산자 값에 따라 OF, SF, ZF, CF, 보조 캐리 플래그, PF를 변화시킴 | |
JZ/JNZ | ZF가 CMP 명령어에 의해 1(JNZ=0)로 설정되면 지정 레이블로 점프 | JZ L1 JNZ L1 |
조건부 점프J |
|
JC/JNC | CF가 1/0이면 점프 | |||
JO/JNO | OF가 1/0이면 점프 | |||
JS/JNS | SF가 1/0이면 점프 | |||
JP/JNP | PF가 1/0이면 점프 | |||
JE/JNE | 비교 결과가 같으면 비교 결과가 다르면 |
동등 비교 |
||
JCXZ | CX = 0이면 | |||
JECXZ | EXC = 0이면 | |||
부호 없는 비교 JA : Jump if Above = JNBE : Jump if Not Below or Equal (OP1 > OP2) JAE : Jump if Above or Equal = JNB : Jump if Not Below (OP1 >= OP2) JB : Jump if Below = JNAE : Jump if Not Above or Equal(OP1 < OP2) JBE : Jump if Below or Equal = JNA Jump if Not Above(OP1 <= OP2) |
||||
부호 있는 비교 JG : Jump if Greater = JNLE : Jump if Not less than or equal(OP1 > OP2) JGE : Jump if Greater than or Equal = JNL Jump if Not Less (OP1 >= OP2) JL : Jump if Less = JNGE : Jump if Not Greater than or Equal(OP1 < OP2) JLE : Jump if Less than or Equal = Jump if Not Greater(OP1 <= OP2) |
||||
조건부 루프 명령어 LOOPZ(Loop if Zero) : ZF = 1인 경우 루프 수행(조건을 가진 LOOP 명령어) LOOPE(Loop if Equal) LOOPNZ(Loop if Not Zero) : ECX(부호 없음) 값이 0보다 크고 ZF=0인 동안 루프 수행 LOOPNE(Loop if Not Equal) |
||||
부울 명령어 | ||||
연산 | 설명 | |||
AND | 소스 피연산자와 목적지 피연산자 간의 부울 AND 연산 연산의 성질을 이용하여 마스킹(특정 비트를 0으로 만들어줌) ASCII 대소문자의 변환에 활용(대문자와 소문자는 (뒤에서) 6번째 비트만 다름) |
|||
OR | 소스 피연산자와 목적지 피연산자 간의 부울 OR 연산 | |||
XOR | 소스 피연산자와 목적지 피연산자 간의 부울 XOR 연산 항상 OF / CF를 0으로 만듦 목적지 피연산자에 할당된 값에 의해 SF, ZF, PF,를 수정 |
|||
NOT | 목적지 피연산자에 대한 부울 NOT 연산 여집합 연산에 사용 |
|||
TEST | 소스 피연산자와 목적지 피연산자 간의 부울 AND 연산을 묵시적으로 수행하여 CPU 플래그를 적절하게 설정 | |||
BT, BTC, BTR, BTS | 소스 피연산자의 비트 n을 캐리 플래그로 복사하고 목적지 피연산자의 같은 비트를 보수화/리셋(0)/셋(1) 시킴 |
주요 프로시저
프로시저명 | 역할 | 활용 |
DumpRegs | 레지스터 내용을 출력 | call DumpRegs |
ExitProcess | 현재의 프로그램 종료 | |
Clrscr | 콘솔 원도우를 깨끗하게 지움 | |
Crlf | 콘솔 윈도우의 커서를 다음 줄의 처음으로 이동 | |
Delay | 지정된 msec 단위시간 동안 프로그램을 멈추게 함 | eax에 시간 간격을 지정 |
DumpMem | 일정 범위 위치의 메모리를 콘솔 윈도우에 16진수로 출력 | 메모리의 시작 주소를 ESI에 출력 단위의 크기를 EBX(바이트 단위) 출력 단위의 개수를 ECX에 전달 |
GetMseconds | EAX 레지스터에 자정 이후 경과시간을 msec 단위로 반환 | 입력 변수 X |
IsDigit | AL에 있는 값이 유효한 10진수 자릿수에 대한 ASCII 코드인지 | AL이 유효한 10진수 자릿수이면 ZF=1 / 그렇지 않으면 0 |
MsgBox | 그래픽 팝업 메시지 상자를 표시 | 나타낼 문자열을 EDX에 저장 제목을 EBX에 저장(선택 사항) |
MsgBoxAsk | Yes/No 버튼을 갖는 그래픽 팝업 메시지 상자 표시 | EAX에 사용자가 어떤 버튼을 선택했는지 저장 |
Parseinteger32 | 부호 있는 10진수 문자열(ASCII)을 32비트 이진수로 변환, 숫자가 아닌 문자 앞의 모둔 유효한 자리 숫자가 변환되며, 빈칸은 무시 |
EAX : 2진수 반환 ECX : 문자열 길이 EDX : 문자열 주소(OFFSET) |
Random32 | 32비트 난수 정수를 생성하고 EAX에 반환 | Seed를 사용 |
Randomize | Random32, RandomRange의 시드 값을 초기화 | 시드는 100분의 1초 단위 시간 값 |
RandomRange | 0 ~ n-1까지의 난수 정수 생성 | EAX 값을 n(범위 매개변수)로 사용하며, 난수 정수가 EAX에 반환 |
ReadChar | 키보드의 한 문자 입력을 읽고 AL에 반환 | 콘솔에 출력되지는 않음 |
ReadDec | 키보드에 32비트 부호 없는 10진수를 읽어서 EAX에 빈환 | 빈 칸은 무시 정수가 비어있으면 EAX = 0 / CF = 1 정수가 빈 칸 만 가지면 EAX = 0 / CF = 1 정수가 2^13-1보다 크면 EAX = 0 / CF = 1 이외의 경우 변환된 정수를 저장(EAX)하고 CF = 1 |
ReadHex | 키보드에서 32비트 16진수 정수를 읽어서 대응되는 2진수 값을 EAX에 반환 |
잘못된 문자에 대한 어떠한 오류 검사도 수행하지 않음 A~F까지 자리 숫자(10~15) 입력 시 대소문자 모두 사용 가능 최대 8자리까지 입력 가능하며 앞의 빈칸이나 추가 문자는 무시 |
ReadInt | 키보드에서 32비트 부호 있는 10진수를 읽어서 EAX에 반환 | 숫자가 아닌 문자를 만날때까지 모든 유효 자리로부터 계산(111AAA -> 111만 인식) |
ReadKey | 키보드 입력 버퍼를 조사(사용자의 입력 여부 식별) | AL이 0이면 특수키(기능키, 화살표), ASCII 코드인 경우 특정 값을 의미 키 입력이 발견되면 ZF = 0 |
ReadString | 키보드에서 문자열을 읽고 Enter키를 누를 때 멈춤 | EDX : OFFSET ECX : 사용자가 입력할 수 있는 최대 문자 수에 1을 더한 값으로 설정 (Null Byte에 대한 공간을 확보하기 위해) EAX : 사용자가 입력한 문자수 |
SetTextColort | 텍스트 출력에 대한 글자색과 배경색 설정 | 글자색 + (배경색 * 16) 색상표의 코드에 대응 |
SetLength | Null 종료 문자열의 길이를 반환 | EAX : 문자열 길이 EDX : OFFSET |
WaitMsg | "Press any key to continue..."를 표시하고 사용자의 입력을 대기 | |
WriteBin | 정수를 ASCII 2진수 형식으로 콘솔 윈도우에 출력 | EAX에 값 전달 2진수 비트는 4개씩 묶어서 표시 |
WriteBinB | 32비트 정수를 ASCII 2진수 형식으로 콘솔 윈도우에 출력 | EAX : 값 전달 EBX : 표시할 크기를 바이트 단위로 반환 |
WriteChar | 콘솔 윈도우에 하나의 문자를 출력 | 문자/문자의 ASCII 코드를 AL에 전달 |
WriteDec | 32비트 부호 없는 정수 앞에 0이 없는 10진수 형식으로 콘솔 윈도우에 출력 | EAX :정수 전달 |
WriteHex | 32비트 부호 없는 정수를 8자리 16진수 형식으로 콘솔 윈도우에 출력하며 필요한 경우 앞에 0들이 삽입 | EAX :정수 전달 |
WriteHexB | 32비트 부호 없는 정수를 16비트 형식으로 콘솔 윈도우에 출력하며 필요한 경우 앞에 0이 삽입 | EAX : 값 전달 EBX : 표시할 크기를 바이트 단위로 반환 |
WriteInt | 32비트 부호 있는 정수에 대해 부호는 포함하고 앞에 0이 없는 10진수 형식으로 콘솔 윈도우에 출력 | EAX :정수 전달 |
WriteString | 널(Null) 종료 문자열을 콘솔 윈도우에 출력 | EDX : OFFSET |
기본 출력
EAX = 00030000 | EBX = 7EPDE000 | ECX = 00000000 | EDX = 003A1005 |
EST = 00000000 | EDI = 00000000 | EBP = 0056FD30 | ESP = 0056FD30 |
EIP = 003A1024 | EFL = 00000206 | CF = 0 SF = 0 ZF = 0 OF = 0 AF = 0 PF = 1 | |
출력의 처음 두 행은 32bit 범용 레지스터의 16진수 값(00030000 = 00030000h) 셋째 행은 Flags와 EIP(Extended Instruction Pointer), EFL(Extended Flags) |
주요 고유 자료형
자료형 | 유형 | 크기 |
BYTE | 부호 없는 정수 | 8Bit |
SBYTE | 부호 있는 정수 | 8Bit |
WORD | 부호 없는 정수 | 16Bit |
SWORD | 부호 있는 정수 | 16Bit |
DWORD | 부호 없는 정수 | 32Bit |
SDWORD | 부호 있는 정수 | 32Bit |
FWORD | 정수 | 48Bit |
QWORD | 정수 | 4Bit |
TBYTE | 정수 | 80Bit(10Byte) |
REAL4 | IEEE 짧은 실수 | 32Bit(4Byte) |
REAL8 | IEEE 긴 실수 | 64Bit(8Byte) |
REAL10 | IEEE 확장 실수 | 80Bit(10Byte) |
구형 데이터 디렉티브 | ||
DB | 8Bit 정수 | |
DW | 16Bit 정수 | |
DD | 32Bit 정수 또는 실수 | |
DQ | 64Bit 정수 또는 실수 | |
DT | 80bit(10Byte) 정수 |
플래그 유형
플래그명 | 용도 | 의미 |
캐리 플래그(Carry Flag, CF) | 부호 없는 정수 연산의 오버플로우(제한 비트보다 더 큰 결과값) 표현 | 1인 경우 오버플로우 발생 |
패리티 플래그(Parity Flag, PF) | 목적지 피연산자의 최하위 바이트 값의 홀수/짝수 | 1 = 짝수 / 0 = 홀수 |
사인 플래그(Sign Flag, SF) | 연산 결과가 음수인지 식별 | 1= 음수 / 0 = 양수 |
오버플로우 플래그 (Overflow Flag, OF) |
부호 있는 산술 연산의 오버플로우 식별 | 1인 경우 오버플로우 발생 |
제로 플래그(Zero Flag, ZF) | 연산 결과가 0임을 나타냄 | 연산 결과가 0이면 1(결과와 반대) |
데이터 정의문
- 메모리에 변수를 위한 저장공간을 확보, 변수 이름의 입력은 선택적(필수 X)
- 예 : count DWORD 12345
- 초기값을 반드시 설정해야 함(값에 ?를 입력하면 값을 초기화하지 않고 그대로 사용)
- list BYTE 10, 20, 30, 40 등 배열 형태로 여러 개의 초기값 설정 가능(주소가 1Byte 단위로 증가)
정수의 제로/부호 확장
- 작은 피연산자에서 큰 피연산자로 데이터를 복사하기 위해 MOV 데이터를 사용할 수 없음(두 연산자의 크기가 다르기 때문에)
- 부호가 없는 경우 제로 확장을 사용하고 부호가 있는 경우 부호 확장을 사용함
직접 오프셋 피연산자
- 변수의 이름에 변위를(위치 간격)을 더하여 직접 오프셋 피연산자를 만들 수 있음
- 예 : mov al, [arrayB +1]
- 배열인 경우 위치를 기반으로 연산(+1 : 배열의 두 번째 값)
간접 주소 지정
- 32비트 범용 레지스터(EAX, EBX, ECX, EDX, ESI, EDI, ESP)의 특정 레지스터를 [eax]의 형태로 사용하여 해당 레지스터의 값을 표현
- 레지스터를 간접 피연산자로 사용하기 전에 항상 초기화해야 함
- 특정 레지스터에 배열을 입력한 뒤, inc reg 형태로 값을 증가시키고 [reg]를 호출하면 배열의 특정 위치에 순차적으로 접근 가능
- add 정수 형태로 위치를 건너뛰어 접근할 수도 있음
반응형