기술문서 ‘09. 07. 15. 작성
작성자 : 한국항공대학교 IDT 배건규
목
차
☞
어셈블리
의 기초
1.
(MASM)
...3
데이터 전송 주소지정 연산
2.
,
...7
프로시저
3.
...13
조건부 처리
4.
...19
정수연산
5.
...28
고급프로시저
6.
...30
문자열과 배열
7.
...33
어셈블리를 이용한 블록 격파 게임 만들기
8.
...42
참고문헌
어셈블리 언어
의 기초
1.
(MASM)
어셈블리 언어의 기본적인 구성요소 1-1.
산술 연산 우선순위(Precedence) - 수식이 두 개 이상의 연산자를 포함시 연산의 순서 의미 ○
데이터 표현 ○
정수 상수 ⋅
[{+|-}] digits[radix]
h → hexadecimal(0A3h, 1Ah) b → binary(11010011b) q/o → Octal(42q, 42o)
실수 상수 ⋅
[sign]integer.[integer][exponent] -44.2E+05
문자 상수 ⋅
진 아스키 코드로 변환해서 사용 'A' or "d" → 2
문자열 상수 ⋅
"This isn't a test"
예약어(Reserved word) ○
인텔 프로세서에 의해 실행되는 명령어 니모닉(MOV, ADD, etc) ⋅
수식에 사용되는 연산자들 ⋅
같이 변수나 피연산자의 크기나 사용처를 알려주는 속성들 BYTE or WORD
⋅
에게 어떻게 프로그램을 어셈블해야 하는지를 알려주는 디렉티브 MASM
⋅
식별자(Identifier) ○
프로그래머가 선택한 이름 ⋅
사이의 문자가 가능 1~247
⋅
은 소문자 대문자를 구별하지 않는다
MASM , .
⋅
첫 번째 문자는 하나의 문자(A..Z, a..z)이거나 (_), @, $이어야 한다. ⋅
예약어를 사용해서는 안 된다. ⋅
연산자 이름 우선순위
( ) 괄호 1
+, - 단항 플러스 마이너스, 2
*, / 곱셈 나눗셈, 3
MOD 나눔자 3
디렉티브(directive) ○
프로그램의 소스 코드를 어셈블할 때 어셈블러가 인식하고 활용하는 명령어 ⋅
논리 세그먼트를 정의하거나 메모리 모델을 선택하거나 프로시저 만들거나 변수정의시 사용 ⋅
디렉티브는 어셈블러 구문으로서 인텔 명령어 집합과는 관계가 없다. ⋅
데이터 영역 프로시저의 시작
.data → , name PROC →
명령어(Instruction) ○
프로그램이 메모리에 탑재되어 실행될 때 프로세서에 의해 실행되는 문장 ⋅
명령어 데이터의 위치를 표시하는 하나의 식별자 Label - or
⋅ target:
mov ax, bx
명령어에 의하여 수행되는 동작을 식별하기 위한 단어 Mnemonic
-⋅
mov, add, sub...
명령어는 개까지 를 갖는데 이는 레지스터 메모리 피연산자 상수 Operand - 0~3 Operand , , , , ⋅
입출력 포트가 될 수 있다
or .
inc ax, mov count, bx
프로그램을 작성한 사람이 프로그램의 소스코드에 대한 설명 Comment
-⋅
COMMENT &
This line is a comment. &
프로그램의 어셈블링 링킹 그리고 실행
1-2. , ,
어셈블 링크 실행 주기- -○
Step1 ⋅
프로그래머는 문자 편집기를 사용하여 소스파일이라고 하는 아스키 문자 파일 생성 →
Step2 ⋅
어셈블러는 소스 파일을 읽어서 기계어 변환인 오브젝트 파일을 생성 오류시, 1단계로 이동 →
Step3 ⋅
링커는 오브젝트 파일을 읽고 링크 라이브러리 안에 있는 프로시저를 호출하는지 점검 후, →
Step4 ⋅
운영체제의 로더는 실행 파일을 메모리로 읽어 들이고 중앙처리장치를 프로그램의 시작 →
주소로 분기하게 하여 그 프로그램을 실행한다.
데이터 정의 1-3.
고유의 데이터 타입 ○
데이터 할당 ○
초기 설정 ⋅
에 문자 대입 value1 BYTE 'A' → value1 A
다중 초기 설정 ⋅
오프셋으로 구별 은 타입 수 만큼 증가 list BYTE 10, 'A', 30, 22h → (offset ) 문자열 설정
⋅
로 문자열의 끝을 구분 greeting1 BYTE "Good afternoon", 0 → NULL(0)
연산자를 이용한 설정 DUP
⋅
문자열이나 배열을 위한 공간 할당 시 유용
메모리 할당 후 으로 초기화 BYTE 20 DUP(0) → 20BYTE , 0
리틀 엔디언- (little endian) 순서 ○
아키텍쳐는 리틀 엔디언 방식을 따른다
Intel CPU .
⋅
변수의 가장 낮은 유효 바이트가 가장 낮은 주소에 저장되고 나머지는 다음의 연속적인 ⋅
메모리 위치에 저장.
일 경우 DWORD 12345678h
⋅
만약 메모리 오프셋 0에 위치해 있다면 78h가 첫 번째 바이트에 저장 →
타입
용도
BYTE 8비트 부호가 없는 정수 SBYTE 8비트 부호가 있는 정수
WORD 16비트 부호가 없는 정수 실세 주소 모드에서( Near 포인터로 사용될 수 있음) SWORD 16비트 부호가 있는 정수
DWORD 32비트 부호가 없는 정수 보호 모드에서( Near포인터로 사용될 수 있음) SDWORD 32비트 부호가 있는 정수
FWORD 48비트 정수 보호 모드에서( Far 포인터) QWORD 64비트 정수
TBYTE 80비트 (10바이트 정수)
심벌 상수 1-4.
심벌이 필요한 이유? ○
심벌을 사용함으로써 프로그램을 읽고 유지하기가 쉬움 ⋅
COUNT = 500 MOV ax, COUNT 프로그램 수정시 용이함. ⋅
가 번 쓰였을 경우 값 수정시 값만 바꿔주면 된다
COUNT 1000 COUNT .
심벌을 이용한 배열과 문자열의 크기 계산 ○
현재 위치 카운터 는 현재 오프셋 위치를 리턴함 이를 이용
$( ) . .
⋅
List BYTE 10, 20, 30, 40 ListSize = ($ - list)
디렉티브 EQU
○
심벌 이름을 정수 수식이나 임의의 문자와 연결 ⋅
PressKey EQU <"Press any key to continue...", 0> .data
prompt BYTE preekey
실습 1-5.
를 이용하여 문장의 글자 수를 계산하고 레지스터의 변화되는 값을 알아본다
LengthOf , .
○
소스코드 ⋅
TITLE LengthOf (hello.asm) ;program 제목과 파일명
INCLUDE \masm615\include\Irvine32.inc
어셈블러 파일을 텍스트파일에 복사한다
; Irvine32.inc .
.data ;date 세그먼트 시작
strlen BYTE "hello world" ;strlen 변수를 byte형으로 선언후 hello world로 초기화 시켜준다.
.code ;code 세그먼트 시작
main PROC ;main 프로시저 시작
mov eax,LENGTHOF strlen ;strlen의 문자열길이를 eax레지스터에 저장한다.
main ENDP ;main 프로시저의 끝
결과화면 ⋅
문자열의 길이가 이기 때문에 레지스터에 진수값인 로 저장이 된다
* 11 eax 16 B .
2
.
데이터 전송 주소지정 연산
,
,
데이터 전송 명령2-1.
피연산자(Operand) 타입 ○
즉시값(Immediate), 레지스터(Register), 메모리(Memory)의 3개지 타입으로 구성. ⋅
직접 메모리 피연산자 ○
레지스터에 값을 이동 mov al, var1 → al var1
⋅
을 역참조하여 메모리의 내용을 가져와 레지스터에 이동 mov al, [00010400] → offset al
⋅
위치에서 를 더한곳의 값을 레지스터에 이동 mov al, [val1+5] → var1 offest 5 al
⋅
명령 MOV ○
소스 피연산자로부터 도착점 피연산자로 데이터를 이동 ⋅
MOV destination, source 피연산자 규칙 MOV
⋅
두 피연산자는 같은 크기여야 한다.
두 피연산자가 모두 메모리 피연산자일 수 없다. 는 도착점 피연산자가 될 수 없다
CS, EIP, IP .
피연산자 설명
r8 8비트 범용 레지스터 : AH, AL, BH, BL, CH, CL, DH, DL r16 16비트 범용 레지스터 : AX, BX, CX, DX, SI, DI, SP, BP
r32 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비트 더블워드 즉시값
즉시값은 세그먼트 레지스터로 이동될 수 없다. 명령
MOVZX ○
소스 피연산자를 도착점 피연산자로 복사하고 그 값을 16비트나 32비트로 확장한다. ⋅
확장된 부분은 0으로 채운다 단 부호가 없는 정수에만 사용된다. , . ⋅
MOV bx, 0A69Bh
MOV eax, bx ;EAX = 0000A69Bh
명령 MOVSX ○
와 같으며 확장된 부분을 로 채운다
MOVSX , 1 .
⋅
MOV bx, 0A69Bh
MOVSX eax, bx ;EAX = FFFFA69Bh
명령 XCHG ○
두 피연산자의 내용을 맞교환 한다. ⋅
xchg ax, bx
직접 오프셋 피연산자 ○
변수 이름에 변위를 더해 명시적으로 레이블링 되지 않은 메모리 위치를 엑세스 가능 ⋅
arrayB BYTE 10h, 20h, 30h, 40h, 50h mov al, [arrayB+1] ;AL = 20h
덧셈과 뺄셈 2-2.
명령 INC, DEC ○
증가 감소 명령은 단일 피연산자에 을 더하거나 을 빼준다
INC( ), DEC( ) 1 1 .
⋅
연산시 많이 쓰임 Loop Count . ⋅
myWord WORD 1000h inc myWord ;1001h dec myWord ;1000h
소스 피연산자를 동일 크기의 도착점 피연산자에 더한다. ⋅
ADD dest, source
소스는 연산에 의하여 변하지 않고 합이 도착점 피연산자에 저장된다. ⋅
명령 SUB ○
도착점 피연산자에서 소스 피연산자를 뺀다. ⋅
.data
var1 DWORD 3000h var2 DWORD 1000h .code
mov eax, var1
sub eax, var2 ;2000h
명령 NEG ○
수를 2의 보수를 취하는 것으로 그 수의 부호를 바꾼다. ⋅
NEG mem
연산의 플래그 영향 2-3.
어셈블리 언어에서는 각 연산 후에 상태 플래그를 점검하여 오버플로 오류를 제어할 수 있다. ○
제로(ZF)와 부호(SF) 플래그 ○
제로 flag는 계산 명령어의 도착점 피연산자가 0의 값을 가질 때 지정. ⋅
부호 플래그는 어떤값이 음수가 될 때 지정. ⋅
mov cx, 0
sub cx, 1 ;CX=-1, SF=1 add cx, 2 ;CX=1, SF=0
캐리(CF) 플래그 ○
가 부호 없는 연산을 수행할시 중요함
CPU .
⋅
부호 없는 덧셈의 결과가 매우 크거나 작을시 캐리 플래그가 지정된다. ⋅
최상위 비트(MSB)에서 발생한 캐리는 자동으로 캐리 플래그에 저장된다. ⋅
mov al, 0FFh
add al, 1 ;CF=1, AL=00
오버플로(OF) 플래그 ○
부호있는 연산에만 관계있음. ⋅
산술연산이 도착점 피연산자에 저장할 수 없는 부호 있는 수를 만들었을 경우에 지정 ⋅
⋅각 데이터 타입마다 가장 큰 숫자를 넘을 경우 1로 set된다 바이트의 경우( +127이상인 경우) mov al, +127
데이터 관련 연산자 및 디렉티브 2-4.
연산자 OFFSET
○
데이터 레이블의 오프셋을 리턴한다. ⋅
오프셋은 데이터 세그먼트의 시작으로부터 레이블까지의 거리를 바이트로 표현한다. ⋅
mov esi, OFFSET myArray+4
연산자 PTR
○
변수가 선언될때의 크기와는 다른 크기로 변수를 액세스 하고자 할 때 사용 ⋅
예를들어 더블워드 변수, myDouble의 하위 16비트만을 AX로 이동 ⋅
myDouble DWORD 12345678h mov ax, WORD PTR myDouble
연산자 LENGTHOF
○
레이블과 같은 줄에 나타나는 값에 의하여 정의된 배열의 요소 개수를 카운트함. ⋅
값은 array4 DWORD 1, 2, 3, 4 ; 4
연산자 SIZEOF
○
와 을 곱한 값을 리턴 LENGTHOF TYPE
⋅
intArray WORD 32 DUP (0) ;sizeof=64(32*2)
디렉티브 LABEL
○
레이블을 삽입할 수 있게 하며 그 레이블에 저장공간 할당 없이 크기 속성을 줄 수 있다. ⋅
데이터 세그먼트 내에 있는 기존의 변수에 다른 이름과 크기 속성을 주는 것이다. ⋅
간접 주소 지정 2-5.
간접 피연산자 ○
⋅배열을 처리하기 위한 실질적인 방법은 레지스터를 포인터로 사용하고 레지스터의 값을 다루는 것이고 이것을 간접 주소지정이라하며 주소를 지니는 레지스터는 간접 피연산자라 한다, . 대괄호로 둘러싸인 32비트 범용 레지스터(EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI)임 ⋅
.data
val1 BYTE 10h .code
는 의 오프셋을 포함한다 mov esi, OFFSET val1 ;esi val1 .
mov al, [esi] ;source에 간접 피연산자 사용지 ESI에 있는 포인터는 역참조 되고 바이트가 AL로 이동
배열 ○
간접 피연산자는 간접 피연산자의 값이 쉽게 수정될 수 있기 때문에 배열에 다룰 때 유용 ⋅
.data
arrayB BYTE 10h, 20h, 30h .code
mov esi, OFFSET arrayB
mov al, [esi] ;AL = 10h inc esi
mov al, [esi] ;AL = 20h
인덱스화된 피연산자 ○
유효주소를 만들기 위해 레지스터에 상수를 더한다. ⋅
임의의 32비트 범용 레지스터가 인덱스화된 피연산자로 쓰일 수 있다. ⋅
를 의미 arrayB[esi] → [arrayB + esi]
포인터 ○
다른 변수의 주소를 가지고 있는 변수를 말하며 배열과 데이터 구조체를 다룰때 많이 쓰임, . ⋅
계열 어셈블리는 와 두 종류의 포인터를 사용 Intel NEAR FAR
⋅
arrayB BYTE 10h, 20h, 30h, 40h
는 의 주소값을 지니고 있다 ptrB DWROD arrayB ;ptrB arrayB .
와 명령
2-6. JMP LOOP 이동 종류
○
무조건 이동(unconditional transfer) ⋅
프로그램은 모든 경우에 분기하며 새로운 주소에서 계속적인 실행이 일어나게 새로운 값이, 명령어 포인터로 탑재된다.
조건 이동(conditional transfer) ⋅
프로그램은 어떤 조건이 참이 될 때 이동하며 Intel 아키텍쳐는 조건 논리 구조를 만들기 위해 결합되는 광범위한 조건 이동 명령어를 제공한다.
는 와 플래그 레지스터의 내용을 근거로 참 거짓 조건을 해석함
CPU ECX / .
명령 JMP ○
코드 세그먼트 내 목표 위치로 무조건 이동한다. ⋅
위치는 어셈블러에 의하여 주소를 변환되는 코드 레이블에 의하여 식별되어야 함 ⋅
현재 프로시저 안에 있는 레이블로만 점프 가능 ⋅
16Bit Mode 32Bit Mode
포인터
NEAR 데이터 세그먼트의 시작부터
비트 오프셋 16
데이터 세그먼트의 시작부터 비트 오프셋
32
포인터
는 무조건이며 조건이 없을시 무한 반복 실행
JMP ,
⋅ top:
jmp top ;repeat the endless loop
명령 LOOP ○
문장의 블록을 특정 횟수 반복하는 쉬운 방법을 제공 ⋅
주로 ECX는 카운터로 많이 사용되며 루프가 반복될 때 매번 감소한다. ⋅
명령어는 단계로서 첫 번째는 에서 을 빼는 것이고 두 번째는 을 비교하는 것
LOOP 2 ECX 1 , 0
⋅
가 이 아니면 으로 식별되는 레이블로 점프하며 이면 점프가 일어나지
ECX 0 destination 0
⋅
않고 제어는 로프의 다음 명령어로 넘어간다, . L1:
inc ax loop L1
실습 2-7.
구구단중 2단부터 5단까지의 결과를 화면에 출력하라. ○
소스코드 ⋅
.data ;data 세그먼트 시작
valA DWORD 1 ;DWORD형 변수를 2개 선언후 1로 초기화
valB DWORD 1
.code ;code 세그먼트 시작
main PROC
mov ecx,4 ;루프카운터에 4를 대입한다.
L1: ;루프카운터에 의해 L1은 4번 반복한다.
push ecx ;ecx레지스터의 값을 Stack에 넣음으로서 다른 반복문을
다시 반복문으로 돌아올 수 있게 해준다
; L1 .
inc valA ;valA값을 1증가
mov valB, 1 ;valB에 1을 대입한다.
mov ecx,9 ;ecx루프카운터에 9를 대입한다.
L2: ;루프카운터에 의해 L2가 9번 반복된다.
mov eax,valA ;valA값을 eax레지스터에 대입한다.
call WriteDec ;eax레지스터 값을 출력한다.
mov al,'*' ;al레지스터에 값을 옮긴다* .
call WriteChar ;al레지스터값을 출력한다.
mov eax,valB ;valB값을 eax레지스터에 대입한다.
mov al,'=' ;al레지스터에 =를 대입한다.
call WriteChar ;=를 출력한다.
mov eax,valA ;valA값을 eax레지스터에 저장한다.
mul valB ;eax레지스터에 있는것과 valB값을 곱해준다.
call WriteDec ;eax레지스터에 있는값을 출력
call Crlf ;new line실행
inc valB ;valB값 1증가
loop L2 ;L2반복문의 끝
pop ecx ;기존 루프값을 꺼낸다.
call Crlf ;new line실행
loop L1 ;L1반복문의 끝
출력화면 ⋅
프로시저
3.
외부 라이브러리 링크 3-1.
링크 라이브러리는 기계어 코드로 어셈블된 프로시저를 갖고 있는 파일이다. ⋅
라이브러리에서 코드는 프로시저 상수 변수를 포함하는 하나이상의 소스파일로 시작한다, , . ⋅
소스 파일들은 오브젝트 파일로 어셈블되고 그 오브젝트 파일은 라이브러리에 삽입된다. ⋅
링커 명령어로 오브젝트 파일과 기타 링크 라이브러리를 합친다. ⋅
제공 링크 라이브러리 3-2. MASM
링크 라이브러리에 있는 프로시저 Irvine32
○
콘솔을 지우고 커서를 위의 왼쪽에 위치시키라
Clrscr .
Crlf 표준 출력에 줄의 끝임을 출력하라.
Delay 특정한 n밀리초 동안 프로그램 실행을 멈추라. 메모리 블록을 표준 출력에 진수로 쓰라
DumpMem 16 .
레지스터를 DumpRegs EAX, EBX, ECX, EDX, ESI, EBP, ESP, EFLAGS, EIP 16
진수로 표시하라 또한 캐리 부호 제로 오버플로 플래그를 표시하라. , , , . GetCommandtail 프로그램의 명령어 인수를 바이트의 배열로 복사하라.
시 이후로 경과된 시간을 미리초로 리턴하라
GetMseconds 0 .
콘솔 상에 커서를 특정한 행과 열에 위치하게 하라 Gotoxy
부터 까지 비트 무작위 정수를 발생시키라 Random32 0 FFFFFFFFh 32 . Randomize 유일한 값을 사용하여 무작위 수 발생기를 시드하라. RandomRange 특정한 범위 안에 있는 무작위 정수를 발생시키라. ReadChar 표준 입력으로부터 문자 하나를 읽으라.
ReadHex Enter키에 의하여 종료되는 32비트 16진 정수를 표준 입력으로부터 읽으라. 키에 의하여 종료되는 비트 부호있는 진수를 표준입력으로부터
ReadInt Enter 32 10
읽으라.
ReadString Enter키에 의하여 종료되는 문자열을 표준 입력으로부터 읽으라. SetTextColor 콘솔에 출력되는 모든 문자의 전경색과 배경색을 지정하라. WaitMsg 메시지를 출력하고 Enter키가 눌러질 때까지 기다리라.
WriteBin 부호가 없는 32비트 정수를 표준 출력에 아스키 2진 포맷으로 쓰라. 하나의 문자를 표준 출력에 쓰라
WriteChar .
부호가 없는 비트 정수를 표준 출력에 진 포맷으로 쓰라
WriteDex 32 10 .
부호가 없는 비트 정수를 표준 출력에 진 포맷으로 쓰라
WriteHex 32 16 .
부호가 있는 비트 정수를 표준 출력에 진 포맷으로 쓰라
WriteInt 32 10 .
널 문자로 끝나는 문자열을 표준 출력에 쓰라
WriteString .
스택 동작 3-3.
데이터 구조 Stack
○
스택은 LIFO(last-in, first-out)구조로서 새로운 값이 스택의 맨 위에 추가되고 기존의 값은, ⋅
맨 위에서부터 빠져 나온다는 원리
실행 시의 스택 ○
실행시의 스택은 두 개의 레지스터 SS와 ESP를 사용하여 CPU가 직접 관리하는 메모리 배열 ⋅
레지스터는 세그먼트 서술자를 갖으며 이것은 사용자 프로그램이 수정할 수 없다
SS , .
⋅
스택 포인터 레지스터(ESP)는 마지막으로 푸시된 정수를 가리킨다. ⋅
푸시(push)동작 ○
⋅푸시동작은 스택 포인터를 4감소시키며(32비트인 경우 새로운 값을 스택 포인터가) 가리키는 저장위치에 복사
팝(Pop)동작 ○
팝 동작은 스택으로부터 값을 제거하고 그 값을 레지스터나 변수에 놓는다. ⋅
스택으로부터 팝된 후 스택 포인터는 스택의 그 다음 높은 저장위치를 가리킴 ⋅
의 사용 Stack
○
레지스터가 하나 이상의 목적으로 사용될 때 레지스터를 저장하는 임시적인 영역으로 ⋅
편리하게 사용된다 레지스터가 수정된 후에 원래의 값으로 복원될 수 있음. 명령이 실행되었을 때 는 현재 프로시저의 리턴 주소를 스택에 저장
CALL CPU
⋅
프로시저를 호출할 때 인수(argument)를 전달 이것들이 스택에 푸시될 수 있다. . ⋅
프로시저 안의 지역 변수들은 스택 위에 생성되며 프로시저가 끝나면 사라진다. ⋅
프로시저의 정의 및 사용 3-4.
프로시저의 정의 ○
언어의 함수 개념이랑 비슷 high-level
⋅
비공식적으로 프로시저는 리턴 문으로 끝나는 문장들의 블록으로 정의 ⋅
과 디렉티브를 사용하여 선언 PROC ENDP
⋅
시작 프로시저가 아닌 다른 프로시저를 만들 때 RET문으로 끝내라. ⋅
를 프로시저를 호출한 위치로 리턴하게 함
(cpu .)
sample PROC .
. ret
sample ENDP
과 명령 CALL RET ○
명령은 프로세서가 새로운 메모리 위치에서 시작하게끔 조정하여 프로시저를 호출한다
CALL .
⋅
프로시저는 프로시저를 호출한 위치로 프로세서를 돌아오게 하기 위하여 RET명령을 사용 ⋅
기계적으로 볼 경우 CALL명령은 리턴 주소를 스택에 놓고 호출되는 프로시저의 주소를 ⋅
명령어 포인터에 놓는다.
그 프로시저가 리턴될 준비가 되면 RET명령은 스택에서 리턴 주소를 명령어 포인터로 팝함 ⋅
는 항상 명령어 포인터 레지스터인 가 가리키는 메모리 위치의 명령어를 실행함
cpu EIP .
⋅
main PROC
call Mysub ;00000020 mov eax, ebx ;00000025
Mysub PROC
mov eax, edx ;00000040 .
.
Mysub ENDP
의 첫 번째 실행 명령어가 오프셋 에 있다고 하면 명령이 실행
Mysub 00000040 , CALL
되었을 때 호출문의 다음주소(00000025)는 스택에 푸시되고 Mysub주소가 EIP로 탑재. 에 있는 모든 명령은 를 만날 때까지 실행되며 명령이 실행되면 스택에서
Mysub RET RET
가 가리키는 값이 로 팝된다
ESP EIP .
→
실습 3-5.
구현 Greatest Common Divisor ○
두 정수의 최대공약수(GCD)를 구하는 함수를 Recursive Ver.으로 작성 ⋅
입력받은 두 정수를 나머지 나눗셈(%)을 하여 나온 값이 0보다 클 동안 반복 ⋅
를 연산하는 부분은 반드시 로 작성 GCD User Proc
⋅
소스코드 ⋅
;_________________________________________________________data .data
inputMsg1 BYTE "Enter the First number : ",0 inputMsg2 BYTE "Enter the Second number : ",0 resultMsg BYTE " GCD : ",0
valL DWORD ? ; 첫 번째 입력값 || 큰 변수 valS DWORD ? ; 두 번째 입력값 || 작은 변수
GCD DWORD 1 ; GCD 값이 저장될 변수
;---code .code
insert PROC
mov edx,OFFSET inputMsg1 ; 첫 번째 숫자 입력 call WriteString
call ReadInt
mov valL,eax ; 변수 valL에 첫 번째 입력값 저장
mov edx,OFFSET inputMsg2 ; 두 번째 숫자 입력 call WriteString
call ReadInt
mov valS,eax ; 변수 valS에 두 번째 입력값 저장
ret
insert ENDP
;---gcd proc
gcdMul PROC
mov eax,valL
cmp eax,valS ; valL 와 valS 대소 비교 jae DiL
mov eax,valL
xchg eax,valS ; valS가 valL보다 크므로 스위치
mov valL,eax
DiL:
mov edx,0 ; 나눗셈전 edx 0으로 초기화 mov eax,valL
je R1
mov ebx,valL
sub ebx,valS ; 큰수에서 작은 수를 뺌
cmp valS,ebx ; 작은수와 큰수와 작은 수의 차를 비 교
mov eax,valS mov valL,eax
mov valS,ebx
mov eax,valL cmp eax,valS jae DiL
mov eax,valL
xchg eax,valS ; 변수 대소 비교 후 체인지 mov valL,eax
call gcdMul ; 재귀 함수 구현
R1:
mov edx,OFFSET resultMsg call WriteString
mov eax,GCD ; 나눠지는 수가 없을 시 소수 초기( ) 값 1출력
mul valS
call WriteDec ; 결과 값 출력 call Crlf
ret gcdMul ENDP
;---main PROC main PROC
call insert call gcdMul exit
main ENDP
결과 화면 ⋅
조건부 처리
4.
부울 및 비교 명령 4-1.
부울 명령 ○
명령 AND ○
두 개의 피연산자에서 매칭되는 비트 사이에 부울 AND연산을 하고 그 결과를 도착점 ⋅
피연산자에 놓는다. AND destination, source
명령은 종종 선택된 비트를 해제하고 나머지를 유지할 때 사용된다
AND .
⋅
명령은 항상 오퍼플로 플래그 와 캐리 플래그 를 해제한다
AND (OF) (CF) .
⋅
명령 OR ○
두개의 피연산자에서 매칭되는 비트사이에 부울 OR 연산을 하고 그 결과를 도착점 ⋅
피연산자에 놓는다. OR destination, source
명령은 종종 선택된 비트를 지정하고 다른 것을 유지할 때 사용한다
OR .
⋅
명령은 항상 캐리와 오버플로 플래그를 해제한다
OR .
⋅
연산 설명
AND 소스 피연산자와 도착점 피연산자 사이의 부울 AND 연산
OR 소스 피연산자와 도착점 피연산자 사이의 부울 OR 연산
XOR 소스 피연산자와 도착점 피연산자 사이의 부울 XOR연산
NOT 도착점 피연산자에 부울 NOT 연산
TEST 소스 피연산자와 도착점 피연산자 사이의 묵시적 부울 AND연산을 수행하여 중앙처리장치의 플래그를 적절히 지정
BT, BTC, BTR, BTE
명령 XOR ○
두 개의 피연산자에서 매칭되는 비트 사이에 부울 배타적 OR연산을 하고 그 결과를 ⋅
피연산자에 놓는다. XOR destination, source
명령은 와 와 같은 피연산자 조합을 사용한다
XOR AND OR .
⋅
의 특별한 점은 동일한 피연산자를 두 번 적용하면 그 자체가 된다
XOR .
⋅
명령은 항상 캐리와 오버플로 플래그를 해제한다
XOR .
⋅
명령 NOT ○
피연산자의 모든 비트를 바꾸고 그 결과는, 1의 보수(one's complement)라 한다. ⋅
어떤 플래그도 영향을 받지 않는다. ⋅
mov al, 11110000b
not al ;AL=00001111b
명령 TEST ○
두 피연산자 사이에 매칭되는 비트에 대하여 묵시적 AND연산을 수행하고 결과에 따라서 ⋅
플래그를 지정한다.
와 차이점은 도착점 피연산자를 수정하지 않는다
AND .
⋅
명령은 항상 오버플로 플래그와 캐리 플래그를 해제한다
TEST .
⋅
부호 제로 패리티 플래그는, , AND명령에서와 동일하게 수정된다. ⋅
명령 CMP ○
도착점 피연산자로부터 소스 피연산자를 묵시적으로 빼며 어떤 피연산자도 수정되지 않는다, . ⋅
CMP destination, source
명령은 오버플로 부호 제로 캐리 보조캐리 패리티 플래그를 명령이 사용되었다고
CMP , , , , , SUB
⋅
했을 때의 도착점 피연산자 값에 따라서 변화시킨다.
조건부 점프 4-2.
조건부 실행 순서 ○
등의 연산으로 중앙처리장치 플래그를 수정한다
CMP, AND, SUB .
⋅
조건부 점프 명령어가 플래그를 테스트하여 새로운 주소로 분기한다. ⋅
CMP leftOp, rightOp
CMP Results ZF CF Flags
destination < source 0 1 SF OF≠
destination > source 0 0 SF=OF
cmp al, 0
jz L1 ;jump if ZF=1 .
L1:
특정한 플래그 값에 근거한 점프 ○
등호에 근거한 점프 ○
부호가 없는 비교 ○
니모닉 설명 플래그
JZ Jump if zero ZF=1
JNZ Jump if not zero ZF=0
JC Jump if carry CF=1
JNC Jump if not carry CF=0
JO Jump if overflow OF=1
JNO Jump if not overflow OF=0
JS Jump if signed SF=1
JNS Jump if not signed SF=0 JP Jump if parity(even) PF=1 JNP Jump if not parity(odd) PF=0
니모닉 설명
JE jump if equal(leftOp=rightOp) JNE jump if not equal(leftOp rightOp)≠ JCXZ jump if CX=0
JECXZ jump if ECX=0
니모닉 설명
JA jump if above(if leftOp>rightOp)
JNBE jump if not below or equal(same as JA)
JAE jump if above or equal(if leftOp>=rightOp)
JNB jump if not below(same as JAE)
JB jump if below(if leftOp<rightOp)
JNAE jump if not above or equal(same as JB)
JBE jump if below or equal(if leftOp<=rightOp)
부호가 있는 비교 ○
조건부 루프 명령 4-3.
명령 LOOPZ(loop if not zero) ○
제로 플래그가 지정되어 있고 부호없는 값 ECX가 0보다 큰 경우 루프를 계속 실행시킴 ⋅
LOOPZ destination
명령 LOOPE(loop if not equal) ○
와 동일한 명령이며 배열에서 첫 번째 숫자를 비교한 후 루프를 반복한다
LOOPZ .
⋅
ECX=ECX-1
if ECX>0 and ZF=0, jump to destination
조건부 구조 4-4.
블록 구조의 IF문 ○
대부분의 고급 언어에서, IF문은 부울 수식이며 그 수식이 참이었을 때 수행되는 것과 ⋅
거짓이었을 때 수행되는 두 개의 문이 따라 나온다. 기본 IF (Java/c++)문
⋅
if(op1 == op2) {
x=1, y=2; }
기본 IF (문 어셈블리) ⋅
mov eax, op1
cmp eax, op2 ;compare EAX to op2 je L1 ;jump if equal to L1 jmp L2 ;otherwise, jump to L2 L1:
mov x,1 mov y,2 L2:
니모닉 설명
JG jump if greater(if leftOp>rightOp)
JNLE jump if not less than or equal(same as JG)
JGE jump if greater than or equal(if leftOp>=rightOp)
JNL jump if not less(same as JGE)
JL jump if less(if leftOp<rightOp)
JNGE jump if not greater than or equal(same as JL)
JLE jump if less than or equal(if leftOp<=rightOp)
논리 AND연산자(Java/c++) ⋅
if(a1>b1) AND (b1>c1) { x=1; }
논리 AND연산자 어셈블리( ) ⋅
cmp a1, b1 ;first expression ja L1
jmp next L1:
cmp b1, c1 ;second expression ja L2
jmp next
L2: ;both are true mov x,1 ;set x to 1 next:
논리 OR연산자(Java/c++) ⋅
if(a1>b1) OR (b1>c1) x=1;
논리 OR연산자 어셈블리( ) ⋅
cmp a1, b1 ;1: compare AL to BL
ja L1 ;if true, skip second expression cmp b1, c1 ;2: compare BL to CL
jbe next ;false: skip next statement L1:mov x,1 ;true: set x=1
next:
루프 WHILE ○
루프
WHILE (Java/c++) ⋅
while(val1 < val2) {
val1++, val2--; }
루프 어셈블리 WHILE ( ) ⋅
mov eax, val1 ;copy variable to eax while:
cmp eax, val2 ;if not(val1<val2) jnl endwhile ;exit the loop inc eax ;val1++; dec val2 ;val2--;
jmp while ;repeat the loop endwhile:
SWITCH CASE ○
어셈블리 Switch case( ) ⋅
.data
CaseTable BYTE 'A' ;lookup value
DWORD Process_A ;address of procedure BYTE 'B'
DWORD Process_B (etc.)
실습 4-5.
에 대해서 프로그램을 코딩하고 를 이용해서 과정을 상세히 이해하고
n! , Debugger Stack ,
○
개 이상의 를 인자값으로 받는 함수가 호출될 때 어떻게 스택에 저장되는지 5 argument
디버거를 통해 알아보시오.
소스코드 ⋅
TITLE Calculating a Factorial (Fact.asm)
; This program uses recursion to calculate the ; factorial of an integer.
; Last update: 09/05/13
INCLUDE \masm615\include\Irvine32.inc
함수를 선언해준다 와 는 짝이다 Factorial PROTO, ; .(invoke proto .)
a1:DWORD, ;인자값을 개 받는다5 . b1:DWORD,
c1:DWORD, d1:DWORD, e1:DWORD
.data
num1 DWORD 12 num2 DWORD 1 num3 DWORD 2 num4 DWORD 3 num5 DWORD 4
.code main PROC
를 레지스터에 저장한다 mov eax, num1 ;12 eax .
INVOKE Factorial, ;Factorial함수를 호출하면서 인자값으로 개를 넘긴다5 . num1,
num2, num3, num4, num5
함수호출이 모두 끝날 경우 이곳으로 리턴되 실행된다
ReturnMain: ; .
call WriteDec ;eax레지스터의 값을 출력한다. call Crlf
exit main ENDP
프로시저 Factorial PROC, ;Factorial
a1:DWORD, ;인자값으로 넘겨받은 값을 DWORD형으로 b1:DWORD, ;차례대로 a1~a5변수에 대입한다. c1:DWORD,
d1:DWORD, e1:DWORD
위치를 레지스터에 저장 mov ebp,esp ;stack point ebp
mov eax,[ebp+8] ;현재 가리키는 주소값에서 을 더하면 그위치의 값을8 에 저장한다
;eax .
값에 을 더하게 되면 주소값과 값을 지나 ;EBP 8 return ebp
처음에 한 값이 저장된다 ; push 12 . cmp eax,0 ;0과 값을 비교한다.
ja L1 ;eax레지스터의 값이 클 경우 L1으로 jump
mov eax,1 ;같을 경우 eax레지스터에 을 대입하고1 L2로 jump jmp L2
값을 감소시킨다 L1: dec eax ;eax 1 .
INVOKE Factorial, ;Factorial함수를 호출한다 재귀 호출.( ) 번째 인자값으로 레지스터값을 넘겨준다
eax, ;1 eax .
; Instructions from this point on execute when each ; recursive call returns.
재귀 함수가 리턴됬을 경우 실행된다
ReturnFact: ; .
mov ebx,[ebp+8] ; get n mul ebx ;ax = ax * bx
L2: ret 4 ;stack을 clear해준다. Factorial ENDP
END main
결과 화면 ⋅
결과 화면 <12! >
디버깅 과정 ⋅
디버거를 이용할시 어셈블러에 의해 생성된 실행파일을 Visual c++아이콘에 드래그 해주면 디버 거를 할 수 있다. F10을 누르게 되면 어셈블리 코드를 볼 수 있으며 좀 더 자세히 접근할시,
를 이용할 수 있다 BreakPoint .
를 이용한 디버거 화면 이용 <Visual C++ > <Visual C++ 2008 >
을 순차적으로 누르게 되면 다음 줄 어셈블리 코드가 실행이 된다 이때 값이 변하는 레지스
F10 .
포인터이다 따라서. ESP레지스터에 들어있는 주소값을 Memory에 입력하게 되면 거기에 해당되 는 값을 볼 수가 있다.
메모리를 참조할 경우 Memory의 주소값은 16진수로 되있기떄문에 주소값을 입력할 경우 앞에 를 붙여 준다 빨간색 동그라미는 이며 노란색 화살표는 이번에 실행될 코드이다
0x . ( BreakPoint .)
앞에 본 화면에서 번 더 실행 < 2 >
의 의 주소를 참고하면 값이 있고 칸뒤에 이 또 칸뒤에 가 저장 Memory Ox0012FFC 02 4 03 , 4 04
돼있다.
이 말은 num5, num3까지가 push돼있다 따라서 함수호출시 인자값을 넘길 경우 오른쪽에 있는. 값부터 push된다는 것을 알 수 있다.
또한, num의 변수는 DWORD로 선언되어 있기 때문에, 4Byte의 Memory를 차지하게 된다 따. 라서 1개블럭(00)당 1Byte이기 때문에 총 4블럭을 차지하게 된다 따라서 인텔 프로세서는 리틀. 엔디언 방식이기 때문에 변수의 가장 낮은 유효바이트가 가장 낮은 주소에 저장됨 - (Little endian)
을 Memory창에서 확인할 수 있다.
정수연산
5.
시프트와 회전 명령 5-1.
시프트 ○
시프트란 피연산자 안에서 비트를 좌우로 이동하는 것을 의미 ⋅
이동시 오버플로와 캐리 플래그에 영향을 줌 ⋅
좌시프트
SHL SHR 우시프트 SAL 산술 좌시프트 산술 우시프트
SAR ROL 좌회전 ROR 우회전
캐리 포함 좌회전
RCL RCR 캐리 포함 우회전 SHLD 더블 좌시프트 더블 우시프트
SHRD
논리 시프트와 산술 시프트 ○
논리 시프트(logical shift)는 새로운 비트 위치를 0으로 채운다. ⋅
산술 시프트(Arithmetic shift)는 새로 만들어지는 비트 위치는 원래 수의 부호 비트 값으로 ⋅
채운다.
좌시프트 명령 SHL( ) ○
도착점 피연산자의 최하위 비트를 0으로 채우는 논리 좌시프트 동작을 수행 ⋅
가장 상위 비트는 캐리 플래그로 옮겨 가고 캐리 플래그에 있는 비트는 손실된다, . ⋅
우시프트 명령 SHR( ) ○
도착점 피연산자에 대해 논리 우시프트 연산을 수행하여 최상위 비트를, 0으로 치환한다. ⋅
최하위 비트는 캐리 플래그로 복사되고 캐리 플래그에 있던 비트는 손실된다, . ⋅
좌회전 명령 ROL( ) ○
각 비트를 왼쪽으로 시프트 하며 최상위 비트가 캐리 플래그와 최하위 비트로 복사 된다, . ⋅
회전을 함으로써 비트 손실이 없다. ⋅
을 이용해서 한 바이트의 상위 비트 비트 와 하위 비트 비트 을 교환 가능
ROL , 4 ( 4~7) 4 ( 0~3)
⋅
우회전 명령 ROR( ) ○
각 비트를 오른쪽으로 시프트한다. ⋅
최하위 비트를 캐리 플래그와 최상위 비트에 동시에 복사한다. ⋅
명령 포맷은 SHL과 동일 ⋅
곱셈과 나눗셈 명령 5-2.
명령 MUL ○
에 비트 피연산자를 곱하는 명령어 이다 AL, AX, EAX 8, 16, 32 . ⋅
표는 승수의 크기에 따른 디폴트 피연산자와 곱셈결과를 보여준다. ⋅
곱셈결과를 저장하는 레지스터는 피승수와 승수 크기의 2배이어서 오버플로가 생기지, ⋅
않도록 해야한다.
곱셈결과의 상위 절반이 0이 아니면 캐리와 오버플로 플래그가 영향을 받는다. ⋅
mov al, 5h mov b1, 10h
mul b1 ;CF=0
명령 IMUL ○
부호 있는 곱셈 명령은 부호 있는 정수 곱셈을 수행한다
IMUL( ) .
⋅
명령과 동일한 구문과 피연산자를 가지며 차이점은 곱셈의 부호를 유지한다
MUL , .
⋅
은 곱셈 결과의 상위 부분이 하위 부분의 부호 확장이 아니면 캐리 플래그와 오버플로 IMUL
⋅
플래그를 설정한다.
mov ax, 48 mov bx, 4
피승수 승수 곱셈결과
AL r/m8 AX
AX r/m16 DX:AX
imul bx ; DX:AX=000000C0h, OF=0
명령 DIV ○
부호 없는 나눗셈 명령은 부호 없는 정수에 대해 비트 나눗셈을 수행함
DIV( ) 8, 16, 32 .
⋅
단일 피연산자만 나태내며 그 피연산자는 제수가 된다, . ⋅
mov ax, 0083h ;dividend mov bl, 2 ;divisor
div bl ;AL=41h, AH=01h
나눗셈 오버플로 ○
나눗셈에서 너무 큰 몫이 만들어져서 도착점 피연산자에 모두 들어갈 수 없으면 나눗셈, ⋅
오버플로(divide overflow)조건이 발생한다.
이는 CPU인터럽트를 발생시키고 현재 프로그램을 중단시킨다, . ⋅
mov ax, 1000h
mov bl, 10h
div bl ;AL cannot hold 100h
⋅위 소스 실행 결과 생긴 몫(100h)이 AL레지스터에 저장될 수 없으므로 나눗셈 오버플로 발생
고급프로시저
6.
지역변수
6-1. (local variable) 지역 변수란?
○
단일 프로시저 안에서 생성 사용 소멸되는 변수이다, , . ⋅
지역 변수에 대한 제한된 엑세스는 디버깅할 때 도움을 준다 단지 몇몇 제한된 프로그램.( ⋅
문장들만이 변수를 수정할 수 있기 때문.)
지역 변수들은 메모리를 효과적으로 사용한다 지역 변수들의 저장 공간은 해제될 수 있고.( , ⋅
새로운 변수들이 그 저장공간을 사용할 수 있기 때문.)
같은 변수 이름은 이름 충돌을 일으키지 않은 한 두 개 또는 그이상의 프로시저들에서, ⋅
나타낼 수 있다.
지역 변수들은 실행 시 스택에서 생성한다. ⋅
디렉티브 LOCAL
○
디렉티브는 하나의 프로시저 내부에서 하나 또는 그 이상의 지역 변수들을 선언한다
LOCAL .
⋅
디렉티브 바로 다음 행에 위치해야 한다
PROC .
⋅
지역 변수 사용시 어셈블러에 의해 코드 생성, ⋅
피제수 제수 몫 나머지
AX r/m8 AL AH
DX:AX r/m16 AX DX
BubbleSort PROC
LOCAL temp : DWORD, SwapFlag : BYTE ret
의 코드는 BubbleSort ENDP
BubbleSort: push ebp mov ebp, esp
add esp, 0FFFFFFF8h mov esp, ebp
구조 pop ebp <stack >
으로 생성된다
ret .
지역 변수로 어떤 크기의 배열을 생성하려고 하면 반드시 프로그램을 어셈블하기 전에, ⋅
충분한 스택 공간을 따로 할당(allocate)해야 한다.
스택 매개변수 6-2.
와 의 차이 argument parameter
○
인수(argument)는 호출하는 프로그램에 의해 프로시저로 전달되는 값이다. ⋅
매개변수(parameter)는 호출된 프로시저가 받는 값을 말한다. ⋅
디렉티브 INVOKE
○
디렉티브는 다중 인수를 전달할 수 있게 하는 의 명령에 대한 보다 더
INVOKE Intel CALL
⋅
강력한 대안이다.
INVOKE procedureName [,argumenList]
는 프로시저로 전달되는 인수들이 콤마로 분리된 일람이다
argumenList .
⋅
는 인수들의 일람을 포함하지 않는다
CALL .
⋅
는 임의 개수의 인수를 허용하며 각 인수들은 여러 소스 코드 행에 걸쳐
INVOKE ,
⋅
나타날 수 있다.
와 함께 사용하는 인수의 유형 INVOKE
⋅
연산자는 디렉티브를 가지고 프로시저를 호출할 때 포인터를 전달하기 위해
ADDR INVOKE ,
⋅
사용된다 프로시저 인수로 주소를 전달하는 것을 참조에 의한 전달. (passing by reference)
유형 예
즉시값 10, 3000h, OFFSET myList, TYPE array
정수 수식 (10*20), COUNT
변수명 myList, array, myWord, myDword
주소 수식 [myList+2], [ebx+esi]
레지스터 명 eax, bl, edi
라한다.
INVOKE FillArray, ADDR myArray
아래 코드는 Swap프로시저를 호출하면서 더블워드 배열에 있는 처음 두 원소릐 주소를, ⋅
전달하는 방법이다. .data
Array DWORD 20 DUP(?) .code
...
INVOKE Swap, ADDR Array ADDR Array+4
디렉티브 PROC
○
디렉티브는 매개변수 알람과 프로시저 이름을 선언한다
PROC .
⋅
label PROC, parameter_1, parameter_n
디렉티브 PROTO
○
디렉티브는 존재하는 프로시저의 프로토타입 을 만든다
PROTO (prototype) .
⋅
프로토타입은 프로시저의 이름과 매개변수 일람을 선언한다. ⋅
프로토타입은 프로시저를 정의하기 전에 호출할 수 있게 해준다. ⋅
은 문장에 의해 호출되는 각 프로시저에 대해 프로토타입을 요구한다
MASM INVOKE .
⋅
주의할 사항은 PROTO는 반드시 INVOKE 이전에 나타나야 한다. ⋅
프로시저 순서 ⋅
PROTO mySub ;procedure prototype INVOKE mySub ;procedure call
mySub PROC ;procedure implementation .
. mySub ENDP
단 프로시저 구현은, INVOKE문장 이전에 나올 수 있다 이 경우. , PRO는 프로토타입 역할임 ⋅
값에 의한 전달(passing by value) ○
변수 값의 복사본이 프로시저로 절달될 때 이것을 값에 의한 전달이라 한다, . ⋅
일반적으로 호출된 프로시저에 의해 값이 변하지 않도록 인수들을 값에 의해 전달 한다, . ⋅
변수의 복사본은 호출하는 프로그램에 의해 스택에 푸시되며 호출된 프로시저는 스택, ⋅
으로부터 값을 가져와서 그 값을 이용한다.
프로시저가 매개 변수를 변경하더라도 호출하는 프로그램에 있는 대응 되는 인수 값에, ⋅
액세스할 수 없다. .data
.code main PROC
INVOKE Sub1, myData exit
main ENDP
Sub1 PROC someDate:WORD mov someData, 0
ret Sub1 ENDP
참조에 의한 전달(passing by reference) ○
변수의 주소가 프로시저로 전달될 때 이것을 참조에 의한 전달 이라한다, . ⋅
호출된 프로시저는 주어진 주소를 통해 변수의 내용을 변경할 수 있다. ⋅
프로시저가 변수를 변경할 것으로 예상되는 경우에만 쓰는 것이 좋다, . ⋅
.data
myData WORD 1000h .code
main PROC
INVOKE Sub2, ADDR myData ;pass by reference exit
main ENDP
Sub2 PROC dataPTr:PTR WORD
mov esi, dataPtr ;get the address
mov WORD PTR[esi], 0 ;dereference, assign zero Sub2 ENDP
문자열과 배열
7.
문자열 프리미티브 명령 7-1.
문자열 프리미티브 ○
바이트 워드 더블워드의 배열 처리를 위한, , Intel 명령 집합에는 5개의 그룹이 있으며 이를, ⋅
문자열 프미리티브라고 하지만 문자 배열로만 국한되진 않는다, .
문자열 명령어는 메모리를 참조하기 위해 ESI, EDI 레지스터를 참조한다. ⋅
는 유일하게 단일 메모리 피연산자를 사용하여 문자열과 배열의 처리에 특히 유용
ESI, EDI ,
⋅
보호모드 에서는 ESI는 자동적으로 DS가 가리키는 세그먼트에서의 오프셋이 되고, EDI는 ⋅
자동적으로 ES가 가리키는 세그먼트 내의 오프셋이 된다. 는 항상 같은 값으로 설정되고 이를 변경할 수 없다
DS, ES , .
문자열 프리미티브 명령 ⋅
MOVSB, MOVSW, MOVSD ○
세 명령은 ESI가 가리키는 메모리 위치에서 EDI가 가리키는 메모리 위치로 데이터를 복사함 ⋅
두 개의 레지스터들은 자동적으로 방향 플래그값에 의해 증가 or 감소한다. ⋅
바이트들의 이동 복사 감소 MOVSB - ( ), ESI/EDI 1 ⋅
워드들의 이동 복사 감소 MOVSW - ( ), ESI/EDI 2
더블워드들의 이동 복사 감소 MOVSD - ( ), ESI/EDI 4
CMPSB, CMPSW, CMPSD ○
세 명령은 각각 ESI가 가리키는 메모리 피연산자와 EDI가 가리키는 메모리 피연산자를 비교 ⋅
방향 플래그에 의해 ESI, EDI값이 증가 또는 감소한다. ⋅ 바이트 비교 CMPSB -⋅ 워드 비교 CMPSW -더블워드 비교 CMPSD
-STOSB, STOSW, STOSD ○
세 명령은 각각 AL/AX/EAX의 내용을 EDI가 가리키는 오프셋 위치의 메모리에 저장함. ⋅
는 방향 플래그에 의해 증가 감소 된다
EDI or .
⋅
LODSB, LODSW, LODSD ○
세 명령은 ESI가 가리키는 메모리에서 바이트나 워드를 읽어 AL/AX/EAX에 저장 ⋅
는 방향 플래그에 의해 증가 감소 된다
ESI or .
⋅
선택된 문자열 프로시저 실습
7-2. ( )
Str_concat ○
문자열의 끝에 문자열을 연결하는 프로시저를 작성하라 target source Str_concat . 이 프로시저가 호출되기 전에 target문자열 내에 충분한 공간이 필요하다. source와
문자열에 대한 포인터를 전달하라
target .
명령어 설명
MOVSB, MOVSW, MOVSD
CMPSB, CMPSW, CMPSD
SCASB, SCASW, SCASD
STOSB, STOSW, STOSD
LODSB, LODSW, LODSD
문자열 데이터 이동 : 한 메모리 위치로부터 다른 곳으로 정수를 복사
문자열 비교 : 두 개의 메모리 값들을 비교
문자열 검색 : 정수와 메모리의 내용 비교
문자열 데이터 저장 : 메모리에 정수 저장
소스코드 ⋅
TITLE Str_concat
INCLUDE \masm615\include\Irvine32.inc
Str_concat PROTO, ;str_concat 프로시저 PROTO선언 ta : PTR BYTE,
so : PTR BYTE
.data
target BYTE "ABCDE",10 DUP(0) ;source의 문자열을 target문자열에 붙인다. source BYTE "FGH",0
.code
;================================================main main PROC ;main함수 시작
mov edx,OFFSET target ;target문자열 출력 call WriteString
call crlf
mov edx,OFFSET source ;source문자열 출력 call WriteString
call crlf
INVOKE Str_concat, ADDR target, ADDR source
을 호출하면서 두 문자열의 주소값을 넘긴다
;Str_concat .
mov edx,OFFSET target ;target문자열 출력 call WriteString
call crlf
exit
main ENDP ;main함수 끝.
;==============================================str Proc
Str_concat PROC, ;파라미터로 2개의 문자열의 주소값을 받는다. ta : PTR BYTE,
so : PTR BYTE
.data
strlenso DWORD ?
.code
mov esi, ta ;ta, so의 시작주소값을 esi, edx에 각각 대입한다. mov edx, so
mov ebx, [esi] ;esi가 가리키는 곳의 값을 ebx레지스터에 대입한다.
mov eax, 0 ;eax를 0으로 초기화시킨다 여기서. eax문자열의 길이를 계산 L2:
cmp ebx, 0 ;ebx에 있는값과 0과 비교한다.
je L3 ;같으면 L3로 이동하고 다를시 아래줄 실행 inc esi ;esi와 eax값을 1씩 증가시킨다.
inc eax
mov ebx, [esi] ;증가된 주소값의 값을 ebx대입한다. jmp L2 ;L2로 점프
L3:
mov strlenta, eax ;Count된 eax값을 strlenta에 대입한다.(target의 문자열 길이)
mov ebx, [edx] ;source의 문자열 길이도 구한다. mov eax, 0
L4:
cmp ebx, 0 je L5
inc edx inc eax
mov ebx, [edx] jmp L4
L5:
mov strlenso, eax
mov esi, ta ;esi와 edx가 가리키고 있는 주소값은 증가시켰기 때문에 mov edx, so ;다시 첫 번째 주소값을 가리키게 한다.
mov ebx, strlenta ;문자열의 길이를 ebx, ecx레지스터에 각각 대입한다. mov ecx, strlenso
L1:
mov al,[edx] ;soure의 문자를 target문자열 뒤에 대입한다. mov [esi+ebx],al
loop L1 ret
Str_concat ENDP ;str_concat 프로시져 끝. ;==================================str_concat end
END main
결과 화면 ⋅
Str_remove ○
문자열로부터 n개의 문자를 제거하는 Str_remove 프로시저를 작성하라 문자열 내의 제거될. 문자의 위치를 포인터및 변수로 전달하라 제거하는 문자의 개수를 지정하는 정수를 전달하라. .
소스코드 ⋅
TITLE Str_remove (hello.asm)
INCLUDE \masm615\include\Irvine32.inc
Str_remove PROTO, ;str_remove의 PROTO선언 tar:PTR BYTE,
i:DWORD, j:DWORD
.data
target BYTE "abcxxxxdefghijklmop", 0 ;remove할 문자열
valA DWORD ? ;인자값으로 넘길 2개의 변수선언 valB DWORD ?
prompt1 BYTE "Enter the Number: ",0 ;숫자를 입력받을시 출력할 문자열
.code
;===================================main main PROC
mov edx,OFFSET prompt1 ;2개의 숫자를 입력받는다. call WriteString
mov valB, eax
INVOKE Str_remove, ADDR target, valA, valB ;입력받는 2개의 숫자를 인자값으로 넘긴다.
exit
main ENDP
;---str Proc
Str_remove PROC, ;target주소값과 2개의 숫자를 파라미터로 설정. tar:PTR BYTE,
i:DWORD, j:DWORD
.data
source BYTE 20 DUP(0) ;복사할 문자열
.code
mov esi,tar ;target의 시작주소를 esi에 대입 mov ecx,SIZEOF source ;source의 문자열값을 ecx에 대입 mov ebx, 0 ;ebx레지스터 0으로 초기화
L1: ;문자열을 복사한다.
mov al,[esi]
mov source[ebx],al inc esi
inc ebx loop L1
mov esi,0 ;esi레지스터값을 0으로 초기화
mov ecx, I ;esi을 값으로 대입한다I .
L2: ;esi제거할 첫문자를 가리킨다.
inc esi loop L2
mov ebx, j ;ebx레지스터 를 대입한다j .
는 몇문자를 제거할 값을 가지고 있다
;ebx .
mov j, SIZEOF source ;반복횟수는 source문자열의 길이에서 값을 제거한I mov eax, j ;만큼 반복한다.
mov ecx, i
L3: ;제거할 문자의 다음부터 제거를 시작한 곳으로
mov al,source[esi+ebx] ;값을 복사한다. mov source[esi],al
inc esi loop L3
mov edx,OFFSET source ;결과 문자열 출력 call WriteString
ret
Str_remove ENDP END main
결과 화면 ⋅
Str_find ○
문자열에서 문자열의 최초의 출현 위치를 찾아 반환하는 프로시저를 작성
target source Str_find
하라 입력 매개변수는. source문자열에 대한 포인터와 target문자열에 대한 포인터 이어야 한 다 일치가 반결되면 프로시저는 제로 플래그를 설정하고. , EAX를 target문자열에서 일치한 위 치로 설정한다 일치가 발견되지 않으면 제로 플래그는 지워진다. , .
소스코드 ⋅
TITLE Str_find (hello.asm)
INCLUDE \masm615\include\Irvine32.inc
Str_find PROTO, ;str_find PROTO 선언 so : PTR BYTE,
ta : PTR BYTE
.data
target BYTE "123ABC342432", 0 ;섞여 있는 문자열 source BYTE "ABC", 0 ;찾을 문자열
;===================================main main PROC
mov edx,OFFSET target ;source와 target문자열 출력 call WriteString
call crlf
mov edx,OFFSET source call WriteString
call crlf
INVOKE Str_find, ADDR source, ADDR target ;str_find 프로시저 호출하면서 두문자열의 주소값을
인자값으로 넘겨준다
; .
exit
main ENDP
;---str Proc
Str_find PROC, ;Str_find 프로시저 두 개의 주소값을 파라미터로 받는다. ta : PTR BYTE,
so : PTR BYTE .data
valA DWORD 0 ;첫번째 문자열이 같은 경우 다른문자도 같을때 비교를, 위한 변수
;
pos DWORD 0 ;몇번째에 같은 문자열이 있는지 저장하는 변수
는
prompt1 BYTE "ABC ", 0 ;결과값 출력시 사용 부터 시작입니다
prompt2 BYTE " . ", 0 prompt3 BYTE "not Found. ", 0
.code
mov esi, so ;soure의 첫 번째 주소값을 esi대입 mov edi, ta ;target의 첫 번째 주소값을 edi대입 mov ebx, valA ;valA를 ebx에 대입
mov eax, 0 ;디버그시 레지스터값을 잘보기 위해 0으로 셋팅 mov edx, 0
L1:
mov al, [esi] ;esi가 가리키고 있는곳의 값을 al에 대입 mov dl, [edi] ;edi가 가리키고 있는곳의 값을 dl에 대입 inc pos ;pos값을 증가
inc esi ;esi주소값 증가
cmp al, 0 ;al값과 0과 비교해 같으면 제로플레그가 1로 셋팅되기 jnz L1 ;때문에 L4로 이동하고 아니면 계속 반복한다.
jmp L4
L2:
inc esi ;첫문자가 같은 경우 다음문자도 같은지 비교한다. inc edi
mov al, [esi] mov dl, [edi] inc ebx
cmp al, dl ;같으면 다음문자도 비교한다. je L2
cmp ebx, 3 ;3개 문자가 모두 같을 경우 L3로이동 je L3
mov edi, ta ;첫문자 이외에 다를 경우 다시 target주소를 edi에 jmp L1 ;대입후 L1으로 이동
L4:
call DumpRegs ;레지스터값 출력
mov edx,OFFSET prompt3 ;값을 찾을수 없다고 출력후 L5로 이동 call WriteString
jmp L5
L3:
call DumpRegs ;값이 일치할 경우 몇 번째부터 시작인지를 출력한다. mov eax, pos
mov edx,OFFSET prompt1 call WriteString
call WriteDec
mov edx,OFFSET prompt2 call WriteString
L5:
ret ;리턴
결과 화면 ⋅
어셈블리 언어를 이용한 블록 격파 게임 만들기
8.
소스코드 ○
TITLE GAME
INCLUDE irvine32.inc
width1 = 20 width2 = 18 width3 = 7 width4 = 10 width5 = 4 BufSize = 80
initplay = 345 initdown = -21 initside = 1 initturn = -1 initbarstart = 343 initbarwidth = 4 initspeed = 80
.data
buffer BYTE BufSize DUP(?),0,0 stdInHandle DWORD ?
bytesRead DWORD ?
gamestart BYTE width1 DUP(2ah),0ah
BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE "* GAME START *", 0ah
BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE width1 DUP(2ah),0
gamefinish BYTE width1 DUP(2ah),0ah
BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE "* GAME FINISH *", 0ah BYTE "* GAME FINISH *", 0ah BYTE "* GAME FINISH *", 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE 2ah, width2 DUP(20h), 2ah, 0ah BYTE width1 DUP(2ah),0
string1 BYTE 441 DUP(4DH), 0
stage1 BYTE width1 DUP(2ah),0ah
BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 3 BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 4 BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 5 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 6
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 7 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 8 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 9 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 10 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 11 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 12 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 13 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 14 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 15
BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 17
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 18 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 19 BYTE width1 DUP(44h), 0 20
BYTE width1 DUP(2ah),0ah
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 1 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 2
BYTE 2ah, 3 DUP(20h), 3 DUP(4Dh), 1 DUP(20h), 4 DUP(4Dh), 1 DUP(20h), 3 DUP(4Dh), 3 DUP(20h), 2ah, 0ah 3
BYTE 2ah, 3 DUP(20h), 3 DUP(4Dh), 1 DUP(20h), 4 DUP(4Dh), 1 DUP(20h), 3 DUP(4Dh), 3 DUP(20h), 2ah, 0ah 4
BYTE 2ah, 3 DUP(20h), 3 DUP(4Dh), 1 DUP(20h), 4 DUP(4Dh), 1 DUP(20h), 3 DUP(4Dh), 3 DUP(20h), 2ah, 0ah 5
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 6 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 7 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 8 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 9 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 10 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 11 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 12 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 13 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 14 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 15
BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 17
BYTE width1 DUP(44h), 0 20
BYTE width1 DUP(2ah),0ah
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 1 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 2
BYTE 2ah, 2 DUP(20h), 4 DUP(4Dh), 2 DUP(20h), 3 DUP(4Dh), 2 DUP(20h), 3 DUP(4Dh), 2 DUP(20h), 2ah, 0ah 3
BYTE 2ah, 3 DUP(20h), 3 DUP(4Dh), 1 DUP(20h), 4 DUP(4Dh), 1 DUP(20h), 3 DUP(4Dh), 3 DUP(20h), 2ah, 0ah 4
BYTE 2ah, 2 DUP(20h), 4 DUP(4Dh), 2 DUP(20h), 3 DUP(4Dh), 2 DUP(20h), 3 DUP(4Dh), 2 DUP(20h), 2ah, 0ah 5
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 6 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 7 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 8 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 9 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 10 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 11 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 12 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 13 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 14 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 15
BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 17
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 18 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 19 BYTE width1 DUP(44h), 0 20
BYTE width1 DUP(2ah),0ah
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 1 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 2
BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 3 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 4
BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 5 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 6
BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 7 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 8
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 15
BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 17
BYTE 2ah, width2 DUP(20h), 2ah, 0ah 18 BYTE 2ah, width2 DUP(20h), 2ah, 0ah 19 BYTE width1 DUP(44h), 0 20
stringScore BYTE " SCORE : ", 0 Score DWORD 300
stringLevel BYTE " LEVEL : ", 0 Level DWORD 2
finish DWORD 1
Ball BYTE 4fh block BYTE 2ah clearblock BYTE 20h
play SDWORD initplay down SDWORD initdown side SDWORD initside turn SDWORD initturn
barstart SDWORD initbarstart barwidth SDWORD initbarwidth speed SDWORD initspeed
.code main PROC
mov ecx, 10 L11:
call Clrscr mov eax, speed
mov edx, OFFSET gamestart call writestring
mov eax, 15 call setTextColor
mov eax, 0 mov ecx, 0 mov edx, 0 mov bl, Ball mov bh, clearblock
call copystage
L1:
mov eax, speed call Delay call Clrscr
call checkup call checkside call checkupside
INVOKE GetStdHandle, STD_INPUT_HANDLE mov stdInHandle,eax
INVOKE PeekConsoleInput, stdInHandle, ADDR buffer, BufSize - 2, ADDR bytesRead
INVOKE FlushConsoleInputBuffer, stdInHandle
mov esi, OFFSET buffer add esi, 10
mov cl, [esi] cmp cl, 37 jne L2 mov cl, 0 mov [esi], cl call moveleft L2:
mov [esi], cl call moveright
L3:
mov esi, OFFSET string1 add esi, play
add esi, down add esi, side
mov [esi], bl
mov edx, OFFSET string1
call writestring call crlf
mov eax, 0 mov eax, play add eax, down add eax, side mov play, eax mov cl, [esi] cmp cl, Ball jne L4
mov [esi], bh L4:
mov edx, 0
mov edx, OFFSET stringScore call writestring
mov eax, Score call writedec call crlf
call checkscore
mov edx, 0
mov edx, OFFSET stringLevel call writestring
mov eax, Level call writedec
cmp ecx, 1 je L1
mov ecx, 10 L22:
call Clrscr
mov edx, OFFSET gamefinish call writestring
call crlf
mov edx, OFFSET stringScore call writestring
mov eax, Score call writedec call crlf
mov edx, OFFSET stringLevel call writestring
mov eax, Level call writedec
mov eax, speed call delay mov ebx, ecx add ebx, 1 mov eax, ebx call SetTextColor loop L22
mov eax, 15 call setTextColor
exit main ENDP
checkup PROC pushad
mov esi, OFFSET string1 add esi, play
add esi, down
jne L2
mov eax, down imul turn mov down, eax
L2:
cmp al, 4Dh jne L3
mov eax, down imul turn mov down, eax
mov bl, clearblock mov [esi], bl
mov ecx, Score add ecx, 10 mov Score, ecx
L3:
cmp al, 44h jne L4 mov eax, 0 mov finish, eax L4:
popad ret checkup ENDP
checkside PROC pushad
mov esi, OFFSET string1 add esi, play
add esi, side
mov al, [esi] cmp al, 2ah jne L2
imul turn mov side, eax
L2:
cmp al, 4Dh jne L3
mov eax, side imul turn mov side, eax
mov bl, clearblock mov [esi], bl
mov ecx, Score add ecx, 10 mov Score, ecx
L3:
popad ret checkside ENDP
checkupside PROC pushad
mov esi, OFFSET string1 add esi, play
add esi, down add esi, side
mov al, [esi] cmp al, 2ah jne L2
mov eax, down imul turn mov down, eax
L2:
cmp al, 4Dh jne L3
mov eax, down imul turn mov down, eax
mov eax, side imul turn mov side, eax
mov bl, clearblock mov [esi], bl
mov ecx, Score add ecx, 10 mov Score, ecx
L3:
popad ret checkupside ENDP
moveright PROC pushad
mov bl, block mov bh, clearblock
mov esi, OFFSET string1 add esi, barstart add esi, barwidth add esi, 1
mov al, [esi] cmp al, 2ah je L2
cmp al, Ball je L2
mov eax, barstart add eax, 1
mov [esi], bl sub esi, barwidth mov [esi], bh L2:
popad ret moveright ENDP
moveleft PROC pushad
mov bl, block mov bh, clearblock
mov esi, OFFSET string1 add esi, barstart mov al, [esi] cmp al, 2ah je L2
cmp al, Ball je L2
mov eax, barstart sub eax, 1
mov barstart, eax
mov [esi], bl add esi, barwidth mov [esi], bh L2:
popad ret moveleft ENDP
copystage PROC pushad
mov esi, OFFSET string1 mov edi, OFFSET stage1 mov eax, Level
L1:
mov eax, 0 mov al, [edi] mov [esi], al inc esi inc edi cmp al, 0 jne L1
mov speed, initspeed mov play, initplay mov down, initdown mov side, initside mov turn, initturn
mov barstart, initbarstart mov barwidth, initbarwidth mov speed, initspeed popad
ret copystage ENDP
checkscore PROC pushad
mov eax, Level dec eax
mov ecx, 300 mul ecx mov ebx, eax mov eax, Score sub eax, ebx cmp eax, 300
jne L1
mov eax, Score cdq
mov ebx, 300 idiv ebx cmp edx, 0 jne L1
mov eax, Level inc eax
cmp eax, 5
mov edx, 0 mov finish, edx je L1
mov edx, 1 mov finish, edx call copystage L1:
popad ret checkscore ENDP
END main
결과 화면 ○
초기 화면 < >
게임 화면 종료 화면