어셈블리에서는 함수라는 표현을 잘 사용하지 않는다.
주로 프로시저와 서브루틴이라고 표현한다. 하지만 해당 강의의 목표는 C++이기 때문에 함수로 표현한다.
기본적으로 함수를 사용하는 이유는 반복적으로 일어나야하는 계산, 특정 조건에 맞는 값을 출력 등을 위해 사용한다.
아래 코드는 간단하게 PRINT_MSG 함수를 만든 예이다.
main:
mov rbp, rsp; for correct debugging
; 함수 (프로시저 procedure 서브루틴 subroutine)
call PRINT_MSG
xor rax, rax
ret
PRINT_MSG:
PRINT_STRING msg
NEWLINE
ret
section .data
msg db 'Hello World', 0x00
해당 코드 동작 순서는
1. call PRINT_MSG를 부른다
2. PRINT_MSG 라벨로 내려가 msg를 PRINT한다
3. PRINT_MSG 안의 ret를 통해 call이 끝난 곧으로 돌아온다.
4. xor rax, rax와 ret를 실행하고 종료한다.
이처럼 call 은 해당 Label로 갔다가 끝나면 다시 call의 원 위치로 돌아오는 역할을 한다.
이를 이용하여 Max를 구분하는 함수를 만들어보자
mov eax, 10
mov ebx, 15
call MAX
PRINT_DEC 4, ecx
NEWLINE
xor rax, rax
ret
MAX:
cmp eax, ebx
jg L1
mov ecx, ebx
jmp L2
L1:
mov ecx, eax
L2:
ret
위 함수는 eax와 ebx의 값을 비교하여 더 큰 값을 ecx에 적용하여 출력해주는 함수이다.
순서는
1. Max 라벨로 이동
2. 두 값을 비교
3. eax가 크다면 L1으로 그렇지 않다면 ebx를 ecx에 저장
3-1. L1으로 갔다면 eax를 ecx에 저장
4. 이후 L2로 return 하며 종료
함수는 위와 같이 동작한다.
그리고 함수를 만들면서 고려해야할 부분들이 있다.
우리는 지금 굉장히 단순한 함수만 만들고 있지만 실제 프로젝트에서는 더 많은 함수와 더 많은 변수를 만나게 될 것이다.
아래 질문에 대해 고민해보자
그런데 인자가 10개라면 어떻게 할까? eax, ebx에 이미 중요한 값이 있으면 어떻게 할까? [!] .data, .bss 를 사용하면? 인자를 도대체 몇개를 할당해야 하지? 다른 메모리 구조가 필요함 해당 함수 안에 있는 동안에는 함수의 변수를 유지시켜줘야함 (유효범위) 함수가 끝난 후에는 상관이 없다 (정리의 개념) 함수 안에서 또 다른 함수를 호출하는 것도 고려해야함 (유동적으로 유효범위가 확장됨)
[!] 스택(stack이라는 메모리 영역을 사용
함수가 사용하는 일종의 메모장
- 매개 변수 전달
- 돌아갈 주소 관리
스택이 오랜만에 다시 언급됐다. stack과 heap영역에 대한 차이를 다시 한번 찾아보고 오자.
이제 어셈블리가 한 강의만 남았다. 배우다보니 느낀 것은 어셈블리라고 하기엔 너무 부족하고 레지스터가 어떻게 동작하는가 우리가 값을 어떻게 저장하고 어떻게 불러오는가에 대한 부분이 더 많았던 것으로 생각된다. 앞으로도 잊지 말아야할 기초이다. -끝-