외로운 Nova의 작업실

Assembly 언어 공부 - 18(JMP와 LOOP 명령어 이론 및 실습) 본문

Programming/Assembly

Assembly 언어 공부 - 18(JMP와 LOOP 명령어 이론 및 실습)

Nova_ 2022. 8. 2. 12:27

안녕하세요, 오늘은 JMP 와 LOOP 명령어가 무엇인지 배워보고 직접 실습해보는 시간을 가져보도록 하겠습니다.

 

JMP 명령어

JMP destination 은 코드레이블로 표시되는 목적지로 무조건 이동시킵니다. 간단한 JMP 명령어 코드를 봐보도록 하겠습니다.

top : 
	...
    	...
    	JMP top

JMP 명령어에의해 위 코드는 반복되게 됩니다. 또한 JMP는 무조건 적이여서 루프를 빠져나가는 다른 방법이 없으면 위와 같은 루프는 끝없이 계속될 것 입니다. 

 

LOOP 명령어

LOOP destination 은 ECX가 자동적으로 카운트로 사용되며 루프를 반복할때마다 ECX의 값을 감소시킵니다. 또한, 루프의 목적지는 현재 위치 카운터에서 -128~+127 바이트 내에 있어야합니다.

 

LOOP 명령어의 실행은 두단계로 나뉩니다. 첫번째, ECX에서 1을 빼고 두번째, ECX가 0이 아니면 destination으로 점프합니다. 간단한 LOOP 명령어 코드를 봐보도록 하겠습니다.

mov ax, 0
mov ecx, 5

L1 : 
	inc ax
    	LOOP L1

위 코드에서 L1은 5번 반복하게되며, ax의 값은 결국 5가 되게됩니다. 처음에 ecx를 0으로 초기화해버리면 LOOP는 4,294,967,296번 반복하게됩니다. 따라서 ecx의 초기값이 굉장히 중요합니다.

 

또한, 중첩 루프의 경우 루프안에서 ECX의 값을 수정해야합니다. 수정할때는 꼭 ECX를 변수에 저장하고 새로운 값을 집어 넣어줘야합니다. 중첩 루프의 간단한 코드를 봐보도록 하겠습니다.

.data
count DWORD ?

.code
	mov ecx, 100

L1 : 	
	mov count, ecx
    	mov ecx, 20
L2 : 
	...
    ...
    LOOP L2
    mov ecx, count
    LOOP L1

위 코드는 결국 L1은 100번, L2는 2000번 실행됩니다. 일반적으로 두레벨 이상으로 중첩된 루프는 작성하기가 어렵다보니중첩 루프를 서브 루틴으로 나누어 루프를 실행시키는 방법도 있습니다.

 

정수 배열 합하기

위 2가지 명령어를 가지고 흔히 쓰는 코드인 정수 배열의 값들을 모두 합하는 실습을 해보도록 하겠습니다. 바로 코드부터 보시죠.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib

PDWORD TYPEDEF PTR DWORD

.data

dArray DWORD 10000h, 20000h, 30000h, 40000h
ptrd PDWORD dArray            


.code
main PROC

mov esi, ptrd			;간접 주소 접근을 위해 esi에 배열의 주소값 할당
mov ecx, LENGTHOF dArray	;ecx 카운터에 배열의 개수를 할당
mov eax, 0h			;eax는 합을 저장할것임으로 초기화

L1 : 
    add eax, [esi]		;eax에 배열의 값저장
    add esi, TYPE dArray	;esi에 다음 배열의 주소 저장
    LOOP L1			;ecx값 하나 빼고 0이 아니면 L1 반복


call DumpRegs

    exit

main ENDP
END main

위 코드를 실행시켜보면,

잘 실행 된 것을 확인 할 수 있습니다.

 

문자열 복사하기

정수 배열의 합 말고도 자주 코딩해야하는 문자열 복사하는 기능은 루프를 사용하여 간단하게 구현할 수 있습니다. 바로 코드부터 보시죠.

include 	c:\assembly\irvine32.inc
includelib  c:\assembly\irvine32.lib
includelib  c:\assembly\kernel32.lib
includelib  c:\assembly\user32.lib


.data
source BYTE "hello world", 0
target BYTE LENGTHOF source DUP(0)           


.code
main PROC

mov esi, 0			;esi를 배열의 index로 사용하기위해 0으로 초기화
mov ecx, LENGTHOF source	;ecx에는 source 배열의 원소의 개수를 넣어줌

L1 :    
    mov al, source[esi]		;레지스터에 source 원소의 값을 넣어줌
    mov target[esi], al		;target 원소에 레지스터 값을 넣어줌
    inc esi			;index값을 1증가시킨다. byte이기때문에 1임
    LOOP L1

mov eax, DWORD PTR target


call DumpRegs

    exit

main ENDP
END main

위 코드를 실행하면,

아스키코드 표를 봐보자

eax에 l l e h가 저장되었을 것이다. 'h' = 68h, 'e' = 65h, 'l' = 6Ch 이므로 잘 target에 저장된 것을 확인 할 수 있다.

Comments