Skip to content

fix(esp32c3): correct -march to rv32imc to prevent illegal instruction crashes#1443

Merged
xushiwei merged 3 commits intogoplus:mainfrom
luoliwoshang:esp32c3/atomic
Dec 11, 2025
Merged

fix(esp32c3): correct -march to rv32imc to prevent illegal instruction crashes#1443
xushiwei merged 3 commits intogoplus:mainfrom
luoliwoshang:esp32c3/atomic

Conversation

@luoliwoshang
Copy link
Member

@luoliwoshang luoliwoshang commented Dec 9, 2025

part of #1427

1. Illegal Instruction Crash with println()

After implementing USB Serial JTAG output:

  • c.Printf() works fine - Output visible through USB Serial JTAG
  • println() crashes the program - Triggers illegal instruction exception

Crash Details:

Guru Meditation Error: Core 0 panic'ed (Illegal instruction)
Core 0 register dump:
PC      : 0x40383334
MSTATUS : 0x00001881
MCAUSE  : 0x00000002  ← Illegal instruction exception
MTVAL   : 0x00003e54  ← Instruction opcode that caused the exception

Root Cause:

  • Using -march=rv32imac enables A extension (atomic operations)
  • ESP32-C3 only supports RV32IMC (no A/D/F extensions)
  • Compiler generates unsupported instructions like C.FLD (compressed floating-point load)
  • When runtime code executes these instructions, it triggers illegal instruction exception

2. Compiler-RT atomic.c Build Failure

After fixing the -march flag to rv32imc (removing A extension), a new issue appears:

Build Error:

/Users/.../compiler-rt-.../lib/builtins/atomic.c:105:16: error:
static assertion failed due to requirement '__atomic_always_lock_free(sizeof(unsigned int), 0)':
Implementation assumes lock-free pointer-size cmpxchg
  105 | _Static_assert(__atomic_always_lock_free(sizeof(uintptr_t), 0),
      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

Cause: atomic.c requires hardware atomic support (A extension), which ESP32-C3 doesn't have.

This affects all ESP32-C3 board variants.

Solution

1. Fix -march Flag to Remove A Extension

Create riscv32-esp.json: Base configuration for ESP RISC-V chips

  • Use riscv32-esp-elf as llvm-target (official target triple from ESP-IDF toolchain)
  • Set correct ISA: -march=rv32imc (no A/D/F extensions)
  • Reference: TinyGo also uses -march=rv32imc for ESP32-C3 and all ESP RISC-V chips

Use llvm-target for identification: Check config.LLVMTarget == "riscv32-esp-elf" instead of hardcoded target names

  • Automatically works for all inherited targets (esp32c3-supermini, m5stamp-c3, etc.)
  • Follows ESP-IDF conventions

Result: No more illegal instruction crashes - println() now works correctly.

2. Exclude atomic.c for ESP Targets

Conditionally exclude atomic.c: Skip compilation for ESP targets that lack A extension

  • Prevents static assertion failures in atomic.c
  • Only include for targets with hardware atomic support (A extension)

Result: Clean compilation without atomic.c errors.

Affected Targets

This fix applies to all ESP32-C3 variants through inheritance:

  • esp32c3
  • esp32c3-supermini
  • m5stamp-c3
  • esp32-c3-devkit-rust-1
  • esp-c3-32s-kit
  • esp32c3-12f

@gemini-code-assist
Copy link

Summary of Changes

Hello @luoliwoshang, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical issue causing illegal instruction crashes on the ESP32-C3 microcontroller by precisely configuring its RISC-V instruction set architecture. It introduces a dedicated target profile for ESP RISC-V, updates the Newlib dependency, and integrates essential bare-metal support for USB Serial JTAG output, significantly enhancing the stability and usability of TinyGo on ESP32-C3 devices.

Highlights

  • ESP32-C3 ISA Correction: The build configuration for ESP32-C3 has been updated to correctly specify the RISC-V instruction set architecture as rv32imc, explicitly excluding the 'A' (Atomic) extension. This change prevents illegal instruction crashes that occurred when attempting to use unsupported atomic operations on the ESP32-C3 hardware.
  • Newlib Update: The Newlib library configuration has been upgraded to esp-4.3.0_20250211-patch4, ensuring the use of the latest patched version for ESP32 builds.
  • Bare-Metal USB Serial JTAG Output: A new C file (targets/device/esp/esp32c3.c) has been added, providing a bare-metal implementation of the _write system call for ESP32-C3. This enables standard output (stdout/stderr) via the USB Serial JTAG interface, crucial for debugging and logging in embedded applications.
  • Refined Target Configuration: The generic riscv32-nostart target has been renamed to riscv32-esp and specifically configured for ESP RISC-V devices, including updates to its LLVM target and CFLAGS to align with ESP32-C3's capabilities.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces bare-metal USB Serial JTAG support for the ESP32-C3, enabling stdout/stderr output. Key changes include adding a new C file (targets/device/esp/esp32c3.c) with ESP32-C3 USB Serial JTAG register definitions, low-level write functions, and a _write syscall implementation that handles newline to CRLF conversion and non-blocking character writing. The esp32c3.json target configuration is updated to inherit from a new riscv32-esp base, include the new C file, and define the USB Serial JTAG memory address in esp32c3.memory.ld. Additionally, the riscv32-esp target's llvm-target and cflags are adjusted to riscv32-esp-elf and -march=rv32imc respectively, reflecting the ESP32-C3's lack of the 'A' (Atomic) extension. This architectural distinction is also incorporated into internal/crosscompile/crosscompile.go and internal/crosscompile/compile/rtlib/compiler_rt.go to conditionally include atomic.c for non-ESP RISC-V32 targets. The newlib-esp32 library configuration is also updated to patch4. Review comments point out that the new _write function in esp32c3.c incorrectly reports all bytes as written despite its non-blocking nature potentially dropping characters, and it lacks a check for valid file descriptors (1 and 2), which could lead to silent data loss or unexpected behavior.

@xgopilot
Copy link
Contributor

xgopilot bot commented Dec 9, 2025

Code Review Summary

This PR successfully fixes the ESP32-C3 illegal instruction crash through a well-architected solution. The approach of creating a dedicated riscv32-esp.json base configuration and using LLVMTarget for distinction is clean and maintainable.

Key strengths:

  • Excellent documentation with ESP-IDF source references
  • Proper exclusion of atomic.c for ESP targets lacking A extension
  • Safe bare-metal USB Serial JTAG implementation

Noteworthy issues identified:

  • Security: _write() returns success even when data is dropped (POSIX violation)
  • Code Quality: Inconsistent target identification strategy between files
  • Documentation: Minor clarity improvements needed in comments

See inline comments for specific recommendations.

@luoliwoshang luoliwoshang marked this pull request as draft December 10, 2025 02:48
@codecov
Copy link

codecov bot commented Dec 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.58%. Comparing base (21ec089) to head (5e4ab9f).
⚠️ Report is 12 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1443      +/-   ##
==========================================
+ Coverage   90.54%   90.58%   +0.03%     
==========================================
  Files          43       43              
  Lines       11423    11429       +6     
==========================================
+ Hits        10343    10353      +10     
+ Misses        917      914       -3     
+ Partials      163      162       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…nstructions

Problem:
- ESP32-C3 only supports RV32IMC (no A extension for atomic operations)
- Using -march=rv32imac generates unsupported atomic instructions
- Including atomic.c causes compilation failure due to missing hardware support

Solution:
- Create riscv32-esp.json as base config for ESP RISC-V chips
- Use llvm-target "riscv32-esp-elf" to identify ESP targets
- Change -march from rv32imac to rv32imc for ESP targets
- Conditionally exclude atomic.c for ESP targets in compiler-rt

This fix applies to all ESP32-C3 variants through inheritance:
- esp32c3
- esp32c3-supermini
- m5stamp-c3
- esp32-c3-devkit-rust-1
- esp-c3-32s-kit
- esp32c3-12f

Reference: ESP-IDF uses riscv32-esp-elf as official target triple
Add test cases to verify correct -march flag selection:
- riscv32 (generic): expects -march=rv32imac (with A extension)
- esp32c3: expects -march=rv32imc (no A extension)

This covers both branches of the ESP RISC-V chip detection logic.
@luoliwoshang luoliwoshang marked this pull request as ready for review December 10, 2025 07:44
@xgopilot
Copy link
Contributor

xgopilot bot commented Dec 10, 2025

Code Review Summary

This PR correctly fixes the ESP32-C3 illegal instruction issue by using the appropriate -march=rv32imc flag and excluding atomic.c. The implementation is sound with good test coverage. I've identified a few noteworthy areas for improvement regarding consistency and test coverage. Overall, this is a well-executed fix.

- Change compiler_rt.go to use exact matching (target != "riscv32-esp-elf")
  instead of strings.Contains for consistency with crosscompile.go
- Remove redundant -march=rv32imc from esp32c3.json since it's already
  inherited from riscv32-esp.json (follows DRY principles)
@luoliwoshang luoliwoshang changed the title fix(esp32c3): skip -march=rv32imac to avoid illegal instruction crash fix(esp32c3): correct -march to rv32imc to prevent illegal instruction crashes Dec 10, 2025
@luoliwoshang luoliwoshang mentioned this pull request Dec 10, 2025
4 tasks
@luoliwoshang
Copy link
Member Author

@xushiwei

@xushiwei xushiwei merged commit fe79ef9 into goplus:main Dec 11, 2025
42 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.

3 participants