Relocatable object and executable format #27

Merged
bcox merged 12 commits from object-format into main 2026-04-14 23:16:18 +00:00
Owner

This PR introduces the S7B binary file format, which is an object file format with multiple chunk types. The PR7 (executable) format is a subset of the object format: it may not contain any relocation chunks.

This PR introduces the S7B binary file format, which is an object file format with multiple chunk types. The PR7 (executable) format is a subset of the object format: it may not contain any relocation chunks.
bcox added 12 commits 2026-04-14 23:07:13 +00:00
Documents the recommended memory layout, slot roles, entry convention,
cross-bank calling patterns (slot-0 trampolines + direct CALLFAR), and
bank allocation scheme for programs larger than ~8 KB. Includes a
worked example of a safe_extcall trampoline for the slot-7 sharp edge.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduce the S7B container format -- a compact binary alternative to
H7X2 for SBC7 programs.  PR7 files (.pr7) carry the same information
as H7X2 (segments with bank + origin, slot configuration, entry point)
in a chunk-based binary format that is roughly 5x more compact.

- docs/s7b.md: full format specification covering the shared S7B
  container, PR7 (program) and OB7 (relocatable object) file types,
  chunk structure, relocation model, and linking workflow
- src/asm7/src/s7b.rs: PR7 writer (write_pr7, generalised RXOR7
  checksum, 14-bit encoding, chunk serialisation)
- src/asm7/src/main.rs: detect .pr7 extension for output format
- src/emu7/src/s7b.rs: S7B reader (chunk parser, CODE/BSS/META
  loading, RELOC rejection for unlinked objects)
- src/emu7/src/bin/emu7.rs: wire PR7 loading into auto-load and
  manual load paths (program.pr7 checked before program.h7x)

The OB7 object format (SYMTAB, RELOC chunks), the link7 linker, and
the od7 object dump tool will follow in subsequent commits.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend the assembler to produce OB7 (relocatable object) files when
the output extension is .ob7.  OB7 files contain SYMTAB and RELOC
chunks alongside the CODE segments, enabling separate compilation and
linking.

New assembler directives:
- .global SYMBOL  -- mark a label as exported (visible to linker)
- .extern SYMBOL  -- declare an imported symbol (resolved by linker)

Relocation tracking:
- New reloc.rs module classifies expressions as constant, relocatable,
  bank-of, lo-byte, or hi-byte references
- analyze_instruction() examines JP, CALL, LD, LD14, ST, and ALU
  instructions for address-dependent operands
- .word and .byte directives also generate relocations when needed
- JR/DJNZ (PC-relative) are exempt from relocation

Symbol table enhancements:
- SymbolKind enum (Label, Equ, Extern) distinguishes relocatable symbols
  from constants
- is_relocatable() returns true for labels and externs, false for .equ
- mark_global() supports forward references (.global before label def)

OB7 output (s7b.rs):
- write_ob7() produces SYMTAB chunk with section symbols, exports,
  imports, and local labels
- RELOC chunks emitted per segment with 7-byte entries (type, offset,
  symbol index, addend)
- CODE chunks marked RELOCATABLE (flags=0x01)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New tool that reads S7B binary files and prints a human-readable dump,
similar to objdump for ELF.  Works on both PR7 (program) and OB7
(relocatable object) files.

Displays:
- File header (magic, version)
- All chunks with type, length, and checksum verification
- META: entry point and slot configuration
- CODE: flags, bank, origin, data size, hex preview
- SYMTAB: symbol table with flags, segment, value, and name
- RELOC: relocation entries with type, offset, symbol cross-reference
- BSS: zero-fill regions
- COMMENT: informational text

Symbol names from SYMTAB are cross-referenced in RELOC output for
readability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New tool that reads multiple OB7 files, resolves symbols, applies
relocations, and writes a fully-resolved PR7 program file.

Linker stages:
1. Place sections: fixed segments at specified addresses, relocatable
   segments concatenated sequentially within target slots
2. Build global symbol table: compute final addresses for all defined
   symbols, merge exports across files, detect duplicates
3. Resolve imports: match imported symbols against global exports
4. Apply relocations: patch R_ADDR14 (14-bit address), R_LO7 (low 7),
   R_HI7 (high 7), R_BANK (bank number) entries in section data
5. Merge adjacent segments within the same bank
6. Write PR7 output with fixed CODE chunks

Supports --entry and --slots overrides.  Reports input count, total
code size, and relocation count on success.

Verified end-to-end: asm7 -> link7 -> od7 with two test objects
sharing a slot, cross-file symbol references, and within-bank linking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Describes how to add PR7 (S7B binary) loading to the ROM monitor's
LD and X commands, including ROM reorganization to make space.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frees 177 bytes in bank 1 for the PR7 loader. The FARCALL from
the boot sequence becomes a direct CALL since both caller and
callee are now in the same bank. Removes the 8-bank RAM test
(minimum 16 banks required by ROM).

Also adds PR7 loader scratch variable definitions to constants.s.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The LD and X commands now accept both H7X and PR7 (S7B binary) files
transparently. After opening a file, the monitor peeks at the first
byte of the file buffer: if it is 'S' (0x53, the PR7 magic), it
FARCALLs to a new PR7 chunk parser in ROM bank 6; otherwise it falls
through to the existing H7X text parser.

The PR7 loader in rom_bank6.s validates the S7B header, iterates
chunks with RXOR7 checksum verification, loads CODE data into physical
banks via slot 2, handles META (entry point + slots) and BSS, rejects
RELOC chunks (unlinked object files), and skips unknown chunk types.

ROM_BANKS_CT updated from 6 to 7. Makefile updated to assemble and
include bank 6 in the ROM image (no more empty padding bank).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The OSD file picker now accepts both .H7X and .PR7 files. Format is
auto-detected from the first byte: 'S' selects the PR7 binary parser,
anything else falls through to the existing H7X ASCII parser.

The new pr7_loader module validates the S7B header, parses chunks in a
loop (CODE → DMA write, BSS → zero-fill, others → skip), and verifies
RXOR7 checksums on every chunk. BSS zero-fill runs at one word per
clock cycle with a 256-byte FIFO to buffer ioctl bytes during fill.
RELOC chunks are rejected (unlinked object files).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dev targets (forth, basic, lisp, example) and release targets now produce
.pr7 files instead of .h7x.  MiSTer distribution uses uppercase .PR7.
Factory disk image uses .pr7 on the S7FS volume.

New: file(1) magic definitions (assets/sbc7.magic) for H7X, S7B, and S7FS
formats, registered in /etc/magic by RPM %post/%postun and deb
postinst/postrm scriptlets.

New: SBC7 fonts (sbc7.ttf, sbc7.woff2) included in packages via
dist-assets target, installed to /usr/lib/sbc7/fonts/.

Both MIME types (application/x-sbc7-pr7 and application/x-sbc7-h7x) are
registered; emu7.desktop handles both.  Pattern rules for .h7x and .pr7
are both present.  make clean removes .h7x, .pr7, and .ob7.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix PR7 loader slot 2 overflow corrupting FS scratch bank
All checks were successful
PR Check / test (pull_request) Successful in 11m16s
PR Check / build-rpm (pull_request) Successful in 23m12s
33fe2455c8
The CODE and BSS write loops wrote through the 2048-byte slot 2
window without detecting boundary overflow.  Programs larger than
~1920 bytes (e.g. TinyBASIC at 4674 bytes) would spill from slot 2
(&2F:7F) into slot 3 (&30:00+), corrupting the FS scratch bank --
including the PR7 loader's own checksum and write-pointer variables.
This caused checksum mismatches ("?") and dirty FS state ("Not found"
on subsequent loads).

Fix: detect when write pointer G crosses &30, remap slot 2 to the
next sequential bank, and reset G to &20.  Applied to both
_pr7_code_loop and _pr7_bss_loop.

Also fix the monitor error path for PR7 failures: close the open
file and restore slots 2/3/4 before reporting the error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bcox merged commit 4a78772dee into main 2026-04-14 23:16:18 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
bcox/sbc7!27
No description provided.