Hi Richard,
Thanks for the detailed report and, especially, for testing the fix with a real
libgc build on FreeBSD. The missing plain symbols were indeed the root cause.
I pushed the resulting work to mob as two commits:
384614a9 tccelf: provide complete ELF boundary symbols
43158eaa tccelf: consider DSO symbols for PROVIDE
I made the first change apply to all ELF targets rather than gating it on
TARGETOS_BSD. The plain etext, edata, and end names now have PROVIDE semantics:
TCC creates them when needed, while leaving user definitions alone.
This turned out to have a bit more reach than it first appeared. The boundary
symbols were calculated before final section layout, so copy relocations and
separately named allocatable sections could leave them pointing too early. All
six plain and underscored symbols are now finalized from the actual output
layout.
The second commit handles the less obvious case where a boundary name is only
present in an input DSO's dynamic symbols. The executable must still provide
and export the final value for dynamic resolution.
Regression tests cover archive references, user overrides, copy relocations,
split sections, and the DSO-only case.
Thanks again for uncovering this.
Best regards,
Mounir IDRASSI
From: Richard Wheeler <[email protected]>
To: "[email protected]"<[email protected]>
Date: Sun, 26 Jul 2026 00:33:36 +0900
Subject: [Tinycc-devel] [PATCH] tccelf: define plain etext/edata/end linker
symbols on BSD targets
> Hi,
>
>
> Found while wiring up FreeBSD CI for vlang/tccbin's prebuilt tcc + Boehm GC
> bundle (a separate project, unrelated to the two win32patches I sent
> earlier): any GC-using program fails to link against aprebuilt libgc.a on
> FreeBSD with
>
> tcc: error: undefined symbol 'etext'
> tcc: error: undefined symbol 'end'
>
> tcc_add_linker_symbols() (tccelf.c) only ever defines the glibc-style
> _etext, _edata, and _end symbols. That's sufficient on Linux/glibc, where
> glibc's own crt objects separately provide the plain (non-underscore)
> etext/edata/end names as aliases - but traditional BSD systems have the
> opposite convention: the plain names are the
> primary linker-provided symbols directly, with no equivalent aliasing
> supplied by libc. Code that references the plain names directly - the
> Boehm-Demers-Weiser GC's FreeBSD data-segment-scanning code looks up
> etext/end to bound its conservative-GC root region - therefore links fine
> under a BSD system's native toolchain but fails under tcc.
>
> Fix: also define the plain names, gated on the existing TARGETOS_BSD macro
> (already used a few lines above in the same function, for OpenBSD's
> __executable_start).
>
> Verified on a real FreeBSD 15.1 VM: a tcc built from this patch successfully
> compiles, links, and runs a GC_INIT()/GC_malloc()-using test program against
> a real prebuilt libgc.a, where an unpatched tcc built from the same tree
> fails with the undefined symbol errors above.
> Tested against current mob (commit 85ba3ae8 at the time of testing).
>
> Thanks,
>
> Richard Wheeler
>
> From 50351a40d72026adde53956bf8498ab47374ea6d Mon Sep 17 00:00:00 2001From:
> Richard Wheeler <[email protected]>
> Date: Sat, 25 Jul 2026 11:24:18 -0400
> Subject: [PATCH] tccelf: define plain etext/edata/end linker symbols on BSD
> targets
>
> tcc_add_linker_symbols() only ever defines the glibc-style _etext,
> _edata, and _end symbols. On Linux/glibc this is sufficient because
> glibc's own crt objects provide the plain (non-underscore) etext,
> edata, and end names as aliases. Traditional BSD systems have the
> opposite convention: the plain names are the primary symbols the
> system linker provides directly, with no equivalent aliasing from
> libc.
>
> Code that references the plain names directly - e.g. the Boehm-
> Demers-Weiser GC's FreeBSD data-segment-scanning code, which looks up
> `etext`/`end` to bound its conservative-GC root region - therefore
> links fine under a BSD system's native linker/toolchain, but fails
> under tcc with "tcc: error: undefined symbol 'etext'"/"'end'".
>
> Fix: also define the plain names, gated on the existing TARGETOS_BSD
> macro (already used a few lines above for OpenBSD's
> __executable_start).
>
> Found while wiring FreeBSD CI for vlang/tccbin's prebuilt tcc + Boehm
> GC bundle: any GC-using program failed to link against the bundled
> libgc.a with exactly this error. Verified the fix on a real FreeBSD
> 15.1 VM: a tcc built from this patch successfully compiles, links,
> and runs a GC_INIT()/GC_malloc()-using test program against that same
> libgc.a, where the unpatched tcc fails with the undefined symbol
> errors above.
> ---
> tccelf.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/tccelf.c b/tccelf.c
> index 7e9758af..f9ae676c 100644
> --- a/tccelf.c
> +++ b/tccelf.c
> @@ -1890,6 +1890,19 @@ static void tcc_add_linker_symbols(TCCState *s1)
> #if TARGETOS_OpenBSD
> set_global_sym(s1, "__executable_start", NULL, ELF_START_ADDR);
> #endif
> +#if TARGETOS_BSD
> + /* Traditional BSD systems provide the plain (non-underscore) names
> + as the primary linker-provided segment-boundary symbols, unlike
> + glibc/Linux where they're only weak aliases of _etext/_edata/_end
> + supplied by the C library's own crt objects - so code that
> + references the plain names directly (e.g. BDWGC's FreeBSD
> + data-segment-scanning code looks up `etext`/`end` to find its
> + conservative-GC root region) links fine under a BSD system's
> + native linker but fails here with "undefined symbol" errors. */
> + set_global_sym(s1, "etext", text_section, -1);
> + set_global_sym(s1, "edata", data_section, -1);
> + set_global_sym(s1, "end", bss_section, -1);
> +#endif
> #ifdef TCC_TARGET_RISCV64
> /* XXX should be .sdata+0x800, not .data+0x800 */
> set_global_sym(s1, "__global_pointer$", data_section, 0x800);
> --
> 2.53.0.windows.2
>
>
> _______________________________________________
> Tinycc-devel mailing list
> [email protected]
> https://lists.nongnu.org/mailman/listinfo/tinycc-devel
>
_______________________________________________
Tinycc-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel