Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/llgo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ jobs:
chmod +x verify_export.sh
./verify_export.sh

- name: Test ESP32-C3 newlib startup
run: |
echo "Testing ESP32-C3 uses newlib startup (not TinyGo start.S)..."
cd _demo/embed
chmod +x test_esp32c3_startup.sh
./test_esp32c3_startup.sh

- name: _xtool build tests
run: |
cd _xtool
Expand Down
51 changes: 51 additions & 0 deletions _demo/embed/test_esp32c3_startup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash

# ESP32-C3 Startup Regression Test
# Verify that _start uses newlib's __libc_init_array (not TinyGo's start.S)

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMP_DIR=$(mktemp -d)
TEST_GO="$TEMP_DIR/main.go"
TEST_ELF="$TEMP_DIR/test.elf"

cleanup() {
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT

echo "==> Creating minimal test program..."
cat > "$TEST_GO" << 'EOF'
package main

func main() {}
EOF

echo "==> Building for ESP32-C3 target..."
cd "$TEMP_DIR"
llgo build -target=esp32c3 -o "$TEST_ELF" "$TEST_GO"

if [ ! -f "$TEST_ELF" ]; then
echo "✗ FAIL: Build failed, $TEST_ELF not found"
exit 1
fi

echo "==> Checking for __libc_init_array call in _start..."

# Disassemble _start and check for __libc_init_array call
if llvm-objdump -d "$TEST_ELF" | grep -A30 "<_start>:" | grep "__libc_init_array" > /dev/null; then
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider increasing -A30 to -A50 for additional safety margin. While 30 lines is reasonable for most _start implementations, using a larger value provides extra headroom if the function grows in the future.

echo "✓ PASS: _start calls __libc_init_array"
echo " This confirms ESP32-C3 uses newlib's standard startup"
echo " (crt0-riscv32-unknown-none, not TinyGo's start.S)"
exit 0
else
echo "✗ FAIL: _start does NOT call __libc_init_array"
echo " ESP32-C3 should use newlib's startup flow"
echo " Check targets/esp32c3.json inheritance chain"
echo ""
echo "Expected: esp32c3 → riscv32-llgo → riscv-llgo → riscv-basic"
echo "Current _start disassembly:"
llvm-objdump -d "$TEST_ELF" | grep -A30 "<_start>:" || true
exit 1
fi
39 changes: 19 additions & 20 deletions targets/esp32-riscv.app.elf.ld
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,37 @@ SECTIONS
*(.rodata1)
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
. = ALIGN(4);
__cpu_frequency = .;
LONG(CPU_FREQUENCY);
__uart0_clkdiv_reg = .;
LONG(UART0_CLKDIV_REG);
__uart0_clkdiv_val = .;
LONG(UART0_CLKDIV_VAL);
__uart0_tx_addr = .;
LONG(UART0_TX_ADDR);
__uart0_status = .;
LONG(UART0_STATUS);
} > iram_seg

.preinit_array :
{
. = ALIGN(4);
Copy link
Contributor

Choose a reason for hiding this comment

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

Documentation note: These sections now reside within .rodata (which maps to iram_seg), ensuring they remain in fast instruction RAM. This placement is both secure (read-only) and performant (single-cycle access). Consider adding a brief comment explaining this design decision for future maintainers.

PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} > iram_seg
.init_array :
{

. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} > iram_seg
.fini_array :
{

. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);

. = ALIGN(4);
__cpu_frequency = .;
LONG(CPU_FREQUENCY);
__uart0_clkdiv_reg = .;
LONG(UART0_CLKDIV_REG);
__uart0_clkdiv_val = .;
LONG(UART0_CLKDIV_VAL);
__uart0_tx_addr = .;
LONG(UART0_TX_ADDR);
__uart0_status = .;
LONG(UART0_STATUS);
} > iram_seg

.ctors :
{
/* gcc uses crtbegin.o to find the start of
Expand Down Expand Up @@ -94,6 +92,7 @@ SECTIONS

.stack (NOLOAD) :
{
. = ALIGN(16);
. += 16K;
__stack = .;
} > dram_seg
Expand Down
2 changes: 1 addition & 1 deletion targets/esp32c3.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"inherits": [
"riscv32"
"riscv32-llgo"
],
"features": "+32bit,+c,+m,+zmmul,-a,-b,-d,-e,-experimental-smmpm,-experimental-smnpm,-experimental-ssnpm,-experimental-sspm,-experimental-ssqosid,-experimental-supm,-experimental-zacas,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-f,-h,-relax,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smepmp,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-v,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xesppie,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zicsr,-zifencei,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b",
"build-tags": [
Expand Down
19 changes: 19 additions & 0 deletions targets/riscv-basic.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"goos": "linux",
"goarch": "arm",
"build-tags": ["tinygo.riscv", "baremetal", "linux", "arm"],
"gc": "conservative",
"linker": "ld.lld",
"rtlib": "compiler-rt",
"libc": "picolibc",
"cflags": [
"-Werror",
"-mno-relax",
"-fno-exceptions", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables",
"-ffunction-sections", "-fdata-sections"
],
"ldflags": [
"--gc-sections"
],
"gdb": ["riscv64-unknown-elf-gdb"]
}
4 changes: 4 additions & 0 deletions targets/riscv-llgo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"inherits": ["riscv-basic"],
"build-tags": ["target_llgo"]
}
18 changes: 2 additions & 16 deletions targets/riscv.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
{
"goos": "linux",
"goarch": "arm",
"build-tags": ["tinygo.riscv", "baremetal", "linux", "arm"],
"gc": "conservative",
"linker": "ld.lld",
"rtlib": "compiler-rt",
"libc": "picolibc",
"cflags": [
"-Werror",
"-mno-relax",
"-fno-exceptions", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables",
"-ffunction-sections", "-fdata-sections"
],
"ldflags": [
"--gc-sections"
],
"inherits": ["riscv-basic"],
"build-tags": ["target_tinygo"],
"extra-files": [
"targets/device/riscv/start.S",
"targets/device/riscv/handleinterrupt.S"
Expand Down
19 changes: 19 additions & 0 deletions targets/riscv32-llgo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"inherits": ["riscv-llgo"],
"llvm-target": "riscv32-unknown-none",
"cpu": "generic-rv32",
"target-abi": "ilp32",
"build-tags": ["tinygo.riscv32"],
"scheduler": "tasks",
"default-stack-size": 2048,
"cflags": [
"-march=rv32imac"
],
"ldflags": [
"-melf32lriscv"
],
"gdb": [
"gdb-multiarch",
"gdb"
]
}
Loading