Tutorial 09: FreshLib Macros

0
#
94
27.12.2025

Tutorial 09: FreshLib Macros

Overview

FreshLib provides a powerful set of macros that simplify assembly programming by handling common patterns like procedure definitions, data declarations, and calling conventions. This tutorial covers the essential macros used throughout FreshLib and AsmBB.

Topics Covered

  1. Procedure Macros - proc, endp, begin, return

  2. Data Declaration - iglobal, uglobal, endg, text

  3. Calling Convention - stdcall, invoke

  4. Structure Definitions - struct, rstruct, ends

  5. Initialization - InitializeAll, FinalizeAll

  6. Hash Tables - PHashTable, phash


Procedure Macros

proc / endp / begin / return

The proc macro defines a procedure with automatic stack frame management:

proc MyFunction, .param1, .param2
begin
        mov     eax, [.param1]
        add     eax, [.param2]
        return
endp

Key Points:

  • Parameters MUST start with a dot (.param1, .param2)

  • begin sets up the stack frame (push ebp; mov ebp, esp)

  • return restores the stack and returns (leave; ret)

  • Local variables use negative offsets from EBP

Local Variables

proc Example, .input
.localVar dd ?          ; Local variable (4 bytes)
.buffer   rb 256        ; Local buffer (256 bytes)
begin
        mov     [.localVar], 42
        return
endp

NOTE

Local variables are defined BEFORE begin and AFTER the parameter list.


Data Declaration Macros

iglobal / uglobal / endg

These macros separate initialized and uninitialized data:

; Initialized data (goes into .data section)
iglobal
  cMessage    text "Hello, World!", 13, 10
  nVersion    dd 100
endg

; Uninitialized data (goes into .bss section, no space in binary)
uglobal
  hBuffer     dd ?
  szTempPath  rb 256
endg

AsmBB Usage Example (from version.asm):

iglobal
  cVersion text VERSION_STRING
endg

text Macro

Creates zero-terminated strings with optional escape sequences:

iglobal
  cHeader text "Content-Type: text/html", 13, 10, 13, 10
  cError  text "Error: ", 0
endg

Inline Usage with stdcall:

stdcall FileWriteString, [STDOUT], txt "Hello!", 13, 10

CAUTION

The txt shorthand creates anonymous labels. For complex code, prefer explicit iglobal blocks.


Calling Convention: stdcall

Basic Usage

stdcall FunctionName, arg1, arg2, arg3

The stdcall macro:

  1. Pushes arguments right-to-left

  2. Calls the function

  3. Callee cleans up the stack

Return Values

  • EAX = Primary return value

  • EDX = Secondary return value (e.g., new pointer after reallocation)

  • CF (Carry Flag) = Error indicator (set on failure)

WARNING

Critical: stdcall does NOT preserve EAX, ECX, EDX. Always save them if needed later!

; ❌ WRONG
stdcall StrPtr, ebx
stdcall FileWriteString, 1, eax     ; EAX was destroyed!

; ✅ CORRECT
stdcall StrPtr, ebx
push    eax
stdcall FileWriteString, 1, msg
pop     eax
stdcall FileWriteString, 1, eax

Structure Definitions

struct / ends

Standard structures with positive offsets:

struct TArray
  .count     dd ?
  .capacity  dd ?
  .itemsize  dd ?
  .lparam    dd ?
  label .array dword
ends

Usage:

mov     eax, [ebx+TArray.count]

rstruct (Reverse Structure)

For structures accessed with negative offsets (like TText, string):

rstruct string
  .capacity dd ?
  .len      dd ?
  .         rb 0            ; String data starts here
ends

Why Reverse? The pointer points to the DATA, not the header. Access header with negative offsets:

mov     eax, [esi+string.len]       ; This is actually [esi-4]!

Initialization Macros

InitializeAll / FinalizeAll

Automatically call all registered initialization/finalization functions:

start:
        InitializeAll           ; Initialize FreshLib subsystems

; ... your code ...

        FinalizeAll             ; Cleanup
        stdcall TerminateAll, 0

How It Works: Libraries register themselves with the initialize directive:

initialize InitStrings          ; From strlib.asm

Hash Table Macros

PHashTable

Creates a compile-time static hash table using Pearson's hash:

; First, define a Pearson table (256 random bytes)
tpl_func:
        db 148, 24, 71, 46, ... (256 bytes total)

; Then define the hash table
PHashTable tableCommands, tpl_func, \
        "help", ProcHelp, \
        "exit", ProcExit, \
        "list", ProcList

Lookup (compile-time constant):

htHelp phash tpl_func, "help"           ; Compute hash at compile time
mov    eax, [tableCommands + 8*htHelp + 4]  ; Get value

AsmBB Usage (from api.asm):

PHashTable tableAPICommands, tblPreCommands, \
        "threads",      apiThreads, \
        "posts",        apiPosts, \
        "search",       apiSearch

Demo Programs

Demo 24: Procedure Basics

File: demo24_proc_basics.asm

Demonstrates proc, endp, begin, return, and local variables.

Demo 25: Data Macros

File: demo25_data_macros.asm

Demonstrates iglobal, uglobal, text, and their proper usage patterns.


Critical Implementation Notes

CAUTION

Register Clobbering: FreshLib uses the stdcall convention where EAX, ECX, EDX are caller-saved. EBX, ESI, EDI, EBP are callee-saved.

Common Patterns

Pattern Usage
push eax / pop eax Preserve return values across calls
mov ebx, edx Update handle after reallocation
jc .error Check for errors (carry flag)
test eax, eax / jz .null Check for NULL returns

Building and Running

cd 09-macros
./build.sh

Reference

  • FreshLib Macros: freshlib/macros/

    • _stdcall.inc - Procedure and calling macros

    • _globals.inc - Data declaration macros

    • _struct.inc - Structure macros

    • _minihash.inc - Hash table macros

  • AsmBB Examples:

    • asmbb/source/api.asm - PHashTable usage

    • asmbb/source/engine.asm - proc/endp patterns

    • asmbb/source/version.asm - iglobal/text usage

93
27.12.2025
; _______________________________________________________________________________________
;|                                                                                       |
;| ..:: FreshLib Tutorials ::..                                                          |
;|_______________________________________________________________________________________|
;
;  Description: Tutorial 09, Demo 24: Procedure Basics.
;  Demonstrates: proc, endp, begin, return, local variables, stdcall
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; Initialized Data
; ========================================
iglobal
  msg_title    text "--- Demo 24: Procedure Basics ---", 13, 10, 13, 10
  msg_demo1    text "AddNumbers(10, 25) = "
  msg_demo2    text "ComputeWithLocal(100) = "
  msg_demo3    text "SafeDivide(100, 0) = "
  msg_ok       text "OK (no error)", 13, 10
  msg_err      text "ERROR (division by zero caught!)", 13, 10
  msg_crlf     text 13, 10
  msg_complete text 13, 10, "Demo complete!", 13, 10
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll
        stdcall FileWriteString, [STDOUT], msg_title

; Demo 1: Simple procedure with parameters
        stdcall FileWriteString, [STDOUT], msg_demo1
        stdcall AddNumbers, 10, 25
        push    eax
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        push    eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        pop     eax
        stdcall StrDel, eax
        stdcall FileWriteString, [STDOUT], msg_crlf

; Demo 2: Procedure with local variables
        stdcall FileWriteString, [STDOUT], msg_demo2
        stdcall ComputeWithLocal, 100
        push    eax
        stdcall NumToStr, eax, ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        push    eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        pop     eax
        stdcall StrDel, eax
        stdcall FileWriteString, [STDOUT], msg_crlf

; Demo 3: Procedure returning error status
        stdcall FileWriteString, [STDOUT], msg_demo3
        stdcall SafeDivide, 100, 0
        jc      .div_error
        stdcall FileWriteString, [STDOUT], msg_ok
        jmp     .done

.div_error:
        stdcall FileWriteString, [STDOUT], msg_err

.done:
        stdcall FileWriteString, [STDOUT], msg_complete
        FinalizeAll
        stdcall TerminateAll, 0

; =========================================
; PROCEDURE EXAMPLES
; =========================================

; Simple procedure with two parameters
; Returns: EAX = sum of param1 and param2
proc AddNumbers, .param1, .param2
begin
        mov     eax, [.param1]
        add     eax, [.param2]
        return
endp

; Procedure with local variable
; Returns: EAX = input * 2 + 10
proc ComputeWithLocal, .input
.temp   dd ?                    ; Local variable
begin
        mov     eax, [.input]
        shl     eax, 1          ; eax = input * 2
        mov     [.temp], eax    ; Store in local
        add     eax, 10         ; eax = temp + 10
        return
endp

; Procedure that can return an error
; Returns: EAX = dividend / divisor, CF=0 on success
;          CF=1 if divisor is zero
proc SafeDivide, .dividend, .divisor
begin
        mov     ecx, [.divisor]
        test    ecx, ecx
        jz      .error

        mov     eax, [.dividend]
        xor     edx, edx
        div     ecx
        clc                     ; Clear carry = success
        return

.error:
        stc                     ; Set carry = error
        return
endp
92
27.12.2025
; _______________________________________________________________________________________
;|                                                                                       |
;| ..:: FreshLib Tutorials ::..                                                          |
;|_______________________________________________________________________________________|
;
;  Description: Tutorial 09, Demo 25: Data Declaration Macros.
;  Demonstrates: iglobal, uglobal, endg, text, var
;_________________________________________________________________________________________

include "%lib%/freshlib.inc"

LINUX_INTERPRETER equ './ld-musl-i386.so'

@BinaryType console, compact
LIB_MODE equ NOGUI

options.DebugMode = 0

include "%lib%/freshlib.asm"

; ========================================
; Initialized Data (iglobal)
; Goes into .data section - takes space in binary
; ========================================
iglobal
; String constants using 'text' macro
  cAppName    text "FreshLib Tutorial Application"
  cSourceStr  text "Hello from buffer!"

; Numeric constants
  nVersion    dd 157
  nMaxItems   dd 1024

; Message strings
  msg_title    text "--- Demo 25: Data Declaration Macros ---", 13, 10, 13, 10
  msg_demo1    text "cAppName (iglobal/text): "
  msg_demo2    text "nVersion (iglobal/dd):   "
  msg_demo3    text "szBuffer (uglobal/rb):   "
  msg_demo4    text "Inline txt macro:        "
  msg_crlf     text 13, 10
  msg_complete text 13, 10, "Demo complete!", 13, 10
endg

; ========================================
; Uninitialized Data (uglobal)
; Goes into .bss section - NO space in binary!
; ========================================
uglobal
; Buffer for runtime data
  szBuffer    rb 256            ; Reserve 256 bytes

; Handles and pointers
  hTempHandle dd ?              ; 4 bytes, uninitialized
  pDataPtr    dd ?
endg

; ========================================
; Entry Point
; ========================================
start:
        InitializeAll
        stdcall FileWriteString, [STDOUT], msg_title

; Demo 1: Show initialized data
        stdcall FileWriteString, [STDOUT], msg_demo1
        stdcall FileWriteString, [STDOUT], cAppName
        stdcall FileWriteString, [STDOUT], msg_crlf

; Demo 2: Show version number
        stdcall FileWriteString, [STDOUT], msg_demo2
        stdcall NumToStr, [nVersion], ntsDec or ntsUnsigned
        push    eax
        stdcall StrPtr, eax
        push    eax
        stdcall FileWriteString, [STDOUT], eax
        pop     eax
        pop     eax
        stdcall StrDel, eax
        stdcall FileWriteString, [STDOUT], msg_crlf

; Demo 3: Use uninitialized buffer
        stdcall FileWriteString, [STDOUT], msg_demo3

; Copy string to buffer
        mov     esi, cSourceStr
        lea     edi, [szBuffer]
        mov     ecx, cSourceStr.length + 1
        rep     movsb

; Print from buffer
        lea     eax, [szBuffer]
        stdcall FileWriteString, [STDOUT], eax
        stdcall FileWriteString, [STDOUT], msg_crlf

; Demo 4: Using inline txt
        stdcall FileWriteString, [STDOUT], msg_demo4
        stdcall FileWriteString, [STDOUT], txt "This uses 'txt' inline!", 13, 10

        stdcall FileWriteString, [STDOUT], msg_complete
        FinalizeAll
        stdcall TerminateAll, 0

Tutorial 09: FreshLib Macros

0
#