amiga-bootcamp/05_reversing/static/m68k_codegen_patterns.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

4 KiB

← Home · Reverse Engineering

Compiler-Specific Code Generation Patterns

Overview

Different Amiga compilers produce distinct code signatures. Recognising these helps quickly identify compiler origin, locate main(), and distinguish OS glue from application logic.


SAS/C 6.x Patterns

Function Prologue / Epilogue

; Non-leaf function with local vars:
LINK    A5, #-N          ; allocate N bytes of locals on stack
MOVEM.L D2-D7/A2-A3, -(SP)  ; save preserved registers
...
MOVEM.L (SP)+, D2-D7/A2-A3
UNLK    A5
RTS

; Leaf function (no locals, no preserved regs):
; — no LINK, pure computation, ends in RTS

D0 Save Pattern

SAS/C saves D0 at the start of functions that need it later:

MOVE.L  D0, -(SP)       ; save return value from previous call
JSR     another_func
MOVE.L  (SP)+, D0       ; restore

Register Argument Passing

SAS/C passes OS call args via #pragma amicall register placement. Inside application functions, SAS/C uses a stack-based C ABI (unlike OS calls):

; C function call in SAS/C: push args right-to-left
MOVE.L  arg3, -(SP)
MOVE.L  arg2, -(SP)
MOVE.L  arg1, -(SP)
JSR     _myfunction
ADDQ.L  #12, SP         ; clean args (caller cleanup)

String Constants

SAS/C places string literals in the data hunk, referenced via absolute addresses requiring HUNK_RELOC32:

MOVE.L  #_str_hello, D1   ; absolute address → RELOC32 entry
MOVEA.L _DOSBase, A6
JSR     (-48,A6)           ; Write(stdout, "hello", ...)

GCC (m68k-amigaos / bebbo) Patterns

PC-Relative String Access

GCC uses PC-relative addressing by default, eliminating most HUNK_RELOC32 entries:

LEA     _str_hello(PC), A0   ; PC-relative — no reloc needed

No Frame Pointer (Default)

; GCC -O2 leaf function:
MOVEM.L D2/A2, -(SP)    ; only save what's used
...
MOVEM.L (SP)+, D2/A2
RTS
; No LINK/UNLK — pure register allocation

GCC Function Prologues

; Non-leaf with GCC -fno-omit-frame-pointer:
LINK    A6, #-N          ; note: GCC uses A6 as frame pointer here
                         ; (conflicts with OS library base usage — rare)
; More common with -O2:
SUBQ.L  #N, SP           ; allocate locals without frame pointer

Integer Division / Modulo

GCC emits calls to __divsi3, __modsi3 from libgcc:

JSR     ___divsi3        ; 32-bit signed divide (libgcc helper)
; operands in D0:D1, result in D0

SAS/C uses the 68k DIVS.L instruction directly (available on 020+) or DIVS.W.


VBCC Patterns

VBCC generates very tight code with minimal function overhead:

; VBCC typical function (no frame pointer, minimal saves):
MOVEM.L D2-D4, -(SP)
...
MOVEM.L (SP)+, D2-D4
RTS

VBCC's OS call inline expansion looks identical to GCC's inline-asm stubs.


Distinguishing Compiler Artefacts from Logic

Pattern Compiler Meaning
LINK A5, #-N SAS/C Function with locals
LINK A6, #-N GCC (rare) Frame pointer mode
JSR ___divsi3 GCC Software 32-bit division
DIVS.L D1, D0 SAS/C (020+) Hardware divide
MULS.L D1, D0 SAS/C (020+) Hardware multiply
LEA str(PC), A0 GCC PC-relative string ref
MOVE.L #_str, D1 SAS/C Absolute string ref (reloc'd)
JSR _main Startup C main() entry point
MOVE.L 4.W, A6 Startup SysBase load
JSR -552(A6) Any exec.library OpenLibrary

Locating main() via Startup Skip

After identifying the startup stub (MOVE.L 4.W, A6JSR _OpenLibraries):

  1. Find the first JSR or BSR after library opens
  2. That target is __main or directly _main
  3. If __main: follow its internal JSR _main call
  4. Label the target main in IDA

References