This is the mail archive of the
libc-ports@sources.redhat.com
mailing list for the libc-ports project.
Fix unwinding for Thumb-2 libraries
- From: Daniel Jacobowitz <dan at codesourcery dot com>
- To: libc-ports at sourceware dot org
- Date: Mon, 5 Apr 2010 10:11:39 -0400
- Subject: Fix unwinding for Thumb-2 libraries
I discovered that the backtrace() function would not work correctly if
GLIBC was built as Thumb-2. You can see the reason why in the deleted
portion of the patch below: to avoid conflicts with GCC, which thinks
that r7 is the frame pointer with -mthumb, the inline syscall assembly
had to save r7 to the stack. There was already a nasty workaround in
place to avoid pushing and popping. That made backtrace appear to
work, but if r7 really was the frame pointer for something further up
the stack, unwinding would break down at that point.
This patch moves the "inline" syscalls to a special out-of-line helper
that takes the syscall number in ip instead of r7.
Tested on arm-none-linux-gnueabi. Is this OK to commit?
[I'm not sure if I still have write access.]
--
Daniel Jacobowitz
CodeSourcery
2010-04-01 Daniel Jacobowitz <dan@codesourcery.com>
* sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S: New file.
* sysdeps/unix/sysv/linux/arm/eabi/sysdep.h [__thumb__]
(INTERNAL_SYSCALL_RAW): Rewrite to use __libc_do_syscall.
* sysdeps/unix/sysv/linux/arm/eabi/Makefile: Add libc-do-syscall
to libraries and tests that require it.
Index: sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S
===================================================================
--- sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S (revision 0)
+++ sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S (revision 0)
@@ -0,0 +1,43 @@
+/* Copyright (C) 2010 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+
+/* Out-of-line syscall stub. We expect the system call number in ip
+ and return the raw result in r0. No registers are clobbered.
+ We could avoid using the stack for this, but the goal is accurate
+ unwind information - and while there is a reserved prefix in the
+ ARM unwind tables for register to register moves, the actual opcodes
+ are not defined. */
+
+ .thumb
+ .syntax unified
+ .hidden __libc_do_syscall
+
+ENTRY (__libc_do_syscall)
+ .fnstart
+ push {r7, lr}
+ .save {r7, lr}
+ cfi_adjust_cfa_offset (8)
+ cfi_rel_offset (r7, 0)
+ cfi_rel_offset (lr, 4)
+ mov r7, ip
+ swi 0x0
+ pop {r7, pc}
+ .fnend
+END (__libc_do_syscall)
Index: sysdeps/unix/sysv/linux/arm/eabi/sysdep.h
===================================================================
--- sysdeps/unix/sysv/linux/arm/eabi/sysdep.h (revision 10159)
+++ sysdeps/unix/sysv/linux/arm/eabi/sysdep.h (working copy)
@@ -44,30 +44,34 @@
argument; otherwise the (optional) compatibility code for APCS binaries
may be invoked. */
-#ifdef __thumb__
-/* Hide the use of r7 from the compiler, this would be a lot
- easier but for the fact that the syscalls can exceed 255.
- For the moment the LOAD_ARGS_7 is sacrificed.
+#if defined(__thumb__)
+/* We can not expose the use of r7 to the compiler. GCC (as
+ of 4.5) uses r7 as the hard frame pointer for Thumb - although
+ for Thumb-2 it isn't obviously a better choice than r11.
+ And GCC does not support asms that conflict with the frame
+ pointer.
+
+ This would be easier if syscall numbers never exceeded 255,
+ but they do. For the moment the LOAD_ARGS_7 is sacrificed.
We can't use push/pop inside the asm because that breaks
- unwinding (ie. thread cancellation). */
-/* FIXME: the str / ldr of r7 are not covered by CFI information. */
+ unwinding (i.e. thread cancellation) for this frame. We can't
+ locally save and restore r7, because we do not know if this
+ function uses r7 or if it is our caller's r7; if it is our caller's,
+ then unwinding will fail higher up the stack. So we move the
+ syscall out of line and provide its own unwind information. */
#undef LOAD_ARGS_7
#undef INTERNAL_SYSCALL_RAW
#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
({ \
- int _sys_buf[2]; \
register int _a1 asm ("a1"); \
- register int *_r6 asm ("r6") = _sys_buf; \
- *_r6 = name; \
+ int _nametmp = name; \
LOAD_ARGS_##nr (args) \
- asm volatile ("str r7, [r6, #4]\n\t" \
- "ldr r7, [r6]\n\t" \
- "swi 0 @ syscall " #name "\n\t" \
- "ldr r7, [r6, #4]" \
- : "=r" (_a1) \
- : "r" (_r6) ASM_ARGS_##nr \
- : "memory"); \
- _a1; })
+ register int _name asm ("ip") = _nametmp; \
+ asm volatile ("bl __libc_do_syscall" \
+ : "=r" (_a1) \
+ : "r" (_name) ASM_ARGS_##nr \
+ : "memory", "lr"); \
+ _a1; })
#else /* ARM */
#undef INTERNAL_SYSCALL_RAW
#define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
Index: sysdeps/unix/sysv/linux/arm/eabi/Makefile
===================================================================
--- sysdeps/unix/sysv/linux/arm/eabi/Makefile (revision 10159)
+++ sysdeps/unix/sysv/linux/arm/eabi/Makefile (working copy)
@@ -7,3 +7,34 @@ ifeq ($(subdir),csu)
# unwind tables for __libc_start_main.
CFLAGS-libc-start.c += -fexceptions
endif
+
+# Add a syscall function to each library that needs one.
+
+ifeq ($(subdir),rt)
+librt-sysdep_routines += libc-do-syscall
+librt-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),nptl)
+libpthread-sysdep_routines += libc-do-syscall
+libpthread-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),resolv)
+libanl-sysdep_routines += libc-do-syscall
+libanl-shared-only-routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),csu)
+sysdep_routines += libc-do-syscall
+endif
+
+ifeq ($(subdir),nscd)
+nscd-modules += libc-do-syscall
+endif
+
+ifeq ($(subdir),posix)
+LDFLAGS-tst-rfc3484 += $(common-objpfx)csu/libc-do-syscall.o
+LDFLAGS-tst-rfc3484-2 += $(common-objpfx)csu/libc-do-syscall.o
+LDFLAGS-tst-rfc3484-3 += $(common-objpfx)csu/libc-do-syscall.o
+endif