어셈블리어 프로그램은 크기가 큰 경향이 있으므로 프로시저 또는 서브루틴은 어셈블리어에서 매우 중요하다. 프로시저는 이름으로 구분된다. 가장 먼저 프로시저 이름을 쓰고, 다음에 프로시저가 수행할 작업이 기술된 프로시저 바디를 작성한다. 마지막으로 return문으로 프로시저의 끝을 표시한다.
프로시저를 정의하는 구문은 다음과 같다.
proc_name:
procedure body
...
ret
프로시저는 CALL 명령어를 사용하여 다른 함수에서 호출할 수 있다. CALL 명령어는 호출하고자 하는 프로시저의 이름을
인자로 받아야 한다.
CALL proc_name
호출된 프로시저는 RET 명령어로 호출한 프로시저에게 제어권을 반환한다.
아주 간단한 sum 프로시저를 작성한다. sum 프로시저는 ECX, EDX 레지스터에 저장된 변수를 add하고 EAX 레지스터로 합을 반환한다.
❗️ 64비트 Intel macOS에서 동작하는 코드이다.
section .text
global _main
_main:
mov ecx, '4'
sub ecx, '0'
mov edx, '5'
sub edx, '0'
call sum ; sum 프로시저 호출
mov r10, res
mov [r10], eax
mov rsi, msg
mov rdx, len
mov rdi, 1
mov rax, 0x2000004
syscall
mov rsi, res
mov rdx, 1
mov rdi, 1
mov rax, 0x2000004
syscall
mov rax, 0x2000001
mov rdi, 0
syscall
sum:
mov eax, ecx
add eax, edx
add eax, '0'
ret
section .data
msg db "The sum is:", 0xA, 0xD
len equ $ - msg
section .bss
res resb 1
코드를 컴파일하고 실행하면 다음과 같은 결과를 확인할 수 있다.
The sum is:
9
스택은 메모리 내에 배열과 같은 데이터 구조로 이루어져있다. 스택의 top이라고 불리는 위치를 통해 데이터가 저장되고 삭제된다. 스택에 push하여 데이터를 저장하고 pop하여 데이터를 꺼낸다. 스택은 LIFO 데이터 구조이다. 즉, 먼저 저장된 데이터가 나중에 제거된다.
어셈블리어는 스택의 두 가지 명령어를 제공한다. : PUSH, POP. 이 명령어들의 구문은 다음과 같다.
PUSH operand
POP address/register
스택 세그먼트 안에 할당된 메모리 공간은 실행 스택을 위해 사용된다. 레지스터 SS와 ESP(또는 SP)는 스택을 실행하는데 사용된다. 스택에 삽입된 마지막 데이터를 가리키는 top은 SS:ESP 레지스터로 접근할 수 있다. 여기서 SS 레지스터는 스택 세그먼트의 시작을 가리키고 SP(또는 ESP)는 스택 세그먼트의 오프셋을 의미한다.
스택 실행은 다음의 특징을 가진다.
다른 목적으로 레지스터를 사용하기 전에 스택에 기존 레지스터의 값을 저장한다. 코드는 다음과 같다.
; 스택에 AX, BX 레지스터를 저장한다.
PUSH AX
PUSH BX
; 다른 목적으로 레지스터를 사용한다.
MOV AX, VALUE1
MOV BX, VALUE2
..
MOV VALUE1, AX
MOV VALUE2, BX
; 레지스터를 원래 값으로 되돌린다.
POP BX
POP AX