amiga-bootcamp/05_reversing/static/compilers/lattice_c.md

153 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[← Home](../../../README.md) · [Reverse Engineering](../../README.md) · [Static Analysis](../README.md) · [Compilers](README.md)
# Lattice C 3.x/4.x — Reverse Engineering Field Manual
## Overview
**Lattice C** (versions 3.x4.x, 19851989) is the direct predecessor to SAS/C. When SAS Institute acquired the Lattice C product line in 1988, they rebranded version 5.0 as "SAS/C". Lattice C 3.x and 4.x binaries represent the first generation of commercial C compilers for AmigaOS. Their code generation is recognizably similar to SAS/C but with less aggressive optimization and some distinct early patterns.
Key constraints:
- **The transition point**: Lattice C 3.x → 4.x → SAS/C 5.x form a continuous evolution. Code from 3.x looks noticeably "early" — simpler register allocation, less peephole optimization, longer function prologues.
- **LINK A5 + D2-D5/A2-A3 save** — Lattice C 3.x typically saves fewer registers than SAS/C (D2-D5 + A2-A3, 6 registers total) but more than Aztec C (5 regs, data only).
- **Startup code evolution** — Lattice C 3.x's `lc.o` startup is simpler than SAS/C's `c.o` — may not handle Workbench launches correctly, may not support `argc`/`argv` parsing.
- **Hunk names**: `CODE`, `DATA`, `BSS` (same as SAS/C — established this convention)
```asm
; Lattice C 3.x function prologue (less aggressive than SAS/C):
_func:
LINK A5, #-$14
MOVEM.L D2-D5/A2-A3, -(SP) ; 4 data + 2 address = 6 registers
; Compare: SAS/C saves D2-D7/A2-A4 (9 registers)
; Compare: Aztec C saves D3-D7 only (5 registers, data only)
```
---
## Binary Identification — Lattice C vs SAS/C
| Criterion | Lattice C 3.x | Lattice C 4.x | SAS/C 5.x/6.x |
|---|---|---|---|
| **Register save** | D2-D5, A2-A3 (6 regs) | D2-D6, A2-A3 (7 regs) | D2-D7, A2-A4 (9 regs) |
| **D6/D7 usage** | Rarely used | Sometimes used | Frequently used |
| **Peephole optimization** | Minimal | Moderate | Aggressive |
| **MOVEQ for small values** | Inconsistent | Common | Always |
| **Stack frame** | LINK A5 always | LINK A5 always | LINK A5 always |
| **Library calls** | `JSR -$XXX(A6)` | `JSR -$XXX(A6)` | `JSR -$XXX(A6)` |
| **Startup** | `lc.o` (simpler) | `lc.o` (improved) | `c.o` (full-featured) |
| **Era** | 19851987 | 19871989 | 19881996 |
### Evolutionary Markers
The Lattice→SAS/C evolution is visible in the binary:
1. **Register save set grows** — 6→7→9 registers as the optimizer learned to use more registers effectively
2. **MOVEQ adoption** — Lattice 3.x uses `MOVE.L #0, D0`; Lattice 4.x uses `MOVEQ #0, D0`; SAS/C always uses MOVEQ
3. **Library call density** — Lattice 3.x loads A6 before every single library call; SAS/C may reuse A6 across calls
4. **Stack frame size** — Lattice 3.x often allocates oversized frames (locals * sizeof(LONG) rounded up to nice boundary)
---
## Historical Context
Lattice, Inc. was an early cross-platform compiler vendor. Their C compiler for the Amiga was the first commercially viable option, shipping in 1985. Commodore itself used Lattice C for some system development before adopting SAS/C.
Key timeline:
- **1985**: Lattice C 3.0 — first commercial Amiga C compiler
- **1986**: Lattice C 3.1 — improved optimizer, bug fixes
- **1987**: Lattice C 4.0 — major update, AmigaOS 1.2 support
- **1988**: SAS Institute acquires Lattice C product line
- **1989**: Rebranded as SAS/C 5.0
Any binary from 19851989 is likely Lattice C. After 1989, the brand transitioned to SAS/C, though Lattice C was still sold through existing channels for a time.
Software likely compiled with Lattice C:
- Commodore's early Amiga utilities (19851986)
- Early third-party tools like `DiskMon`, `CLImate`, `Memacs`
- Amiga 1000 launch-era software
- Early versions of `ARP` (AmigaDOS Replacement Project) components
- Early `WShell` / `ZShell` versions
---
## Same C Function — Lattice C Output
```asm
; CountWords() — Lattice C 4.x:
; (Notably simpler than SAS/C — less aggressive optimizer)
_CountWords:
LINK A5, #-$08
MOVEM.L D2-D4/A2, -(SP) ; 4 regs saved (D2-D4 + A2)
; Note: A2 saved even though it's not used — Lattice C saves a fixed set
MOVEQ #0, D2 ; D2 = count
MOVEQ #0, D3 ; D3 = in_word
MOVEA.L $08(A5), A0 ; A0 = str
BRA .loop_test ; Lattice C uses BRA (long), not BRA.S
.loop_body:
MOVE.L #' ', D0 ; MOVE.L for char constant (should be MOVEQ!)
CMP.B (A0), D0
BEQ .not_word ; BEQ (long), not BEQ.S
MOVE.L #'\t', D0
CMP.B (A0), D0
BEQ .not_word
MOVE.L #'\n', D0
CMP.B (A0), D0
BEQ .not_word
TST.B D3
BNE .next_char
ADDQ.L #1, D2
MOVEQ #1, D3
BRA .next_char
.not_word:
MOVEQ #0, D3
.next_char:
ADDQ.L #1, A0
.loop_test:
TST.B (A0)
BNE .loop_body
MOVE.L D2, D0
MOVEM.L (SP)+, D2-D4/A2
UNLK A5
RTS
```
**Lattice C observations**:
1. **`MOVE.L #' ', D0`** instead of `MOVEQ #' ', D0` — Lattice C doesn't always use MOVEQ for constants that fit in 8 bits. This wastes 2 bytes and 4 cycles per constant load.
2. **`BRA`/`BEQ`/`BNE`** (long, 4-byte) instead of `BRA.S`/`BEQ.S`/`BNE.S` (short, 2-byte) — Lattice C's branch target distance calculation is conservative.
3. **A2 saved but unused** — Lattice C saves a fixed register set rather than analyzing which registers are actually needed.
---
## Differences from SAS/C — Summary
```
Lattice C 3.x/4.x → SAS/C 5.x/6.x improvements visible in disassembly:
✓ MOVEQ substituted for MOVE.L #small_const
✓ BRA.S/BEQ.S/BNE.S used where target is within 8-bit range
✓ Dead register saves eliminated (per-function save analysis)
✓ Common subexpression elimination (CSE) more aggressive
✓ Loop induction variables kept in registers, not on stack
✓ Struct copy inlined as MOVE.L (A0)+, (A1)+ for small structs
✓ Tail-call optimization in some cases (rare but present in SAS/C 6.x)
```
---
## References
- [compiler_fingerprints.md](../../compiler_fingerprints.md) — Quick identification
- *Lattice C 3.x/4.x Manual* (archive.org)
- See also: [sasc.md](sasc.md) — SAS/C (direct successor)
- See also: [aztec_c.md](aztec_c.md) — contemporary competitor