외로운 Nova의 작업실

Assembly 언어 공부 - 30(INVOKE,ADDR,PROC,PROTO 디렉티브) 본문

Programming/Assembly

Assembly 언어 공부 - 30(INVOKE,ADDR,PROC,PROTO 디렉티브)

Nova_ 2022. 10. 3. 16:20

안녕하세요, 오늘은 프로시저를 정의하고 호출하는 강력한 수단에대해서 배워보도록 하겠습니다. 

 

- INVOKE, ADDR

우리는 지금까지 레지스터나 스택으로 프로시저에게 매개변수를 전달했습니다. 하지만 invoke 명령어를 이용하면 편하게 C언어에서 함수를 사용하는 것처럼 사용할 수 있습니다. 단, 매개변수는 역순으로 스택에 push됩니다. 바로 예제를 봐봅시다.

.code

invoke DumpArray, OFFSET array, LENGTHOF array, TYPE array

위 코드는 DumpArray 프로시저를 실행합니다. DumpArray 프로시저는 Array의 값들을 순서대로 콘솔에 출력해줍니다. 매개변수로는 배열의 주소, 배열의 길이, 배열의 크기를 주어야합니다. 위 코드는 MASM 어셈블러에 의해 아래코드로 재작성됩니다.

.code

push TYPE array
push LENGTHOF array
push OFFSET array
call DumpArray

invoke는 매개변수가 32비트보다 작을때 EAX와EDX를 사용합니다. 따라서 항상 invoke를 호출하기 전후로 EAX,EDX를 저장하고 복원하는게 좋습니다.

 

addr 연산자는 포인터 인수를 전달할때 사용합니다. 또한, invoke 명령어에서만 활용할 수 있는점이 있습니다. 바로 예제를 봐봅시다.

.code

invoke DumpArray, ADDR array, LENGHTHOF array, TYPE array

 

- PROC 

PROC 디렉티브는 매개변수를 사용하기위해 항상 ebp에서 주소값을 계산하던 것을 생략하게 도와줍니다.

.code

AddSum PROC,
    val1:DWORD,
    val2:DWORD
    mov eax, val1
    add eax, val2
    ret
AddSum ENDP

AddSum 프로시저는 2개의 변수를 받아 합을 eax에 저장합니다. 따라서 2개의 매개변수를 val1, val2로 이름을 짓고 DWORD 크기라고 명시해주어야됩니다. 주의할점은 PROC뒤에 , 가 있다는 점입니다. 변수의 이름을 정의했다면, 아래 mov eax, val1 처럼 변수처럼 사용할 수 있습니다. 위 코드는 아래와 같이 변합니다.

.code

AddSum PROC,
    push ebp
    mov ebp, esp
    mov eax, dword ptr [ebp+8]
    add eax, dword ptr [ebp+0Ch]
    ret 8
AddSum ENDP

PROC 디렉티브를 이용하면 ret 8 처럼 매개변수의 삭제도 자동을 됩니다. PROC를 사용하면서 매개변수 전달 규약을 지지정할 수 있습니다. 다음은 C 호출 규약의 예시입니다.

.code

Example PROC C,
	parm1:DWORD,
    	parm2:DWORD

아래는 STDCALL 호출 규약의 예시입니다.

.code

Example PROC STDCALL,
	parm1:DWORD,
    	parm:DWORD

위처럼 호출 규약을 명시해준다면 호춝듀약에따라 MASM 어셈블러가 자동으로 코드를 수정해줍니다.

 

- PROTO

proto 디렉티브는 프로시저의 원형을 만듭니다. c언어에서 먼저 함수의 원형만 선언해놓고 나중에 정의할때 처럼 원형을 정의할때 사용합니다. 따라서 보통 PROTO - INVOKE - PROC 순서대로 위 디렉티브들을 사용합니다. 원형을 미리 정의하고 실행을 시킨후 나중에 함수를 정의하는 구조입니다. 먼저 정의하고 실행시켜도 무방합니다. 아래는 예시입니다.

.code

Example PROTO,
	parm1:DWORD,
    	parm2:DWORD

Eample 프로시저는 DWORD 타입의 매개변수를 2개 받는 프로시저인 것을 알 수 있습니다.

Comments