This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Save call-clobbered registers in _mcount on 32-bit Solaris/x86 (PR target/38239)
- From: Rainer Orth <ro at CeBiTec dot Uni-Bielefeld dot DE>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 15 Mar 2016 11:28:47 +0100
- Subject: Save call-clobbered registers in _mcount on 32-bit Solaris/x86 (PR target/38239)
- Authentication-results: sourceware.org; auth=none
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