Re: gcc14 static linking ends with segfault

From: Konstantin Belousov <kostikbel_at_gmail.com>
Date: Mon, 27 Jan 2025 19:24:34 UTC
On Mon, Jan 27, 2025 at 10:42:25AM -0800, Steve Kargl wrote:
> On Mon, Jan 27, 2025 at 04:34:22PM +0100, Dimitry Andric wrote:
> >     /usr/lib/crt1.o \
> >     /usr/lib/crti.o \
> >     /usr/lib/crtbeginT.o \
> (...)
> >     /usr/local/lib/gcc13/gcc/x86_64-portbld-freebsd15.0/13.3.0/crtend.o \
> >     /usr/lib/crtn.o
> > 
> 
> 
> > 
> > Summarizing, I think that it is weird that gcc doesn't use its own
> > crtbegin object, at least for static linking. There may be some
> > historical reason for it, but it should then also not use its own crtend
> > object!
> 
> Not sure about a historical reason, but gcc14 seems to not 
> supply crt1.o, crt1.o, crtbeginT.o, ot crtn.o.  Thus, the
> linker is picking up those files from /usr/lib.
> 
> % find /usr/local/lib/gcc14/ -name crt\*.o
> /usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/crtbegin.o
> /usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/crtend.o
> /usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/crtbeginS.o
> /usr/local/lib/gcc14/gcc/x86_64-portbld-freebsd15.0/14.2.0/crtendS.o
> 
> If I move gcc14/.../crtend.o out of the way, then the segfault goes away
> as the linker shows
> 
>  -V -Bstatic -o z
>  /usr/lib/crt1.o
>  /usr/lib/crti.o
>  /usr/lib/crtbeginT.o
> ...
>  /usr/lib/crtend.o
>  /usr/lib/crtn.o

The following patch worked for me without changing anything in gcc.

From 976aa780b8ad212127d84a47a5a05f1bd6aef60c Mon Sep 17 00:00:00 2001
From: Konstantin Belousov <kib@FreeBSD.org>
Date: Mon, 27 Jan 2025 21:21:20 +0200
Subject: [PATCH] crtbegin: accurately check for the end of .dtors

not relying only on the end section marker, but also checking for the
section size when iterating.

Reported by:	kargl
Analyzed by:	dim
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
---
 lib/csu/common/crtbegin.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/lib/csu/common/crtbegin.c b/lib/csu/common/crtbegin.c
index d6978859af4a..06fe990052f7 100644
--- a/lib/csu/common/crtbegin.c
+++ b/lib/csu/common/crtbegin.c
@@ -66,19 +66,27 @@ static crt_func __DTOR_LIST__[] __section(".dtors") __used = {
 	(crt_func)-1
 };
 
+extern const char startof_dtors[] __asm(".startof..dtors")
+    __weak_symbol __hidden;
+extern const char sizeof_dtors[] __asm(".sizeof..dtors")
+    __weak_symbol __hidden;
+
 static void
 __do_global_dtors_aux(void)
 {
 	crt_func fn;
+	uintptr_t dtors_end;
 	int n;
 
 #ifdef SHARED
 	run_cxa_finalize();
 #endif
 
+	dtors_end = (uintptr_t)&startof_dtors + (uintptr_t)&sizeof_dtors;
 	for (n = 1;; n++) {
 		fn = __DTOR_LIST__[n];
-		if (fn == (crt_func)0 || fn == (crt_func)-1)
+		if (fn == (crt_func)0 || fn == (crt_func)-1 || (dtors_end > 0 &&
+		    (uintptr_t)&__DTOR_LIST__[n] >= dtors_end))
 			break;
 		fn();
 	}
-- 
2.48.1