aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sysdeps/arm/arm-unwind-resume.S26
-rw-r--r--sysdeps/arm/pt-arm-unwind-resume.S48
-rw-r--r--sysdeps/arm/unwind-arch.h4
-rw-r--r--sysdeps/arm/unwind-resume.c25
-rw-r--r--sysdeps/generic/unwind-resume.c55
5 files changed, 97 insertions, 61 deletions
diff --git a/sysdeps/arm/arm-unwind-resume.S b/sysdeps/arm/arm-unwind-resume.S
index 22525f4db0..92c171fe0f 100644
--- a/sysdeps/arm/arm-unwind-resume.S
+++ b/sysdeps/arm/arm-unwind-resume.S
@@ -18,29 +18,29 @@
#include <sysdep.h>
-/* This is just implementing exactly what the C version does.
+/* This is equivalent to the following C implementation:
+
+ void
+ _Unwind_Resume (struct _Unwind_Exception *exc)
+ {
+ __unwind_link_get_resume () (exc);
+ }
+
We do it in assembly just to ensure that we get an unmolested tail
call to the libgcc function, which is necessary for the ARM unwinder. */
ENTRY (_Unwind_Resume)
- LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
- cmp ip, #0
- beq 1f
-0: PTR_DEMANGLE (ip, ip, r2, r3)
- bx ip
-
/* We need to save and restore LR (for our own return address)
and R0 (for the argument to _Unwind_Resume) around the call. */
-1: push {r0, lr}
+ push {r0, lr}
cfi_adjust_cfa_offset (8)
cfi_rel_offset (r0, 0)
cfi_rel_offset (lr, 4)
- bl __libgcc_s_init
+ bl __unwind_link_get_resume
+ mov r3, r0
pop {r0, lr}
cfi_adjust_cfa_offset (-8)
- cfi_restore (r0)
+ cfi_restore (r4)
cfi_restore (lr)
-
- LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
- b 0b
+ bx r3
END (_Unwind_Resume)
diff --git a/sysdeps/arm/pt-arm-unwind-resume.S b/sysdeps/arm/pt-arm-unwind-resume.S
index 7cb555c02b..d579848696 100644
--- a/sysdeps/arm/pt-arm-unwind-resume.S
+++ b/sysdeps/arm/pt-arm-unwind-resume.S
@@ -1,2 +1,46 @@
-#define __libgcc_s_init pthread_cancel_init
-#include <arm-unwind-resume.S>
+/* _Unwind_Resume wrapper for ARM EABI.
+ Copyright (C) 2015-2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+/* This is just implementing exactly what the C version does.
+ We do it in assembly just to ensure that we get an unmolested tail
+ call to the libgcc function, which is necessary for the ARM unwinder. */
+
+ENTRY (_Unwind_Resume)
+ LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
+ cmp ip, #0
+ beq 1f
+0: PTR_DEMANGLE (ip, ip, r2, r3)
+ bx ip
+
+ /* We need to save and restore LR (for our own return address)
+ and R0 (for the argument to _Unwind_Resume) around the call. */
+1: push {r0, lr}
+ cfi_adjust_cfa_offset (8)
+ cfi_rel_offset (r0, 0)
+ cfi_rel_offset (lr, 4)
+ bl pthread_cancel_init
+ pop {r0, lr}
+ cfi_adjust_cfa_offset (-8)
+ cfi_restore (r0)
+ cfi_restore (lr)
+
+ LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
+ b 0b
+END (_Unwind_Resume)
diff --git a/sysdeps/arm/unwind-arch.h b/sysdeps/arm/unwind-arch.h
index fcf889b3c7..62f643b221 100644
--- a/sysdeps/arm/unwind-arch.h
+++ b/sysdeps/arm/unwind-arch.h
@@ -32,4 +32,8 @@
assert (local.ptr__Unwind_VRS_Get != NULL); \
PTR_MANGLE (local.ptr__Unwind_VRS_Get);
+/* This is used by the _Unwind_Resume assembler implementation to
+ obtain the address to jump to. */
+void *__unwind_link_get_resume (void) attribute_hidden;
+
#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/arm/unwind-resume.c b/sysdeps/arm/unwind-resume.c
new file mode 100644
index 0000000000..169d5c30e6
--- /dev/null
+++ b/sysdeps/arm/unwind-resume.c
@@ -0,0 +1,25 @@
+/* Unwinder function forwarders for libc. Arm version.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, see <https://www.gnu.org/licenses/>. */
+
+#include <sysdeps/generic/unwind-resume.c>
+
+void *
+__unwind_link_get_resume (void)
+{
+ return UNWIND_LINK_PTR (link (), _Unwind_Resume);
+}
diff --git a/sysdeps/generic/unwind-resume.c b/sysdeps/generic/unwind-resume.c
index 09533d6992..9e63762bf1 100644
--- a/sysdeps/generic/unwind-resume.c
+++ b/sysdeps/generic/unwind-resume.c
@@ -16,68 +16,31 @@
License along with the GNU C Library; see the file COPYING.LIB. If
not, see <https://www.gnu.org/licenses/>. */
-#include <dlfcn.h>
#include <stdio.h>
-#include <unwind.h>
#include <gnu/lib-names.h>
+#include <unwind-link.h>
#include <sysdep.h>
#include <unwind-resume.h>
-
-void (*__libgcc_s_resume) (struct _Unwind_Exception *exc)
- attribute_hidden __attribute__ ((noreturn));
-
-static _Unwind_Reason_Code (*libgcc_s_personality) PERSONALITY_PROTO;
-
-void attribute_hidden __attribute__ ((cold))
-__libgcc_s_init (void)
+static struct unwind_link *
+link (void)
{
- void *resume, *personality;
- void *handle;
-
- /* See include/dlfcn.h. Use of __libc_dlopen requires RTLD_NOW. */
- handle = __libc_dlopen (LIBGCC_S_SO);
-
- if (handle == NULL
- || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
- || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL)
- __libc_fatal (LIBGCC_S_SO
- " must be installed for unwinding to work\n");
-
-#ifdef PTR_MANGLE
- PTR_MANGLE (resume);
-#endif
- __libgcc_s_resume = resume;
-#ifdef PTR_MANGLE
- PTR_MANGLE (personality);
-#endif
- libgcc_s_personality = personality;
+ struct unwind_link *unwind_link = __libc_unwind_link_get ();
+ if (unwind_link == NULL)
+ __libc_fatal (LIBGCC_S_SO " must be installed for unwinding to work\n");
+ return unwind_link;
}
#if !HAVE_ARCH_UNWIND_RESUME
void
_Unwind_Resume (struct _Unwind_Exception *exc)
{
- if (__glibc_unlikely (__libgcc_s_resume == NULL))
- __libgcc_s_init ();
-
- __typeof (__libgcc_s_resume) resume = __libgcc_s_resume;
-#ifdef PTR_DEMANGLE
- PTR_DEMANGLE (resume);
-#endif
- (*resume) (exc);
+ UNWIND_LINK_PTR (link (), _Unwind_Resume) (exc);
}
#endif
_Unwind_Reason_Code
__gcc_personality_v0 PERSONALITY_PROTO
{
- if (__glibc_unlikely (libgcc_s_personality == NULL))
- __libgcc_s_init ();
-
- __typeof (libgcc_s_personality) personality = libgcc_s_personality;
-#ifdef PTR_DEMANGLE
- PTR_DEMANGLE (personality);
-#endif
- return (*personality) PERSONALITY_ARGS;
+ return UNWIND_LINK_PTR (link (), personality) PERSONALITY_ARGS;
}