Skip to content

feat(asm): 6502 relocating linker — object modules, relocation, and symbol resolution #112

Description

@relmer

Goal

Casso's assembler emits one absolutely located image. A linker would let it
consume separately assembled modules with unresolved cross-module references,
choose a final address for each, fix up address operands, and match imports to
exports.

Captured for later — this is the seed, not the spec. Sequenced after
specs/020-disk-file-access.

Why it matters: three consumers, one linker

This is the reason it is worth building rather than three separate hacks.

  1. Merlin relocatable modules (specs/019-assembler-dialects). Merlin
    shipped a Relocating Linker; Merlin Pro "supports both Entry and External
    Label Definitions for use with the Relocating Linker," and the package
    advertised generating "relocatable object code, library routines, run time
    packages." 019 scopes to absolute Merlin and refuses REL / ENT / EXT
    with a named diagnostic (019 FR-016..FR-019). A linker widens that boundary.
  2. ca65 (specs/023-ca65-dialect). Real ca65 projects assume ld65:
    .import / .export / .segment plus a linker configuration naming memory
    areas. 023 scopes to the absolute subset and states plainly that most
    published ca65 projects will not assemble unmodified. This is the single
    biggest lever on that limitation.
  3. Relocatable object output (feat(asm): relocatable object output (o65 / ELF) #58), which is the same machinery from the
    producing side.

Both 019 and 023 define their subset boundary as data in one place
(019 FR-019, 023 FR-012) specifically so it can widen when this lands, rather
than requiring scattered checks to be hunted down.

Rough shape

  • Object module format: emitted code plus relocation records ("the operand at
    offset N is an address; adjust by the module's final base") and a symbol table
    of exports and unresolved imports.
  • Symbol resolution across modules, with duplicate-definition and
    unresolved-reference diagnostics that name the module.
  • Address assignment per module. For ca65 fidelity this needs a segment /
    memory-area configuration; for Merlin fidelity it needs far less.
  • Library archives (Merlin's "library routines" case).
  • A debug-info story that survives relocation, so listings and symbol files stay
    useful.

Scope questions to settle in the spec

  • Does Casso define its own object format, or target an existing one (Merlin
    REL, ca65 .o, o65 per feat(asm): relocatable object output (o65 / ELF) #58)? Reading someone else's format is a compatibility
    win and a constraint.
  • Is the linker a separate subcommand or folded into assembly? Merlin 32 links
    internally with no intermediate files; cc65 keeps ld65 separate.
  • How much of ca65's linker-config language is in scope? This is where the cost
    concentrates.

Non-goals

  • Not required by the developer build loop in 020. A 6502 program cannot exceed
    the 64 KB address space, so a modern host never needs a linker for capacity —
    only for modularity, libraries, and dialect compatibility.
  • Not a prerequisite for 019 or 023; both ship with a documented boundary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestimpact: user (developer)Developer persona: writing 6502 code with the assembler / CLI / debuggerpriority: lowDev / power-user / infrastructure (end-user-value triage)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions