CodeToLive

Functions & Procedures in Assembly

Functions (also called procedures or subroutines) in assembly language allow you to organize code into reusable blocks. Proper function implementation requires understanding calling conventions, parameter passing, stack management, and register usage.

Basic Function Structure

A function in assembly typically has three parts:

  1. Prologue: Setup stack frame and save registers
  2. Function Body: Perform the actual work
  3. Epilogue: Clean up and return to caller

Simple Function Example


section .text
    global _start

; Function definition
my_function:
    ; Prologue
    push ebp            ; Save old base pointer
    mov ebp, esp        ; Set new base pointer
    
    ; Function body
    mov eax, 42         ; Do something
    
    ; Epilogue
    mov esp, ebp        ; Restore stack pointer
    pop ebp             ; Restore base pointer
    ret                 ; Return to caller

_start:
    call my_function    ; Call the function
    ; ... rest of program ...
      

Calling Conventions

Calling conventions define how functions are called and how parameters are passed. Common conventions:

cdecl (C Declaration)

stdcall

fastcall

Parameter Passing

Parameters can be passed via registers or the stack (or a combination).

Stack-based Parameter Passing


section .text
    global _start

; Function to add two numbers
add_numbers:
    push ebp
    mov ebp, esp
    
    mov eax, [ebp+8]    ; First parameter
    add eax, [ebp+12]   ; Second parameter
    
    mov esp, ebp
    pop ebp
    ret

_start:
    push 20             ; Push second parameter
    push 10             ; Push first parameter
    call add_numbers
    add esp, 8          ; Clean up parameters (cdecl)
    
    ; EAX now contains 30
      

Register-based Parameter Passing


section .text
    global _start

; Function to add two numbers (fastcall style)
add_numbers:
    push ebp
    mov ebp, esp
    
    mov eax, ecx        ; First parameter in ECX
    add eax, edx        ; Second parameter in EDX
    
    mov esp, ebp
    pop ebp
    ret

_start:
    mov ecx, 10         ; First parameter
    mov edx, 20         ; Second parameter
    call add_numbers
    
    ; EAX now contains 30
      

Return Values

Functions typically return values in registers:

Local Variables

Local variables are allocated on the stack by adjusting ESP:


my_function:
    push ebp
    mov ebp, esp
    sub esp, 12         ; Allocate space for 3 integers
    
    ; Access local variables
    mov dword [ebp-4], 10   ; First local
    mov dword [ebp-8], 20   ; Second local
    mov dword [ebp-12], 30  ; Third local
    
    ; ... use locals ...
    
    mov esp, ebp        ; Clean up locals
    pop ebp
    ret
      

Preserving Registers

According to calling conventions, some registers must be preserved across function calls:

Register Preservation Example


my_function:
    push ebp
    mov ebp, esp
    push ebx            ; Save EBX (callee-saved)
    push esi            ; Save ESI (callee-saved)
    
    ; Function body that uses EBX and ESI
    
    pop esi             ; Restore ESI
    pop ebx             ; Restore EBX
    mov esp, ebp
    pop ebp
    ret
      

Recursive Functions

Recursive functions follow the same rules but must carefully manage stack space:


section .text
    global _start

; Recursive factorial function
factorial:
    push ebp
    mov ebp, esp
    
    mov eax, [ebp+8]    ; Get parameter n
    cmp eax, 1
    jle base_case       ; if n <= 1, return 1
    
    ; Recursive case: n * factorial(n-1)
    dec eax
    push eax            ; Push n-1 as argument
    call factorial
    add esp, 4          ; Clean up argument
    
    imul dword [ebp+8]  ; Multiply by original n
    jmp end_factorial

base_case:
    mov eax, 1          ; Return 1 for base case

end_factorial:
    mov esp, ebp
    pop ebp
    ret

_start:
    push 5              ; Compute factorial(5)
    call factorial
    add esp, 4
    
    ; EAX now contains 120 (5!)
      

Function Pointers

Functions can be called indirectly through pointers:


section .data
    func_ptr dd my_function

section .text
    global _start

my_function:
    mov eax, 42
    ret

_start:
    call [func_ptr]     ; Call through function pointer
    ; EAX now contains 42
      

Variadic Functions

Functions with variable number of arguments require special handling:


section .text
    global _start

; Simple variadic sum function
variadic_sum:
    push ebp
    mov ebp, esp
    
    mov ecx, [ebp+8]    ; Get count of arguments
    mov eax, 0          ; Initialize sum
    lea edx, [ebp+12]   ; Pointer to first argument
    
sum_loop:
    add eax, [edx]      ; Add argument to sum
    add edx, 4          ; Move to next argument
    loop sum_loop
    
    mov esp, ebp
    pop ebp
    ret

_start:
    push 3              ; Push third argument
    push 2              ; Push second argument
    push 1              ; Push first argument
    push 3              ; Push argument count
    call variadic_sum
    add esp, 16         ; Clean up
    
    ; EAX now contains 6 (1+2+3)
      

Inline Assembly

Assembly functions can be called from high-level languages:


// C program calling assembly function
extern int assembly_function(int, int);

int main() {
    int result = assembly_function(10, 20);
    return 0;
}
      

; Corresponding assembly function
global assembly_function

assembly_function:
    push ebp
    mov ebp, esp
    
    mov eax, [ebp+8]    ; First parameter
    add eax, [ebp+12]   ; Second parameter
    
    mov esp, ebp
    pop ebp
    ret
      

Tail Call Optimization

When a function's last action is calling another function, the call can be optimized to a jump:


; Regular recursive call
factorial:
    ; ...
    call factorial
    ; ...
    ret

; Tail call optimized version
factorial_tail:
    ; ...
    jmp factorial_tail  ; Instead of call/ret
      

Function Macros

Macros can simplify function definitions:


%macro FUNCTION 1
    %1:
        push ebp
        mov ebp, esp
%endmacro

%macro ENDFUNCTION 0
        mov esp, ebp
        pop ebp
        ret
%endmacro

FUNCTION my_function
    mov eax, 42
ENDFUNCTION
      

Common Pitfalls

Next Steps

Now that you understand functions, you can learn about: