]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Support loading libunwind instead of libgcc_s
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 25 Feb 2026 18:31:16 +0000 (15:31 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Thu, 12 Mar 2026 16:52:50 +0000 (13:52 -0300)
The 'unwind-link' facility allows glibc to support thread cancellation
and exit (pthread_cancel, pthread_exiti, backtrace) by dynamically
loading the  unwind library at runtime, preventing a hard dependency on
libgcc_s within libc.so.

When building with libunwind (for clang/LLVM toolchains [1]), two
assumptions in the existing code break:

  1. The runtime library is libunwind.so instead of libgcc_s.so.

  2. libgcc relies on __gcc_personality_v0 to handle unwinding mechanics.
     libunwind exposes the standard '_Unwind_*' accessors directly.

This patch adapts `unwind-link` to handle both environments based on
the HAVE_CC_WITH_LIBUNWIND configuration:

  * The UNWIND_SONAME macro now selects between LIBGCC_S_SO and
    LIBUNWIND_SO.

  * For libgcc, it continues to resolve `__gcc_personality_v0`.

  * For libunwind, it instead resolves the standard
    _Unwind_GetLanguageSpecificData, _Unwind_SetGR, _Unwind_SetIP,
     and _Unwind_GetRegionStart helpers.

   * unwind-resume.c is updated to implement wrappers for these
     accessors that forward calls to the dynamically loaded function
     pointers, effectively shimming the unwinder.

Tests and Makefiles are updated to link against `$(libunwind)` where
appropriate.

Reviewed-by: Sam James <sam@gentoo.org>
[1] https://github.com/libunwind/libunwind

elf/Makefile
misc/unwind-link.c
nptl/pthread_cancel.c
nptl/pthread_exit.c
shlib-versions
sysdeps/generic/unwind-link.h
sysdeps/generic/unwind-resume.c

index 73229952caa8e197a850129e8ff63c639b4c84d4..32d9fdc22197792c647dd5fe0133fd12028e8e9f 100644 (file)
@@ -2765,6 +2765,8 @@ $(objpfx)tst-big-note-lib.so: $(objpfx)tst-big-note-lib.o
        $(LINK.o) -shared -o $@ $(LDFLAGS.so) $(dt-relr-ldflag) $<
 
 $(objpfx)tst-unwind-ctor: $(objpfx)tst-unwind-ctor-lib.so
+LDLIBS-tst-unwind-ctor += $(libunwind)
+LDFLAGS-tst-unwind-ctor-lib.so = -Wl,--unresolved-symbols=ignore-all
 
 CFLAGS-tst-unwind-main.c += -funwind-tables -DUSE_PTHREADS=0
 
index 6019dacf6637d5c6dce8fbdb94473aefc0c7660c..c5c1a3ea692887a9b1e635be15fa56176545435c 100644 (file)
@@ -37,6 +37,12 @@ static void *global_libgcc_handle;
    may depend on unwinding.  */
 __libc_lock_define (static, lock);
 
+#ifndef HAVE_CC_WITH_LIBUNWIND
+# define UNWIND_SONAME LIBGCC_S_SO
+#else
+# define UNWIND_SONAME LIBUNWIND_SO
+#endif
+
 struct unwind_link *
 __libc_unwind_link_get (void)
 {
@@ -48,7 +54,7 @@ __libc_unwind_link_get (void)
   /* Initialize a copy of the data, so that we do not need about
      unlocking in case the dynamic loader somehow triggers
      unwinding.  */
-  void *local_libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
+  void *local_libgcc_handle = __libc_dlopen (UNWIND_SONAME);
   if (local_libgcc_handle == NULL)
     {
       __libc_lock_unlock (lock);
@@ -72,8 +78,19 @@ __libc_unwind_link_get (void)
   local.ptr___frame_state_for
     = __libc_dlsym (local_libgcc_handle, "__frame_state_for");
 #endif
+#ifndef HAVE_CC_WITH_LIBUNWIND
   local.ptr_personality
     = __libc_dlsym (local_libgcc_handle, "__gcc_personality_v0");
+#else
+  local.ptr__Unwind_GetLanguageSpecificData
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetLanguageSpecificData");
+  local.ptr__Unwind_SetGR
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_SetGR");
+  local.ptr__Unwind_SetIP
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_SetIP");
+  local.ptr__Unwind_GetRegionStart
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetRegionStart");
+#endif
   UNWIND_LINK_EXTRA_INIT
 
   /* If a symbol is missing, libgcc_s has somehow been corrupted.  */
@@ -84,7 +101,15 @@ __libc_unwind_link_get (void)
   assert (local.ptr__Unwind_GetIP != NULL);
 #endif
   assert (local.ptr__Unwind_Resume != NULL);
+#ifndef HAVE_CC_WITH_LIBUNWIND
   assert (local.ptr_personality != NULL);
+#else
+  assert (local.ptr__Unwind_GetLanguageSpecificData != NULL);
+  assert (local.ptr__Unwind_SetGR != NULL);
+  assert (local.ptr__Unwind_GetIP != NULL);
+  assert (local.ptr__Unwind_SetIP != NULL);
+  assert (local.ptr__Unwind_GetRegionStart != NULL);
+#endif
 
   PTR_MANGLE (local.ptr__Unwind_Backtrace);
   PTR_MANGLE (local.ptr__Unwind_ForcedUnwind);
@@ -96,7 +121,14 @@ __libc_unwind_link_get (void)
 #if UNWIND_LINK_FRAME_STATE_FOR
   PTR_MANGLE (local.ptr___frame_state_for);
 #endif
+#ifndef HAVE_CC_WITH_LIBUNWIND
   PTR_MANGLE (local.ptr_personality);
+#else
+  PTR_MANGLE (local.ptr__Unwind_GetLanguageSpecificData);
+  PTR_MANGLE (local.ptr__Unwind_SetGR);
+  PTR_MANGLE (local.ptr__Unwind_SetIP);
+  PTR_MANGLE (local.ptr__Unwind_GetRegionStart);
+#endif
 
   __libc_lock_lock (lock);
   if (atomic_load_relaxed (&global_libgcc_handle) != NULL)
index 9150411271dff22be5cbca21739f47f3960a90dd..5a5a637d7c662c29232423964b214f7c1ad32369 100644 (file)
@@ -87,7 +87,7 @@ __pthread_cancel (pthread_t th)
   {
     struct unwind_link *unwind_link = __libc_unwind_link_get ();
     if (unwind_link == NULL)
-      __libc_fatal (LIBGCC_S_SO
+      __libc_fatal (UNWIND_SONAME
                    " must be installed for pthread_cancel to work\n");
   }
 #endif
index 4c151719926afed2a4c5d79c7ad57b62e73a34df..1ed5ed52c44651a0377f16d44f2e0f9ee9bec0c0 100644 (file)
@@ -28,7 +28,7 @@ __pthread_exit (void *value)
   {
     struct unwind_link *unwind_link = __libc_unwind_link_get ();
     if (unwind_link == NULL)
-      __libc_fatal (LIBGCC_S_SO
+      __libc_fatal (UNWIND_SONAME
                     " must be installed for pthread_exit to work\n");
   }
 #endif
index b1fd0a5eab4b849045d85d2e8a2a2befd8b6a642..32093228c445a27760f67eec8eb93385517d831c 100644 (file)
@@ -68,3 +68,5 @@ libmvec=1
 
 # The malloc debug library
 libc_malloc_debug=0
+
+libunwind=1
index 1150cda2199a488e1adf07f6dd8f4637dc8173ef..ea39e525d295dbab29da216743d2620b53d4440d 100644 (file)
@@ -34,6 +34,12 @@ unwind_arch_adjustment (void *prev, void *addr)
 # include <pointer_guard.h>
 # include <unwind-resume.h>
 
+# ifndef HAVE_CC_WITH_LIBUNWIND
+#  define UNWIND_SONAME LIBGCC_S_SO
+# else
+#  define UNWIND_SONAME LIBUNWIND_SO
+# endif
+
 # if UNWIND_LINK_FRAME_STATE_FOR
 struct frame_state;
 # endif
@@ -50,7 +56,14 @@ struct unwind_link
 #if UNWIND_LINK_FRAME_STATE_FOR
   struct frame_state *(*ptr___frame_state_for) (void *, struct frame_state *);
 #endif
+#ifndef HAVE_CC_WITH_LIBUNWIND
   _Unwind_Reason_Code (*ptr_personality) PERSONALITY_PROTO;
+#else
+  __typeof (_Unwind_GetLanguageSpecificData) *ptr__Unwind_GetLanguageSpecificData;
+  __typeof (_Unwind_SetGR) *ptr__Unwind_SetGR;
+  __typeof (_Unwind_SetIP) *ptr__Unwind_SetIP;
+  __typeof (_Unwind_GetRegionStart) *ptr__Unwind_GetRegionStart;
+#endif
   UNWIND_LINK_EXTRA_FIELDS
 };
 
index de176a1f727df2dc280a2d93e5fe18f58f5019b4..18c40501bbdac2445ce80105372f7a0374533424 100644 (file)
@@ -38,11 +38,43 @@ _Unwind_Resume (struct _Unwind_Exception *exc)
 }
 #endif
 
+#ifndef HAVE_CC_WITH_LIBUNWIND
 _Unwind_Reason_Code
 __gcc_personality_v0 PERSONALITY_PROTO
 {
   return UNWIND_LINK_PTR (link (), personality) PERSONALITY_ARGS;
 }
+#else
+void *
+_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
+{
+  return UNWIND_LINK_PTR (link (), _Unwind_GetLanguageSpecificData) (context);
+}
+
+void
+_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
+{
+  UNWIND_LINK_PTR (link (), _Unwind_SetGR) (context, index, val);
+}
+
+_Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *context)
+{
+  return UNWIND_LINK_PTR (link (), _Unwind_GetIP) (context);
+}
+
+void
+_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
+{
+  UNWIND_LINK_PTR (link (), _Unwind_SetIP) (context, val);
+}
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (struct _Unwind_Context *context)
+{
+  return UNWIND_LINK_PTR (link (), _Unwind_GetRegionStart) (context);
+}
+#endif
 
 _Unwind_Reason_Code
 _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,