Skip to content

fix(assembler): correct RCALL label offset + accept avr-gcc assembly syntax#8

Merged
begeistert merged 1 commit into
mainfrom
fix/assembler-rcall-and-gcc-frontend
Jun 24, 2026
Merged

fix(assembler): correct RCALL label offset + accept avr-gcc assembly syntax#8
begeistert merged 1 commit into
mainfrom
fix/assembler-rcall-and-gcc-frontend

Conversation

@begeistert

Copy link
Copy Markdown
Collaborator

Found via clean-room differential testing: assemble the same source with our assembler and with avr-as (assemble and link, so R_AVR_13_PCREL relocations are applied), then compare byte-for-byte. The oracle also runs real avr-gcc -Os -S output through both toolchains.

Correctness bug: RCALL with a label

RCALL computed the PC-relative displacement from the current instruction instead of the next one — it omitted the byteLoc + 2 reference that RJMP already passed to ConstOrLabel. Only label operands were affected; numeric offsets were already the relative value, which is why the existing numeric-only tests never caught it.

Case Before avr-as (linked)
loop: rcall loop 00 d0 ff df ✅ now
rcall fwd; nop; fwd: 02 d0 01 d0 ✅ now

RJMP and every brXX branch already matched avr-as and are unchanged.

avr-gcc / avr-as front-end compatibility

The instruction encoder was already correct; these were front-end gaps that blocked feeding real avr-gcc .S output:

  • GNU local labels (.L0:, .L2:) parsed as labels, not directives; forward references resolve in pass two (the expression evaluator now accepts dotted symbol tokens).
  • GNU name = value assignment (no .equ): __SP_H__ = 0x3e, .L__stack_usage = 2.
  • Negative 8-bit immediates via two's complement (avr-as allows -128..255): ldi r16,-10f ef.
  • C-style /* … */ block comments stripped before parsing (newlines preserved so line numbers stay accurate).
  • . location counter in relative branches: rcall . / rjmp . encode offset 0 (the avr-gcc stack-reserve idiom), matching avr-as.
  • avr-gcc metadata directives (.file/.section/.type/.size/.ident/.weak/.globl/.p2align/…) accepted as no-ops; genuinely unknown directives are still reported as errors.
  • Numeric symbol in register position resolves to that register, so avr-gcc's __zero_reg__ = 1 / __tmp_reg__ = 0 work as r1/r0.

Validation

Real avr-gcc -Os -S output for several C programs (GPIO, loops, arithmetic, functions, switch, bit ops) now assembles byte-identical to the GNU toolchain (assembled + linked).

Remaining gaps are linker-domain and out of scope for the flat code-image assembler: data symbols in .data/.bss (no RAM-address model) and libgcc calls (__mulhisi3, …) — both require a linker.

Adds 12 regression tests. 484 tests pass (472 previous + 12 new), no regressions.

🤖 Generated with Claude Code

…syntax

Found via clean-room differential testing against avr-as (assemble + link,
so R_AVR_13_PCREL relocations are applied) and avr-gcc -Os -S output.

RCALL bug: RCALL with a label operand computed the PC-relative displacement
from the current instruction instead of the next one, because it omitted the
`byteLoc + 2` reference that RJMP already passed to ConstOrLabel. Only label
operands were affected (numeric offsets were already the relative value), so
the existing numeric-only tests never caught it. Verified against avr-as:
`loop: rcall loop` => ffdf, `rcall fwd; nop; fwd:` => 01d0.

avr-gcc / avr-as front-end compatibility (the encoder was already correct;
these are front-end gaps that blocked feeding real avr-gcc .S output):

- GNU local labels (.L0:, .L2:) are now parsed as labels, not directives;
  forward references resolve in pass two via the expression evaluator, which
  now accepts dotted symbol tokens.
- GNU `name = value` symbol assignment (no .equ keyword) is supported, e.g.
  `__SP_H__ = 0x3e`, `.L__stack_usage = 2`.
- Negative 8-bit immediates (ldi/subi/sbci/andi/ori/cpi) are accepted via
  two's complement (avr-as allows -128..255): `ldi r16,-1` => 0fef.
- C-style /* ... */ block comments are stripped before parsing (newlines
  preserved so reported line numbers stay accurate).
- '.' location counter in relative branches: `rcall .` / `rjmp .` encode
  offset 0 (the avr-gcc stack-reserve idiom), matching avr-as.
- avr-gcc metadata directives (.file/.section/.type/.size/.ident/.weak/
  .globl/.p2align/...) are accepted as no-ops; genuinely unknown directives
  are still reported as errors.
- A numeric symbol used in register position resolves to that register, so
  avr-gcc's `__zero_reg__ = 1` / `__tmp_reg__ = 0` work as r1/r0.

Validation: real avr-gcc -Os -S output for several C programs (GPIO, loops,
arithmetic, functions, switch, bit ops) now assembles byte-identical to the
GNU toolchain. Remaining gaps (data symbols in .data, libgcc calls) are
linker-domain and out of scope for the flat code-image assembler.

Adds 12 regression tests. 484 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying avr8sharp-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: fa10707
Status: ✅  Deploy successful!
Preview URL: https://1d913e31.avr8sharp-docs.pages.dev
Branch Preview URL: https://fix-assembler-rcall-and-gcc.avr8sharp-docs.pages.dev

View logs

@begeistert
begeistert merged commit a79d553 into main Jun 24, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant