-
Notifications
You must be signed in to change notification settings - Fork 46
Open
Description
Problem
ESP32-C3 doesn't support RISC-V A extension (atomic operations). When code uses atomic operations, linking fails with undefined symbol errors:
llgo run -a -target esp32c3 .
ld.lld: error: undefined symbol: __atomic_store_4
>>> referenced by write
>>> .../write.o:(github.com/goplus/llgo/_demo/embed/esp32c3/write.main)
Root Cause
- ESP32-C3 only supports RV32IMC instruction set, no A extension (atomic operations)
- PR fix(esp32c3): correct -march to rv32imc to prevent illegal instruction crashes #1443 fixed
-march=rv32imac→-march=rv32imcand excludedatomic.ccompilation - However, when Go code uses atomic operations (e.g.,
sync/atomicpackage or compiler-generated atomic instructions), it generates calls to__atomic_*functions - Without hardware support or software implementation, linker cannot find these symbols
Proposed Solution
Reference TinyGo's approach (tinygo#2146) - implement software atomic operations by disabling interrupts:
//export __atomic_load_4
func __atomic_load_4(ptr *uint32, ordering int32) uint32 {
mask := riscv.DisableInterrupts()
value := *ptr
riscv.EnableInterrupts(mask)
return value
}
//export __atomic_store_4
func __atomic_store_4(ptr *uint32, value uint32, ordering int32) {
mask := riscv.DisableInterrupts()
*ptr = value
riscv.EnableInterrupts(mask)
}Rationale: On single-core systems (like ESP32-C3), disabling interrupts guarantees atomicity since no other code can interrupt current execution.
Functions to Implement
Common atomic operation functions:
__atomic_load_1/2/4/8- Atomic load__atomic_store_1/2/4/8- Atomic store__atomic_exchange_1/2/4/8- Atomic exchange__atomic_compare_exchange_1/2/4/8- Atomic compare-and-swap (CAS)__atomic_fetch_add_1/2/4/8- Atomic add__atomic_fetch_sub_1/2/4/8- Atomic subtract__atomic_fetch_and/or/xor_1/2/4/8- Atomic bitwise operations
Simplified Approach
For llgo, we can start with the most commonly used functions (like __atomic_store_4, __atomic_load_4) using simple assignment:
// targets/device/esp/esp32c3_atomic.c
void __atomic_store_4(uint32_t *ptr, uint32_t value, int ordering) {
*ptr = value; // Simple assignment (safe on single-core)
}
uint32_t __atomic_load_4(uint32_t *ptr, int ordering) {
return *ptr;
}Add interrupt disabling logic later if stricter atomicity guarantees are needed.
Related Links
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels