This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Incorrect code for __builtin_frame_address(0)


Hello,

 Tracking down an obscure segmentation fault in glibc, I've discovered we 
get the return value of __builtin_frame_address(0) wrong if 
-fomit-frame-pointer is used.  It happens even for platforms for which the 
flag is the default when optimizing!

 Example code:

$ cat getfp.c
void *getfp(void)
{
	return __builtin_frame_address(0);
}
$ mipsel-linux-gcc -O2 -fomit-frame-pointer -c getfp.c -o 
mipsel-linux-getfp.o
$ mipsel-linux-objdump -d mipsel-linux-getfp.o

mipsel-linux-getfp.o:     file format elf32-tradlittlemips

Disassembly of section .text:

00000000 <getfp>:
   0:	27bdfff8 	addiu	sp,sp,-8
   4:	afbe0000 	sw	s8,0(sp)
   8:	03c01021 	move	v0,s8
   c:	8fbe0000 	lw	s8,0(sp)
  10:	03e00008 	jr	ra
  14:	27bd0008 	addiu	sp,sp,8
	...
$ i386-linux-gcc -O2 -fomit-frame-pointer -c getfp.c -o i386-linux-getfp.o
$ i386-linux-objdump -d i386-linux-getfp.o

i386-linux-getfp.o:     file format elf32-i386

Disassembly of section .text:

00000000 <getfp>:
   0:	55                   	push   %ebp
   1:	89 e8                	mov    %ebp,%eax
   3:	5d                   	pop    %ebp
   4:	c3                   	ret    

$ alpha-linux-gcc -O2 -fomit-frame-pointer -c getfp.c -o 
alpha-linux-getfp.o
$ alpha-linux-objdump -d alpha-linux-getfp.o

alpha-linux-getfp.o:     file format elf64-alpha

Disassembly of section .text:

0000000000000000 <getfp>:
   0:	f0 ff de 23 	lda	sp,-16(sp)
   4:	00 04 ef 47 	mov	fp,v0
   8:	00 00 5e b7 	stq	ra,0(sp)
   c:	08 00 fe b5 	stq	fp,8(sp)
  10:	00 00 5e a7 	ldq	ra,0(sp)
  14:	08 00 fe a5 	ldq	fp,8(sp)
  18:	10 00 de 23 	lda	sp,16(sp)
  1c:	01 80 fa 6b 	ret

Obviously wrong...

 I've narrowed it down to expand_builtin_return_addr() referring to 
"hard_frame_pointer_rtx", which may not hold the actual frame pointer if 
-fomit-frame-pointer is used.  An obvious fix is below, prepared and 
tested with GCC 4.0.0 for platforms I have tools immediately available 
for, that is: alpha-linux, i386-linux and mipsel-linux (I've skipped other 
MIPS variants as obviously the same), by using the code as quoted above 
and proof-reading the output:

$ mipsel-linux-objdump -d mipsel-linux-getfp.o

mipsel-linux-getfp.o:     file format elf32-tradlittlemips

Disassembly of section .text:

00000000 <getfp>:
   0:	03e00008 	jr	ra
   4:	03a01021 	move	v0,sp
	...
$ i386-linux-objdump -d i386-linux-getfp.o

i386-linux-getfp-1.o:     file format elf32-i386

Disassembly of section .text:

00000000 <getfp>:
   0:	89 e0                	mov    %esp,%eax
   2:	c3                   	ret    
$ alpha-linux-objdump -d alpha-linux-getfp.o

alpha-linux-getfp-1.o:     file format elf64-alpha

Disassembly of section .text:

0000000000000000 <getfp>:
   0:	00 04 fe 47 	mov	sp,v0
   4:	01 80 fa 6b 	ret
   8:	1f 04 ff 47 	nop	
   c:	00 00 fe 2f 	unop	

I've verified code is still OK if -fno-omit-frame-pointer is in effect.

 I've done a quick check with GCC 3.2.3, 3.3.5 and 3.4.4 and they appear 
to suffer from this bug as well; the lack of differences in the affected 
functions makes me believe the bug is present in the HEAD, too.

2005-06-03  Maciej W. Rozycki  <macro@linux-mips.org>

	* config/alpha/alpha.h (INITIAL_FRAME_ADDRESS_RTX): New macro.
	* config/i386/i386.h (INITIAL_FRAME_ADDRESS_RTX): Likewise.
	* config/mips/mips.h (INITIAL_FRAME_ADDRESS_RTX): Likewise.

 Please apply.  Though for the HEAD, using "frame_pointer_rtx" as the 
default in place of "hard_frame_pointer_rtx" might be a reasonable 
alternative.  Other platforms that implement -fomit-frame-pointer may need 
a similar fix -- currently only s390.h defines INITIAL_FRAME_ADDRESS_RTX.

  Maciej

gcc-4.0.0-frame_address.patch
diff -up --recursive --new-file gcc-4.0.0.macro/gcc/config/alpha/alpha.h gcc-4.0.0/gcc/config/alpha/alpha.h
--- gcc-4.0.0.macro/gcc/config/alpha/alpha.h	2005-04-17 06:39:08.000000000 +0000
+++ gcc-4.0.0/gcc/config/alpha/alpha.h	2005-06-03 00:25:43.000000000 +0000
@@ -936,6 +936,10 @@ extern int alpha_memory_latency;
 
 #define FIRST_PARM_OFFSET(FNDECL) 0
 
+/* Defining this macro makes __builtin_frame_address(0) work
+   with -fomit-frame-pointer.  */
+#define INITIAL_FRAME_ADDRESS_RTX frame_pointer_rtx
+
 /* Definitions for register eliminations.
 
    We have two registers that can be eliminated on the Alpha.  First, the
diff -up --recursive --new-file gcc-4.0.0.macro/gcc/config/i386/i386.h gcc-4.0.0/gcc/config/i386/i386.h
--- gcc-4.0.0.macro/gcc/config/i386/i386.h	2005-04-05 22:59:21.000000000 +0000
+++ gcc-4.0.0/gcc/config/i386/i386.h	2005-06-03 00:26:10.000000000 +0000
@@ -1655,6 +1655,10 @@ enum reg_class
 /* Offset of first parameter from the argument pointer register value.  */
 #define FIRST_PARM_OFFSET(FNDECL) 0
 
+/* Defining this macro makes __builtin_frame_address(0) work
+   with -fomit-frame-pointer.  */
+#define INITIAL_FRAME_ADDRESS_RTX frame_pointer_rtx
+
 /* Define this macro if functions should assume that stack space has been
    allocated for arguments even when their values are passed in registers.
 
diff -up --recursive --new-file gcc-4.0.0.macro/gcc/config/mips/mips.h gcc-4.0.0/gcc/config/mips/mips.h
--- gcc-4.0.0.macro/gcc/config/mips/mips.h	2005-04-15 07:00:18.000000000 +0000
+++ gcc-4.0.0/gcc/config/mips/mips.h	2005-06-03 00:26:34.000000000 +0000
@@ -2149,6 +2149,10 @@ extern enum reg_class mips_char_to_class
 /* The argument pointer always points to the first argument.  */
 #define FIRST_PARM_OFFSET(FNDECL) 0
 
+/* Defining this macro makes __builtin_frame_address(0) work
+   with -fomit-frame-pointer.  */
+#define INITIAL_FRAME_ADDRESS_RTX frame_pointer_rtx
+
 /* o32 and o64 reserve stack space for all argument registers.  */
 #define REG_PARM_STACK_SPACE(FNDECL) 			\
   (TARGET_OLDABI					\


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]