[09/10] Implement _Unwind_Resume in libc on top of <unwind-link.h>
Commit Message
Temporarily move the arm _Unwind_Resume implementation to the file
used by libpthread. It will be ported to <unwind-link.h> along with
the rest of nptl.
---
sysdeps/arm/arm-unwind-resume.S | 26 +++++++-------
sysdeps/arm/pt-arm-unwind-resume.S | 48 ++++++++++++++++++++++++--
sysdeps/arm/unwind-arch.h | 4 +++
sysdeps/arm/unwind-resume.c | 25 ++++++++++++++
sysdeps/generic/unwind-resume.c | 55 +++++-------------------------
5 files changed, 97 insertions(+), 61 deletions(-)
create mode 100644 sysdeps/arm/unwind-resume.c
Comments
On 2/17/21 11:03 AM, Florian Weimer via Libc-alpha wrote:
> Temporarily move the arm _Unwind_Resume implementation to the file
> used by libpthread. It will be ported to <unwind-link.h> along with
> the rest of nptl.
LGTM.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> ---
> sysdeps/arm/arm-unwind-resume.S | 26 +++++++-------
> sysdeps/arm/pt-arm-unwind-resume.S | 48 ++++++++++++++++++++++++--
> sysdeps/arm/unwind-arch.h | 4 +++
> sysdeps/arm/unwind-resume.c | 25 ++++++++++++++
> sysdeps/generic/unwind-resume.c | 55 +++++-------------------------
> 5 files changed, 97 insertions(+), 61 deletions(-)
> create mode 100644 sysdeps/arm/unwind-resume.c
>
> 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;
> }
>
@@ -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)
@@ -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)
@@ -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 */
new file mode 100644
@@ -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);
+}
@@ -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;
}