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]

Save call-clobbered registers in _mcount on 32-bit Solaris/x86 (PR target/38239)


I've recently been pointed at PR target/38239, where trivial programs
compiled/linked with -pg SEGV on 32-bit Solaris/x86 since _mcount
clobbers %ecx.  It was initially reported for gcc 4.3, but I couldn't
reproduce it there and the testcase works fine up to and including gcc
4.8.  Since 4.9, the SEGV reported occurs again.

Upon closer investigation (checking i386.c (x86_function_profiler),
final.c (profile_function) and the _mcount implemtations of glibc and
BSDs), it turns out that _mcount isn't called like a regular function,
but is expected to save and restore call-clobbered registers itself.
Unfortunately, there's no specification on how _mcount is expected to
behave.

The fix is trivial, of course.  Bootstrapped without regressions on
i386-pc-solaris2.1[012].  Will install on mainline soon, and on the 5
and 4.9 branches in about a week, given that this is a longstanding
regression that makes -pg profiling unusable/unreliable.

	Rainer


2016-03-11  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	PR target/38239
	* config/sol2/gmon.c [__i386__] (_mcount): Save and restore
	call-clobbered registers.
	(internal_mcount): Remove __i386__ handling.

# HG changeset patch
# Parent  2a1815d64dfb93b0ac1d59c094d4da5347634d38
Save call-clobbered registers in _mcount on 32-bit Solaris/x86 (PR target/38239)

diff --git a/libgcc/config/sol2/gmon.c b/libgcc/config/sol2/gmon.c
--- a/libgcc/config/sol2/gmon.c
+++ b/libgcc/config/sol2/gmon.c
@@ -44,11 +44,7 @@
 
 extern void monstartup (char *, char *);
 extern void _mcleanup (void);
-#ifdef __i386__
-static void internal_mcount (void) __attribute__ ((used));
-#else
 static void internal_mcount (char *, unsigned short *) __attribute__ ((used));
-#endif
 static void moncontrol (int);
 
 struct phdr {
@@ -223,8 +219,19 @@ void
 /* Solaris 2 libraries use _mcount.  */
 #if defined __i386__
 asm(".globl _mcount\n"
+    "	.type	_mcount, @function\n"
     "_mcount:\n"
-    "	jmp	internal_mcount\n");
+    /* Save and restore the call-clobbered registers.  */
+    "	pushl	%eax\n"
+    "	pushl	%ecx\n"
+    "	pushl	%edx\n"
+    "	movl	12(%esp), %edx\n"
+    "	movl	4(%ebp), %eax\n"
+    "	call	internal_mcount\n"
+    "	popl	%edx\n"
+    "	popl	%ecx\n"
+    "	popl	%eax\n"
+    "	ret\n");
 #elif defined __x86_64__
 /* See GLIBC for additional information about this technique.  */
 asm(".globl _mcount\n" 
@@ -299,32 +306,13 @@ asm(".global _mcount\n"
 #endif
 
 static void
-#ifdef __i386__
-internal_mcount (void)
-#else
 internal_mcount (char *selfpc, unsigned short *frompcindex)
-#endif
 {
   struct tostruct *top;
   struct tostruct *prevtop;
   long toindex;
   static char already_setup;
 
-#ifdef __i386__
-  char *selfpc;
-  unsigned short *frompcindex;
-
-  /* Find the return address for mcount and the return address for mcount's
-     caller.  */
-
-  /* selfpc = pc pushed by mcount call.
-     This identifies the function that was just entered.  */
-  selfpc = (void *) __builtin_return_address (0);
-  /* frompcindex = pc in preceding frame.
-     This identifies the caller of the function just entered.  */
-  frompcindex = (void *) __builtin_return_address (1);
-#endif
-
 /* Only necessary without the Solaris CRTs or a proper gcrt1.o, otherwise
    crtpg.o or gcrt1.o take care of that.
 
# HG changeset patch
# Parent  bc0ec420e463ad63db543a27592dd7dca577b7ad
Save call-clobbered registers in _mcount on 32-bit Solaris/x86 (PR target/38239)

diff --git a/libgcc/config/gmon-sol2.c b/libgcc/config/gmon-sol2.c
--- a/libgcc/config/gmon-sol2.c
+++ b/libgcc/config/gmon-sol2.c
@@ -43,11 +43,7 @@
 
 extern void monstartup (char *, char *);
 extern void _mcleanup (void);
-#ifdef __i386__
-static void internal_mcount (void) __attribute__ ((used));
-#else
 static void internal_mcount (char *, unsigned short *) __attribute__ ((used));
-#endif
 static void moncontrol (int);
 
 struct phdr {
@@ -222,8 +218,19 @@ void
 /* Solaris 2 libraries use _mcount.  */
 #if defined __i386__
 asm(".globl _mcount\n"
+    "	.type	_mcount, @function\n"
     "_mcount:\n"
-    "	jmp	internal_mcount\n");
+    /* Save and restore the call-clobbered registers.  */
+    "	pushl	%eax\n"
+    "	pushl	%ecx\n"
+    "	pushl	%edx\n"
+    "	movl	12(%esp), %edx\n"
+    "	movl	4(%ebp), %eax\n"
+    "	call	internal_mcount\n"
+    "	popl	%edx\n"
+    "	popl	%ecx\n"
+    "	popl	%eax\n"
+    "	ret\n");
 #elif defined __x86_64__
 /* See GLIBC for additional information about this technique.  */
 asm(".globl _mcount\n" 
@@ -298,32 +305,13 @@ asm(".global _mcount\n"
 #endif
 
 static void
-#ifdef __i386__
-internal_mcount (void)
-#else
 internal_mcount (char *selfpc, unsigned short *frompcindex)
-#endif
 {
   struct tostruct *top;
   struct tostruct *prevtop;
   long toindex;
   static char already_setup;
 
-#ifdef __i386__
-  char *selfpc;
-  unsigned short *frompcindex;
-
-  /* Find the return address for mcount and the return address for mcount's
-     caller.  */
-
-  /* selfpc = pc pushed by mcount call.
-     This identifies the function that was just entered.  */
-  selfpc = (void *) __builtin_return_address (0);
-  /* frompcindex = pc in preceding frame.
-     This identifies the caller of the function just entered.  */
-  frompcindex = (void *) __builtin_return_address (1);
-#endif
-
   if(!already_setup) {
     extern char etext[];
 
-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University

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