2. Defining and Using Procedures
1) Creating Procedures
1> 다른 language의 함수와 유사한 개념이다. (큰 문제를 작은 문제로 쪼개어 다룬다.)
2> 사용
func_name PROC
.
ret
func_name ENDP
2) Documenting Procedure
(procedure 만들 때 적어주면 좋은 것들)
1> procedure가 수행하는 작업에 대한 설명
2> Receives : Input parameters에 대한 설명 (their usage and requirements)
3> Returns : procedure가 return하는 값들에 대한 설명
4> Requires : procedure가 호출되기 전에 만족되어야 하는 조건들(precondition)에 대한 설명
5> 예시
SumOf PROC
; Calculates and returns the sum of three 32-bit integers.
; Receives: EAX, EBX, ECX, the three integers. May be signed or unsigned.
; Returns: EAX = sum, and the status flags (Carry, Overflow, etc.) are changed.
; Requires: nothing
add eax,ebx
add eax,ecx
ret
SumOf ENDP
3) CALL, RET (Instruction)
1> CALL : procedure를 호출
- 다음에 실행될 instruction의 주소를 stack에 push
- 호출되는 procedure의 주소를 EIP에 copy
2> RET : procedure에서 return
- stack의 top을 EIP로 pop
3> 예시 1
main PROC
00000020 call MySub
00000025 mov eax,ebx
.
main ENDP
MySub PROC
00000040 mov eax,edx
.
ret
MySub ENDP
- 00000020 call MySub : 다음에 실행될 instruction(MOV)의 주소(00000025)를 stack에 push
- 00000020 call MySub -> 00000040 mov eax,edx : 호출되는 procedure(MySub)의 주소(00000040)를 EIP에 copy
- ret : stack의 top(0000025)을 EIP로 pop
4> 예시 2 : Nested Procedure Call
main PROC
.
.
call Sub1
exit
main ENDP
Sub1 PROC
.
.
call Sub2
ret
Sub1 ENDP
Sub2 PROC
.
.
call Sub3
ret
Sub2 ENDP
Sub3 PROC
.
.
ret
Sub3 ENDP
- 위와 같이 4중 중첩인 경우 stack에 3개의 return address가 저장된다.
- main -> sub1 -> sub2 순서대로 stack에 쌓인다.
4) Local and Global Labels
1> local label은 procedure 내에서만 접근 가능하다.
2> global label은 어디서나 접근이 가능하다.
3> 예시
main PROC
jmp L2 ; error
L1: ; global label
exit
main ENDP
sub2 PROC
L2:
jmp L1 ; local label
ret ; ok
sub2 ENDP
5) Procedure Parameters
1> procedure는 다른 여러 프로그램들에서 사용될 수 있기 때문에 specific한 변수명을 필요로 하면 안된다.
=> parameter는 runtime에 결정되어서 다양한 곳에서 필요한 procedure를 유연하게 할 수 있다.
2> not flexible procedure (안 좋은 사례)
ArraySum PROC
mov esi, 0 ; array index
mov eax, 0 ; set the sum to zero
mov ecx, LENGTHOF myarray ; set number of elements
L1: add eax, myArray[esi] ; add each integer to sum
add esi,4 ; point to next integer
loop L1 ; repeat for array size
mov theSum,eax ; store the sum
ret
ArraySum ENDP
- 위 프로그램은 myArray, theSum이라는 specific 변수에 대해서만 작동한다.
3> flexible procedure (좋은 사례)
ArraySum PROC
; Receives: ESI points to an array of doublewords,
; ECX = number of array elements.
; Returns: EAX = sum
;-----------------------------------------------------
mov eax, 0 ; set the sum to zero
L1: add eax, [esi] ; add each integer to sum
add esi,4 ; point to next integer
loop L1 ; repeat for array size
ret
ArraySum ENDP
- 이 procedure는 ESI에 주소가 들어있는 임의의 DWORD array의 합을 EAX에 저장한다.
6) Program Design Using Flowchart
1> Basic building blocks of flowcharts
2> 예시 1 : 이전에 배운 ArraySum procedure
push esi
push ecx
mov eax,0
AS1: add eax,[esi]
add esi,4
loop AS1
pop ecx
pop esi
3> 예시 2
input exam grade from the user
if( grade > 70 )
display "Pass"
else
display "Fail"
endif
7) USES (operator)
1> 보존해야할 register를 명시
2> 예시
ArraySum PROC USES esi ecx
mov eax,0 ; set the sum to zero
etc.
MASM은
위의 USES esi ecx 부분을
push esi
push ecx
pop ecx
pop esi
로 변환한다.
3> 변환되었을 경우의 코드
ArraySum PROC
push esi
push ecx
mov eax, 0
. . .
pop ecx
pop esi
ret
ArraySum ENDP
8) register를 push하지 말아야하는 경우
SumOf PROC ; sum of three integers (EAX = 1, EBX = 2, ECX = 3)
push eax ; line 2 : stack EAX = 1
add eax,ebx ; line 3 : EAX = 3, EBX = 2
add eax,ecx ; line 4 : EAX = 6, ECX = 3
pop eax ; line 5 : stack EAX = 1
ret
SumOf ENDP
- line 4에서 3개의 register의 합인 6이 EAX에 저장되지만
- line 5에서 이전에 stack에 EAX를 저장해둔 값을 다시 가져와서 초기값 1로 되돌아 간다.
cf> Program Design Using Procedures
Top-Down Design (functional decomposition)
- 코드를 작성하기 전에 프로그램을 디자인 함
- 큰 작업을 작은 작업들로 나눔
- 프로시저 호출에 의한 계층적 구조 사용
- 각각의 프로시저 테스트
cf> 어셈블리는 반환형을 특별히 특정할 필요가 없다.
어떤 register에 return값이 들어가있다 정도만 중요하다.