Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Jan 2025 21:24:34 +0200
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Steve Kargl <sgk@troutmask.apl.washington.edu>
Cc:        Dimitry Andric <dim@freebsd.org>, freebsd-hackers@freebsd.org
Subject:   Re: gcc14 static linking ends with segfault
Message-ID:  <Z5fdcvWgUpibIBXq@kib.kiev.ua>
In-Reply-To: <Z5fTkXmqr1MZKk8d@troutmask.apl.washington.edu>
References:  <Z5aYNdVQdGdVImBG@troutmask.apl.washington.edu> <Z5cRe8tivqpgme1I@kib.kiev.ua> <Z5cnYyWxcT5pk1Wf@troutmask.apl.washington.edu> <C09215C1-ABF0-4248-A69A-F0137BBC7E2B@FreeBSD.org> <Z5fTkXmqr1MZKk8d@troutmask.apl.washington.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Z5fdcvWgUpibIBXq>