amiga-bootcamp/13_toolchain/fd_files.md
Ilia Sharin 21751c0025 docs(amiga): complete AmigaOS 3.1/3.2 developer reference — 172 files across 17 sections
Comprehensive technical documentation covering:
- Hardware: OCS/ECS/AGA custom chip registers, Copper & Blitter deep dives
- Boot sequence: cold boot through startup-sequence
- Binary format: HUNK executable spec, relocation, debug info
- Linking & ABI: .fd files, LVO tables, register calling conventions
- Exec kernel: tasks, interrupts, memory, signals, semaphores
- AmigaDOS: file I/O, FFS/OFS layout, CLI/Shell scripting
- Graphics: planar bitmaps, Copper programming, HAM/EHB modes
- Intuition: screens, windows, IDCMP, BOOPSI
- Devices: trackdisk, SCSI, serial, timer, audio, keyboard
- Libraries: utility, expansion, IFFParse, locale, ARexx
- Networking: bsdsocket API, SANA-II, TCP/IP stack comparison
- Toolchain: GCC, vasm/vlink, SAS/C, NDK, debugging
- Reverse engineering: IDA/Ghidra setup, compiler fingerprints, case studies
- CPU & MMU: 68040/060 emulation libs, PMMU, cache management
- Driver development: SANA-II, Picasso96/RTG, AHI audio

All files include breadcrumb navigation. No local paths or proprietary content.
2026-04-23 12:17:35 -04:00

5.3 KiB
Raw Blame History

← Home · Toolchain

FD/SFD Files — Function Definition Format and LVO Generation

Overview

FD files (Function Definition files) are the machine-readable specification of a library's public API. They define every function's name, LVO offset, and register argument mapping. FD files are the source of truth for generating pragma files, inline headers, and IDA LVO scripts.


File Location

NDK:fd/exec_lib.fd
NDK:fd/dos_lib.fd
NDK:fd/intuition_lib.fd
NDK:fd/graphics_lib.fd
NDK:sfd/exec_lib.sfd       (SFD = extended format with C prototypes)

FD File Syntax

* "exec.library"
##base _SysBase
##bias 30
##public
Supervisor(userFunction)(A5)
ExitIntr()()
Schedule()()
Reschedule()()
Switch()()
Dispatch()()
Exception()()
InitCode(startClass,version)(D0,D1)
InitStruct(initTable,memory,size)(A1,A2,D0)
MakeLibrary(funcInit,structInit,libInit,dataSize,segList)(A0,A1,A2,D0,D1)
MakeFunctions(target,functionArray,funcDispBase)(A0,A1,A2)
FindResident(name)(A1)
InitResident(resident,segList)(A1,D1)
Alert(alertNum)(D7)
Debug(flags)(D0)
##bias 120
Forbid()()
Permit()()
##bias 132
Disable()()
Enable()()
...

Syntax Rules

Element Meaning
* "name" Comment; library identity
##base _Symbol Global base pointer symbol name
##bias N Set current LVO offset to N
##public Following functions are public
##private Following functions are private (reserved)
FuncName(args)(regs) Function: name, C parameter names, register assignments
##end End of file

LVO auto-increment: After each function, the bias increases by 6 (one JMP instruction slot = 6 bytes).


SFD File Format (Extended)

SFD adds full C prototypes:

==id $Id: exec_lib.sfd,v 1.0 2003/01/01 00:00:00 Exp $
==base _SysBase
==basetype struct ExecBase *
==libname exec.library
==bias 30
==public
APTR Supervisor(ULONG (*userFunction)()) (A5)
==end

Parsing FD Files — Python Script

#!/usr/bin/env python3
"""parse_fd.py — Parse AmigaOS FD files into LVO tables.

Usage: python3 parse_fd.py exec_lib.fd [--json] [--ida]
"""
import re, sys, json, argparse

def parse_fd(path):
    """Parse an FD file and return list of (offset, name, args, regs)."""
    funcs = []
    bias = 30
    public = True
    
    with open(path) as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith('*'):
                continue
            if line.startswith('##base'):
                continue
            if line.startswith('##bias'):
                bias = int(line.split()[1])
                continue
            if line == '##public':
                public = True
                continue
            if line == '##private':
                public = False
                continue
            if line == '##end':
                break
            
            # Parse: FuncName(args)(regs)
            m = re.match(r'(\w+)\(([^)]*)\)\(([^)]*)\)', line)
            if m and public:
                name = m.group(1)
                args = [a.strip() for a in m.group(2).split(',') if a.strip()]
                regs = [r.strip() for r in m.group(3).split(',') if r.strip()]
                funcs.append({
                    'name': name,
                    'lvo': -bias,
                    'bias': bias,
                    'args': args,
                    'regs': regs
                })
            bias += 6  # always advance, even for private
    
    return funcs

def output_ida_script(funcs, base_name):
    """Generate IDA Python LVO dict."""
    print(f"# Auto-generated from FD file")
    print(f"LVO_{base_name} = {{")
    for f in funcs:
        print(f"    {f['lvo']:+5d}: \"{f['name']}\",")
    print("}")

def output_json(funcs):
    print(json.dumps(funcs, indent=2))

def output_table(funcs):
    print(f"{'LVO':>6}  {'Bias':>5}  {'Function':<30}  {'Registers'}")
    print(f"{'─'*6}  {'─'*5}  {'─'*30}  {'─'*30}")
    for f in funcs:
        regs = ', '.join(f['regs']) if f['regs'] else '(none)'
        print(f"{f['lvo']:>+6d}  {f['bias']:>5d}  {f['name']:<30}  {regs}")

if __name__ == '__main__':
    ap = argparse.ArgumentParser(description='Parse AmigaOS FD files')
    ap.add_argument('fdfile', help='Path to .fd file')
    ap.add_argument('--json', action='store_true', help='Output JSON')
    ap.add_argument('--ida', action='store_true', help='Output IDA script')
    args = ap.parse_args()
    
    funcs = parse_fd(args.fdfile)
    if args.json:
        output_json(funcs)
    elif args.ida:
        output_ida_script(funcs, args.fdfile.split('/')[-1].replace('_lib.fd',''))
    else:
        output_table(funcs)
    
    sys.stderr.write(f"Parsed {len(funcs)} public functions\n")

Where to Get NDK FD Files

NDK Source FD path
NDK 3.9 Aminet: dev/misc/NDK39.lha (free) NDK_3.9/Include/fd/
NDK 3.2 Hyperion (commercial, ~€30) NDK3.2/Include_H/fd/
NDK 3.1 Commodore (archived) NDK3.1/Include/fd/

Auto-Generating IDA LVO Labels

# Generate IDA script from all FD files:
for fd in NDK_3.9/Include/fd/*_lib.fd; do
    python3 parse_fd.py "$fd" --ida >> all_lvos.py
done

Then in IDA: File → Script command → Run all_lvos.py


References

  • NDK39: fd/ directory
  • 05_reversing/static/api_call_identification.md — using LVOs in RE