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 2001
From: 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

Reply via email to