기술문서 09. 07. 15. 작성 작성자 : 한국항공대학교 IDT 배건규 muckmock@kau.ac.kr - 1 -
목차 1. 어셈블리(MASM) 의기초...3 2. 데이터전송, 주소지정연산...7 3. 프로시저...13 4. 조건부처리...19 5. 정수연산...28 6. 고급프로시저...30 7. 문자열과배열...33 8. 어셈블리를이용한블록격파게임만들기...42 9. 참고문헌...56-2 -
1. 어셈블리언어(MASM) 의기초 1-1. 어셈블리언어의기본적인구성요소 산술연산우선순위(Precedence) - 수식이두개이상의연산자를포함시연산의순서의미 연산자이름우선순위 ( ) 괄호 1 +, - 단항플러스, 마이너스 2 *, / 곱셈, 나눗셈 3 MOD 나눔자 3 +, - 덧셈, 뺄셈 4 데이터표현 정수상수 [{+ -}] digits[radix] h b hexadecimal(0a3h, 1Ah) 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) 이거나 (_), @, $ 이어야한다. 예약어를사용해서는안된다. - 3 -
디렉티브 (directive) 프로그램의소스코드를어셈블할때어셈블러가인식하고활용하는명령어 논리세그먼트를정의하거나메모리모델을선택하거나프로시저만들거나변수정의시사용 디렉티브는어셈블러구문으로서인텔명령어집합과는관계가없다..data 데이터영역, name PROC 프로시저의시작 명령어 (Instruction) 프로그램이메모리에탑재되어실행될때프로세서에의해실행되는문장 Label: Mnemonic Operand(s) ;Comment 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 링커는오브젝트파일을읽고링크라이브러리안에있는프로시저를호출하는지점검후, 링크라이브러리에서필요한프로시저를복사해서오브젝트파일과합치고실행파일생성 - 4 -
Step4 운영체제의로더는실행파일을메모리로읽어들이고중앙처리장치를프로그램의시작 주소로분기하게하여그프로그램을실행한다. 1-3. 데이터정의 고유의데이터타입 타입 용도 BYTE 8비트부호가없는정수 SBYTE 8비트부호가있는정수 WORD 16 비트부호가없는정수( 실세주소모드에서 Near 포인터로사용될수있음) SWORD 16비트부호가있는정수 DWORD 32 비트부호가없는정수( 보호모드에서 Near 포인터로사용될수있음) SDWORD 32비트부호가있는정수 FWORD 48 비트정수( 보호모드에서 Far 포인터) QWORD 64비트정수 TBYTE 80 비트 (10 바이트) 정수 REAL4 32 비트(4 바이트) IEEE 짧은실수 REAL8 64 비트(8 바이트) IEEE 긴실수 REAL10 80 비트(10 바이트) IEEE 확장실수 데이터할당 초기설정 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가첫번째바이트에저장 - 5 -
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 main PROC ;code 세그먼트시작 ;main 프로시저시작 mov eax,lengthof strlen ;strlen의문자열길이를 eax 레지스터에저장한다. main ENDP END main ;main 프로시저의끝 ;program 종료 - 6 -
결과화면 * 문자열의길이가 11이기때문에 eax레지스터에 16진수값인 B 로저장이된다. 2. 데이터전송, 주소지정, 연산 2-1. 데이터전송명령 피연산자(Operand) 타입 즉시값(Immediate), 레지스터(Register), 메모리(Memory) 의 3 개지타입으로구성. 피연산자 설명 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비트더블워드즉시값 r/m8 8 비트피연산자, 16비트범용레지스터나메모리바이트 r/m16 16 비트피연산자, 16비트범용레지스터나메모리바이트 r/m32 32 비트피연산자, 32비트범용레지스터나메모리바이트 mem 8, 16 또는 32비트메모리피연산자 직접메모리피연산자 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 는도착점피연산자가될수없다. - 7 -
즉시값은세그먼트레지스터로이동될수없다. 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 명령 - 8 -
소스피연산자를동일크기의도착점피연산자에더한다. 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 add cx, 2 ;CX=-1, SF=1 ;CX=1, SF=0 캐리(CF) 플래그 CPU 가부호없는연산을수행할시중요함. 부호없는덧셈의결과가매우크거나작을시캐리플래그가지정된다. 최상위비트(MSB) 에서발생한캐리는자동으로캐리플래그에저장된다. mov al, 0FFh add al, 1 ;CF=1, AL=00 오버플로(OF) 플래그 부호있는연산에만관계있음. 산술연산이도착점피연산자에저장할수없는부호있는수를만들었을경우에지정 각데이터타입마다가장큰숫자를넘을경우 1로 set 된다( 바이트의경우 +127 이상인경우) mov al, +127 add al, 1 ;OF=1-9 -
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에있는포인터는 mov [esi], BL 역참조되고바이트가 AL로이동 ;destination이면레지스터가포인트하고있는메모리 위치에새로운값이저장 - 10 -
배열 간접피연산자는간접피연산자의값이쉽게수정될수있기때문에배열에다룰때유용.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 두종류의포인터를사용 NEAR 포인터 FAR 포인터 16Bit Mode 데이터세그먼트의시작부터 16 비트오프셋 32Bit Mode 데이터세그먼트의시작부터 32 비트오프셋 32비트세그먼트오프셋주소 48비트세그먼트오프셋주소 arrayb BYTE 10h, 20h, 30h, 40h ptrb DWROD arrayb ;ptrb는 arrayb 의주소값을지니고있다. 2-6. JMP와 LOOP명령 이동종류 무조건이동 (unconditional transfer) 프로그램은모든경우에분기하며, 새로운주소에서계속적인실행이일어나게새로운값이명령어포인터로탑재된다. 조건이동 (conditional transfer) 프로그램은어떤조건이참이될때이동하며 Intel 아키텍쳐는조건논리구조를만들기위해결합되는광범위한조건이동명령어를제공한다. CPU는 ECX 와플래그레지스터의내용을근거로참/ 거짓조건을해석함. JMP명령 코드세그먼트내목표위치로무조건이동한다. 위치는어셈블러에의하여주소를변환되는코드레이블에의하여식별되어야함 현재프로시저안에있는레이블로만점프가능 - 11 -
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 main PROC ;code 세그먼트시작 mov ecx,4 ; 루프카운터에 4 를대입한다. L1: ; 루프카운터에의해 L1은 4 번반복한다. push ecx ;ecx레지스터의값을 Stack에넣음으로서다른반복문을 inc vala ;vala값을 1증가 ; 다시 L1 반복문으로돌아올수있게해준다. 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 레지스터에대입한다. call WriteDec ;eax레지스터값출력 - 12 -
mov al,'=' ;al 레지스터에 = 를대입한다. call WriteChar ;= 를출력한다. mov eax,vala ;vala값을 eax 레지스터에저장한다. mul valb ;eax레지스터에있는것과 valb 값을곱해준다. call WriteDec call Crlf ;eax레지스터에있는값을출력 ;new line실행 inc valb ;valb값 1증가 loop L2 ;L2반복문의끝 pop ecx call Crlf loop L1 ; 기존루프값을꺼낸다. ;new line실행 ;L1반복문의끝 출력화면 3. 3-1. 프로시저 외부라이브러리링크 링크라이브러리는기계어코드로어셈블된프로시저를갖고있는파일이다. 라이브러리에서코드는프로시저, 상수, 변수를포함하는하나이상의소스파일로시작한다. 소스파일들은오브젝트파일로어셈블되고그오브젝트파일은라이브러리에삽입된다. 링커명령어로오브젝트파일과기타링크라이브러리를합친다. link32 hello.obj irvine32.lib - 13 -
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) 는마지막으로푸시된정수를가리킨다. - 14 -
푸시(push) 동작 푸시동작은스택포인터를 4 감소시키며(32 비트인경우) 새로운값을스택포인터가 가리키는저장위치에복사 팝(Pop) 동작 팝동작은스택으로부터값을제거하고그값을레지스터나변수에놓는다. 스택으로부터팝된후스택포인터는스택의그다음높은저장위치를가리킴 Stack 의사용 레지스터가하나이상의목적으로사용될때레지스터를저장하는임시적인영역으로 편리하게사용된다. 레지스터가수정된후에원래의값으로복원될수있음 CALL명령이실행되었을때 CPU는현재프로시저의리턴주소를스택에저장 프로시저를호출할때인수(argument) 를전달. 이것들이스택에푸시될수있다. 프로시저안의지역변수들은스택위에생성되며프로시저가끝나면사라진다. 3-4. 프로시저의정의및사용 프로시저의정의 high-level 언어의함수개념이랑비슷 비공식적으로프로시저는리턴문으로끝나는문장들의블록으로정의 PROC과 ENDP 디렉티브를사용하여선언 시작프로시저가아닌다른프로시저를만들때 (cpu 를프로시저를호출한위치로리턴하게함.) RET 문으로끝내라. 시작프로시저(main) 는 exit 문으로끝내는특별한경우이다. - 15 -
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로작성 소스코드 INCLUDE /masm615/include/irvine32.inc - 16 -
; 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 div vals 작은수에서큰수를나눔 cmp edx,0 ; 나머지값과 0 비교 ; - 17 -
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 값 1출력 mov eax,gcd ; 나눠지는수가없을시( 소수) 초기 mul vals call WriteDec call Crlf ; 결과값출력 ret gcdmul ENDP ;-------------------------------------main PROC main PROC call insert call gcdmul exit main ENDP END main - 18 -
결과화면 4. 4-1. 조건부처리 부울및비교명령 부울명령 연산 설명 AND 소스피연산자와도착점피연산자사이의부울 AND 연산 OR 소스피연산자와도착점피연산자사이의부울 OR 연산 XOR 소스피연산자와도착점피연산자사이의부울 XOR연산 NOT 도착점피연산자에부울 NOT 연산 TEST BT, BTC, BTR, BTE 소스피연산자와도착점피연산자사이의묵시적부울 AND연산을 수행하여중앙처리장치의플래그를적절히지정소스피연산자로부터캐리플래그로비트 n을복사하고도착점피연산 자에서같은비트를보수/ 리셋/ 지정 AND 명령 두개의피연산자에서매칭되는비트사이에부울 피연산자에놓는다. AND destination, source AND연산을하고그결과를도착점 AND 명령은종종선택된비트를해제하고나머지를유지할때사용된다. AND 명령은항상오퍼플로플래그(OF) 와캐리플래그(CF) 를해제한다. OR 명령 두개의피연산자에서매칭되는비트사이에부울 OR 피연산자에놓는다. OR destination, source 연산을하고그결과를도착점 OR 명령은종종선택된비트를지정하고다른것을유지할때사용한다. OR 명령은항상캐리와오버플로플래그를해제한다. - 19 -
XOR 명령 두개의피연산자에서매칭되는비트사이에부울배타적 피연산자에놓는다. XOR destination, source XOR명령은 AND와 OR 와같은피연산자조합을사용한다. OR연산을하고그결과를 XOR 의특별한점은동일한피연산자를두번적용하면그자체가된다. XOR 명령은항상캐리와오버플로플래그를해제한다. NOT 명령 피연산자의모든비트를바꾸고, 그결과는 1 의보수(one's complement) 라한다. 어떤플래그도영향을받지않는다. mov al, 11110000b not al ;AL=00001111b TEST 명령 두피연산자사이에매칭되는비트에대하여묵시적 플래그를지정한다. AND 와차이점은도착점피연산자를수정하지않는다. TEST 명령은항상오버플로플래그와캐리플래그를해제한다. 부호, 제로, 패리티플래그는 AND 명령에서와동일하게수정된다. AND연산을수행하고결과에따라서 CMP 명령 도착점피연산자로부터소스피연산자를묵시적으로빼며, 어떤피연산자도수정되지않는다. CMP destination, source CMP 명령은오버플로, 부호, 제로, 캐리, 보조캐리, 패리티플래그를 SUB명령이사용되었다고 했을때의도착점피연산자값에따라서변화시킨다. CMP Results ZF CF Flags destination < source 0 1 SF OF destination > source 0 0 SF=OF destination = source 1 0 ZF=1 4-2. 조건부점프 조건부실행순서 CMP, AND, SUB 등의연산으로중앙처리장치플래그를수정한다. 조건부점프명령어가플래그를테스트하여새로운주소로분기한다. CMP leftop, rightop - 20 -
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 JECXZ jump if CX=0 jump if ECX=0 부호가없는비교 JA JNBE JAE JNB JB JNAE JBE JNA 니모닉 설명 jump if above(if leftop>rightop) jump if not below or equal(same as JA) jump if above or equal(if leftop>=rightop) jump if not below(same as JAE) jump if below(if leftop<rightop) jump if not above or equal(same as JB) jump if below or equal(if leftop<=rightop) jump if not above(same as JBE) - 21 -
부호가있는비교 JG JNLE JGE JNL JL JNGE JLE JNG 니모닉 설명 jump if greater(if leftop>rightop) jump if not less than or equal(same as JG) jump if greater than or equal(if leftop>=rightop) jump if not less(same as JGE) jump if less(if leftop<rightop) jump if not greater than or equal(same as JL) jump if less than or equal(if leftop<=rightop) jump if not greater(same as JLE) 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 L1: mov x,1 mov y,2 L2: ;otherwise, jump to L2-22 -
논리 AND 연산자(Java/c++) if(a1>b1) AND (b1>c1) { x=1; } 논리 AND 연산자( 어셈블리) cmp a1, b1 ja L1 jmp next L1: cmp b1, c1 ja L2 jmp next ;first expression ;second expression 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 ja L1 cmp b1, c1 jbe next ;1: compare AL to BL ;if true, skip second expression ;2: compare BL to CL ;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 while: cmp eax, val2 jnl endwhile inc eax dec val2 jmp while endwhile: mov val1, eax ;copy variable to eax ;if not(val1<val2) ;exit the loop ;val1++; ;val2--; ;repeat the loop ;save new value for val1-23 -
SWITCH CASE Switch case( 어셈블리).data CaseTable BYTE 'A' ;lookup value DWORD Process_A BYTE 'B' DWORD Process_B (etc.) ;address of procedure 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 call Clrscr ; 화면을 clear 시켜준다. - 24 -
mov eax, num1 ;12를 eax 레지스터에저장한다. INVOKE Factorial, ;Factorial함수를호출하면서인자값으로 5 개를넘긴다. num1, num2, num3, num4, num5 ReturnMain: ; 함수호출이모두끝날경우이곳으로리턴되실행된다. main ENDP call WriteDec call Crlf exit ;eax 레지스터의값을출력한다. 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 레지스터값을넘겨준다. num2, num3, num4, num5-25 -
; 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 을순차적으로누르게되면다음줄어셈블리코드가실행이된다. 이때값이변하는레지스 터는빨간색으로표기가된다. EIP 는다음실행될주소값을가지고있으며, ESP레지스터는스택 - 26 -
포인터이다. 따라서 ESP레지스터에들어있는주소값을 Memory에입력하게되면거기에해당되 는값을볼수가있다. 메모리를참조할경우 Memory의주소값은 16진수로되있기떄문에주소값을입력할경우앞에 0x 를붙여준다. ( 빨간색동그라미는 BreakPoint 이며노란색화살표는이번에실행될코드이다.) 노란색화살표가가리키고있는곳이이번에실행될코드이다. 따라서앞에줄을보면어셈블리코 드로 num5가 push 된것을확인할수있다. 따라서그값이실제메모리에저장되있는지확인하기 위해서 ESP(Stack의위치 Pointer) 의주소를 Memory에써주면맨첫번째값이 04라는것을 확인할수있다. num5값이 4로초기화시켜줬기때문에 2 개의값이일치하는것을알수있다. - 27 -
< 앞에본화면에서 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으로채우는논리좌시프트동작을수행 가장상위비트는캐리플래그로옮겨가고, 캐리플래그에있는비트는손실된다. SHL destination, count - 28 -
SHR( 우시프트) 명령 도착점피연산자에대해논리우시프트연산을수행하여, 최상위비트를 0 으로치환한다. 최하위비트는캐리플래그로복사되고, 캐리플래그에있던비트는손실된다. ROL( 좌회전) 명령 각비트를왼쪽으로시프트하며, 최상위비트가캐리플래그와최하위비트로복사된다. 회전을함으로써비트손실이없다. ROL 을이용해서, 한바이트의상위 4 비트( 비트 4~7) 와하위 4 비트( 비트 0~3) 을교환가능 ROR( 우회전) 명령 각비트를오른쪽으로시프트한다. 최하위비트를캐리플래그와최상위비트에동시에복사한다. 명령포맷은 SHL과동일 5-2. MUL 곱셈과나눗셈명령 명령 AL, AX, EAX에 8, 16, 32 비트피연산자를곱하는명령어이다. 표는승수의크기에따른디폴트피연산자와곱셈결과를보여준다. 곱셈결과를저장하는레지스터는피승수와승수크기의 2 배이어서, 오버플로가생기지 않도록해야한다. 곱셈결과의상위절반이 mov al, 5h mov b1, 10h mul b1 피승수승수곱셈결과 AL r/m8 AX AX r/m16 DX:AX EAX r/m32 EDX:EAX 0 이아니면캐리와오버플로플래그가영향을받는다. ;CF=0 IMUL 명령 IMUL( 부호있는곱셈) 명령은부호있는정수곱셈을수행한다. MUL 명령과동일한구문과피연산자를가지며, 차이점은곱셈의부호를유지한다. IMUL 은곱셈결과의상위부분이하위부분의부호확장이아니면캐리플래그와오버플로 플래그를설정한다. mov ax, 48 mov bx, 4-29 -
imul bx ; DX:AX=000000C0h, OF=0 DIV 명령 DIV( 부호없는나눗셈) 명령은부호없는정수에대해 8, 16, 32 비트나눗셈을수행함. 단일피연산자만나태내며, 그피연산자는제수가된다. 피제수 제수 몫 나머지 AX r/m8 AL AH DX:AX r/m16 AX DX EDX:EAX r/m32 EAX EDX 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 디렉티브바로다음행에위치해야한다. 지역변수사용시, 어셈블러에의해코드생성 - 30 -
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 name 예 10, 3000h, OFFSET mylist, TYPE array (10*20), COUNT mylist, array, myword, mydword [mylist+2], [ebx+esi] eax, bl, edi ADDR mylist ADDR연산자는 INVOKE 디렉티브를가지고프로시저를호출할때, 포인터를전달하기위해 사용된다. 프로시저인수로주소를전달하는것을참조에의한전달(passing by reference) - 31 -
라한다. 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 INVOKE mysub mysub PROC.. mysub ENDP ;procedure prototype ;procedure call ;procedure implementation 단, 프로시저구현은 INVOKE 문장이전에나올수있다. 이경우, PRO는프로토타입역할임 값에의한전달 (passing by value) 변수값의복사본이프로시저로절달될때, 이것을값에의한전달이라한다. 일반적으로, 호출된프로시저에의해값이변하지않도록인수들을값에의해전달한다. 변수의복사본은호출하는프로그램에의해스택에푸시되며, 호출된프로시저는스택으로부터값을가져와서그값을이용한다. 프로시저가매개변수를변경하더라도, 호출하는프로그램에있는대응되는인수값에액세스할수없다..data mydata WORD 1000h ;this never changes - 32 -
.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 mov WORD PTR[esi], 0 Sub2 ENDP ;get the address ;dereference, assign zero 7. 7-1. 문자열과배열 문자열프리미티브명령 문자열프리미티브 바이트, 워드, 더블워드의배열처리를위한 Intel 명령집합에는 5 개의그룹이있으며, 이를 문자열프미리티브라고하지만, 문자배열로만국한되진않는다. 문자열명령어는메모리를참조하기위해 ESI, EDI 레지스터를참조한다. ESI, EDI 는유일하게단일메모리피연산자를사용하여, 문자열과배열의처리에특히유용 보호모드에서는 ESI는자동적으로 DS 가가리키는세그먼트에서의오프셋이되고, EDI는 자동적으로 ES 가가리키는세그먼트내의오프셋이된다. DS, ES 는항상같은값으로설정되고, 이를변경할수없다. - 33 -
문자열프리미티브명령 명령어 MOVSB, MOVSW, MOVSD 문자열데이터이동 정수를복사 : 설명 한메모리위치로부터다른곳으로 CMPSB, CMPSW, CMPSD 문자열비교 : 두개의메모리값들을비교 SCASB, SCASW, SCASD 문자열검색 : 정수와메모리의내용비교 STOSB, STOSW, STOSD 문자열데이터저장 : 메모리에정수저장 LODSB, LODSW, LODSD 문자열로부터누산기로탑재 탑재 (AL, AX, or EAX) : 메모리에서누산기로정수를 MOVSB, MOVSW, MOVSD 세명령은 ESI가가리키는메모리위치에서 EDI가가리키는메모리위치로데이터를복사함 두개의레지스터들은자동적으로방향플래그값에의해증가 MOVSB - 바이트들의이동( 복사), ESI/EDI 1감소 MOVSW - 워드들의이동( 복사), ESI/EDI 2감소 MOVSD - 더블워드들의이동( 복사), ESI/EDI 4감소 or 감소한다. CMPSB, CMPSW, CMPSD 세명령은각각 ESI가가리키는메모리피연산자와 EDI가가리키는메모리피연산자를비교 방향플래그에의해 CMPSB - CMPSW - CMPSD - 바이트비교 워드비교 더블워드비교 ESI, EDI 값이증가또는감소한다. 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 문자열에대한포인터를전달하라. - 34 -
소스코드 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 strlenta DWORD? ; 문자열의길이를담기위한변수선언. - 35 -
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: L3: cmp ebx, 0 ;ebx에있는값과 0 과비교한다. je L3 ; 같으면 L3로이동하고다를시아래줄실행 inc esi ;esi와 eax값을 1 씩증가시킨다. inc eax mov ebx, [esi] ; 증가된주소값의값을 ebx 대입한다. jmp L2 ;L2로점프 mov strlenta, eax ;Count된 eax값을 strlenta 에대입한다.(target 의문자열길이) mov ebx, [edx] mov eax, 0 L4: cmp ebx, 0 je L5 inc edx inc eax mov ebx, [edx] jmp L4 L5: mov strlenso, eax ;source 의문자열길이도구한다. mov esi, ta ;esi와 edx가가리키고있는주소값은증가시켰기때문에 mov edx, so ; 다시첫번째주소값을가리키게한다. mov ebx, strlenta ; 문자열의길이를 ebx, ecx 레지스터에각각대입한다. mov ecx, strlenso L1: mov al,[edx] ;soure의문자를 target 문자열뒤에대입한다. mov inc inc [esi+ebx],al edx esi - 36 -
ret loop L1 Str_concat ENDP ;==================================str_concat end END main ;str_concat 프로시져끝. 결과화면 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 call readint mov vala, eax call WriteString call readint - 37 -
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 mov inc inc al,[esi] source[ebx],al esi 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 sub eax, I mov i, eax ; 만큼반복한다. ;( 그래야원하는만큼문자를제거할수있다.) - 38 -
mov ecx, i L3: ; 제거할문자의다음부터제거를시작한곳으로 mov al,source[esi+ebx] ; 값을복사한다. mov inc source[esi],al 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, so : PTR BYTE, ta : PTR BYTE ;str_find PROTO 선언.data target BYTE "123ABC342432", 0 source BYTE "ABC", 0 ; 섞여있는문자열 ; 찾을문자열.code - 39 -
;===================================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 주소값을 exit main ENDP ;str_find 프로시저호출하면서두문자열의 ; 인자값으로넘겨준다. ;-----------------------------------str Proc Str_find PROC,.data ta : PTR BYTE, so : PTR BYTE ;Str_find 프로시저두개의주소값을파라미터로받는다. 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값을증가 cmp al, dl ; 두문자가같을경우 L2로이동 je L2-40 -
inc esi ;esi주소값증가 cmp al, 0 ;al값과 0과비교해같으면제로플레그가 1로셋팅되기 jnz L1 ; 때문에 L4 로이동하고아니면계속반복한다. jmp L4 L2: L4: 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으로이동 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 Str_find ENDP END main ; 리턴 ; 프로시저끝. - 41 -
결과화면 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 "* GAME START *", 0ah BYTE "* GAME START *", 0ah BYTE "* GAME START *", 0ah - 42 -
BYTE width1 DUP(2ah),0 gamefinish BYTE width1 DUP(2ah),0ah BYTE "* GAME FINISH *", 0ah BYTE "* GAME FINISH *", 0ah BYTE "* GAME FINISH *", 0ah BYTE width1 DUP(2ah),0 string1 BYTE 441 DUP(4DH), 0 stage1 BYTE width1 DUP(2ah),0ah 1 2-43 -
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 6 7 8 9 10 11 12 13 14 15 BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 17 18 19 BYTE width1 DUP(44h), 0 20 BYTE width1 DUP(2ah),0ah 1 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 6 7 8 9 10 11 12 13 14 15 BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 17 18 19-44 -
BYTE width1 DUP(44h), 0 20 BYTE width1 DUP(2ah),0ah 1 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 6 7 8 9 10 11 12 13 14 15 BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 17 18 19 BYTE width1 DUP(44h), 0 20 BYTE width1 DUP(2ah),0ah 1 2 BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 3 4 BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 5 6 BYTE 2ah, width5 DUP(20h), width4 DUP(4Dh), width5 DUP(20h), 2ah, 0ah 7 8 9 10 11 12 13 14-45 -
15 BYTE 2ah, width3 DUP(20h), 4 DUP(2ah), width3 DUP(20h), 2ah, 0ah 16 17 18 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 call delay mov ebx, ecx add ebx, 1 mov eax, ebx call SetTextColor loop L11-46 -
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 L2: mov esi, OFFSET buffer add esi, 10 mov cl, [esi] cmp cl, 37 jne L2 mov cl, 0 mov [esi], cl call moveleft cmp cl, 39 jne L3 mov cl, 0-47 -
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 L4: 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 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 mov ecx, finish - 48 -
cmp ecx, 1 je L1 L22: mov ecx, 10 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 mov al, [esi] cmp al, 2ah - 49 -
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 mov eax, side - 50 -
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 mov eax, side imul turn mov side, eax - 51 -
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 barstart, eax - 52 -
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 dec eax mov ecx, 441 mul ecx add edi, eax - 53 -
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 mov Level, eax - 54 -
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 결과화면 < 초기화면> < 게임화면> < 종료화면> - 55 -
9. References [1] 어셈블리언어 - KIP R. IRVINE - 56 -