Fix Thumb-2 Linux nested functions with -O0 libgcc

Joseph S. Myers joseph@codesourcery.com
Wed May 20 14:55:00 GMT 2009


This patch fixes a problem calling nested functions on ARM EABI
GNU/Linux if libgcc is built for Thumb-2 with -O0.

The libgcc function __clear_cache, used when stack trampolines are in
use, is defined using an asm that puts the inputs in register
variables, an ARM-specific syscall number in a register variable for
r7, and calls the syscall.

r7 is also used as the frame pointer for Thumb.  If GCC eliminates the
frame pointer the asm works OK, but if not (in particular if building
with -O0) then the generated code ends up trying to use the syscall
number stored in r7 as the frame pointer for restoring values from the
stack.  To avoid this problem arising, it seems simplest to implement
this simple function directly in assembly, which this patch does.
Tested with no regressions with cross to arm-none-linux-gnueabi.  OK
to commit?

2009-05-20  Joseph Myers  <joseph@codesourcery.com>

	* config/arm/lib1funcs.asm (__clear_cache): Define if
	L_clear_cache.
	* config/arm/linux-eabi.h (CLEAR_INSN_CACHE): Define to give an
	error if used.
	* config/arm/t-linux-eabi (LIB1ASMFUNCS): Add _clear_cache.

Index: gcc/config/arm/lib1funcs.asm
===================================================================
--- gcc/config/arm/lib1funcs.asm	(revision 147732)
+++ gcc/config/arm/lib1funcs.asm	(working copy)
@@ -1096,6 +1096,26 @@
 	FUNC_END div0
 	
 #endif /* L_dvmd_lnx */
+#ifdef L_clear_cache
+@ EABI GNU/Linux call to cacheflush syscall.
+#if !defined __ARM_EABI__ || !defined __linux__
+#error "This is only for ARM EABI GNU/Linux"
+#endif
+	FUNC_START clear_cache
+	push	{r7}
+#if __ARM_ARCH__ >= 7 || defined(__ARM_ARCH_6T2__)
+	movw	r7, #2
+	movt	r7, #0xf
+#else
+	mov	r7, #0xf0000
+	add	r7, r7, #2
+#endif
+	mov	r2, #0
+	swi	0
+	pop	{r7}
+	RET
+	FUNC_END clear_cache
+#endif /* L_clear_cache */
 /* ------------------------------------------------------------------------ */
 /* Dword shift operations.  */
 /* All the following Dword shift variants rely on the fact that
Index: gcc/config/arm/linux-eabi.h
===================================================================
--- gcc/config/arm/linux-eabi.h	(revision 147732)
+++ gcc/config/arm/linux-eabi.h	(working copy)
@@ -72,16 +72,8 @@
    do not use -lfloat.  */
 #undef LIBGCC_SPEC
 
-/* Clear the instruction cache from `beg' to `end'.  This makes an
-   inline system call to SYS_cacheflush.  */
+/* Clear the instruction cache from `beg' to `end'.  This is
+   implemented in lib1funcs.asm, so ensure an error if this definition
+   is used.  */
 #undef  CLEAR_INSN_CACHE
-#define CLEAR_INSN_CACHE(BEG, END)					\
-{									\
-  register unsigned long _beg __asm ("a1") = (unsigned long) (BEG);	\
-  register unsigned long _end __asm ("a2") = (unsigned long) (END);	\
-  register unsigned long _flg __asm ("a3") = 0;				\
-  register unsigned long _scno __asm ("r7") = 0xf0002;			\
-  __asm __volatile ("swi 0		@ sys_cacheflush"		\
-		    : "=r" (_beg)					\
-		    : "0" (_beg), "r" (_end), "r" (_flg), "r" (_scno));	\
-}
+#define CLEAR_INSN_CACHE(BEG, END) not used
Index: gcc/config/arm/t-linux-eabi
===================================================================
--- gcc/config/arm/t-linux-eabi	(revision 147732)
+++ gcc/config/arm/t-linux-eabi	(working copy)
@@ -24,8 +24,8 @@
 MULTILIB_OPTIONS	=
 MULTILIB_DIRNAMES	=
 
-# Use a version of div0 which raises SIGFPE.
-LIB1ASMFUNCS := $(filter-out _dvmd_tls,$(LIB1ASMFUNCS)) _dvmd_lnx
+# Use a version of div0 which raises SIGFPE, and a special __clear_cache.
+LIB1ASMFUNCS := $(filter-out _dvmd_tls,$(LIB1ASMFUNCS)) _dvmd_lnx _clear_cache
 
 # Multilib the standard Linux files.  Don't include crti.o or crtn.o,
 # which are provided by glibc.

-- 
Joseph S. Myers
joseph@codesourcery.com



More information about the Gcc-patches mailing list