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]

RFC: AMD64 gprof support for Solaris 2.10


This patch makes -pg work on AMD64 Solaris 2.10.  This patch is
actually against 4.1; I haven't yet tested with mainline.  However,
while I'm doing that, I thought that it would be a good idea to post
this to see if any Solaris or AMD64 experts spotted issues.

The changes are:

1. Use size_t/ptrdiff_t instead of "int" to make the code 64-bit safe.

2. In 64-bit mode, make _mcount be a stub routine, rather than just a
   jump, since the SELFPC and FROMPCINDEX values are not accessibleas
   readily as in 32-bit mode.

3. Recognize that 64-bit applications are zero-based, rather than
   starting at the magic 0x80400000 address.

These changes get the tests in the testsuite passing on Solaris 2.10
in 64-bit mode, and, empirically, work when using -pg to compile
programs: the gprof output looks plausible.

Any comments from relevant maintainers?  If not, I plan to
forward-port the patch, test, and commit.

Thanks,

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2007-03-28  Mark Mitchell  <mark@codesourcery.com>

	gcc/
	* config/i386/gmon-sol2.c (size_t): New type.
	(intptr_t): Likewise.
	(s_textsize): Declare as size_t.
	(sbrk): Declare.
	(monstartup): Use size_t for sizes.
	(_mcount): Save and restore registers.
	(internal_mcount): Pass 0 as the first argument to monstartup
	in 64-bit mode.
	(moncontrol): Convert pointer to appropriately sized integer
	beforepassing to profil.

Index: gcc/config/i386/gmon-sol2.c
===================================================================
--- gcc/config/i386/gmon-sol2.c	(revision 167163)
+++ gcc/config/i386/gmon-sol2.c	(revision 167164)
@@ -105,6 +105,9 @@ struct rawarc {
 extern char *sbrk ();
 #endif
 
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ intptr_t;
+
     /*
      *	froms is actually a bunch of unsigned shorts indexing tos
      */
@@ -114,7 +117,7 @@ static struct tostruct	*tos = 0;
 static long		tolimit = 0;
 static char		*s_lowpc = 0;
 static char		*s_highpc = 0;
-static unsigned long	s_textsize = 0;
+static size_t		s_textsize = 0;
 
 static int	ssiz;
 static char	*sbuf;
@@ -126,23 +129,25 @@ static int	s_scale;
 
 extern int errno;
 
+extern void *sbrk (intptr_t);
+
 monstartup(lowpc, highpc)
     char	*lowpc;
     char	*highpc;
 {
-    int			monsize;
+    size_t		monsize;
     char		*buffer;
-    register int	o;
+    register size_t	o;
 
 	/*
 	 *	round lowpc and highpc to multiples of the density we're using
 	 *	so the rest of the scaling (here and in gprof) stays in ints.
 	 */
     lowpc = (char *)
-	    ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
+	    ROUNDDOWN((size_t)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
     s_lowpc = lowpc;
     highpc = (char *)
-	    ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
+	    ROUNDUP((size_t)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
     s_highpc = highpc;
     s_textsize = highpc - lowpc;
     monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
@@ -244,20 +249,62 @@ _mcleanup()
     close( fd );
 }
 
+#ifdef __x86_64__
+/* See GLIBC for additional information about this technique.  */
+asm(".globl _mcount\n" 
+    "\t.type\t_mcount, @function\n"
+    "_mcount:\n"
+    /* The compiler calls _mcount after the prologue, and does not
+       save any of the registers.  Therefore we must preserve all
+       seven registers which may contain function arguments.  */
+    "\tsubq\t$0x38,%rsp\n"
+    "\tmovq\t%rax,(%rsp)\n"
+    "\tmovq\t%rcx,0x08(%rsp)\n"
+    "\tmovq\t%rdx,0x10(%rsp)\n"
+    "\tmovq\t%rsi,0x18(%rsp)\n"
+    "\tmovq\t%rdi,0x20(%rsp)\n"
+    "\tmovq\t%r8,0x28(%rsp)\n"
+    "\tmovq\t%r9,0x30(%rsp)\n"
+    /* Get SELFPC (pushed by the call to this function) and
+       FROMPCINDEX (via the frame pointer.  */
+    "\tmovq\t0x38(%rsp),%rdi\n"
+    "\tmovq\t0x8(%rbp),%rsi\n"
+    "\tcallq\tinternal_mcount\n"
+    /* Restore the saved registers.  */
+    "\tmovq\t0x30(%rsp),%r9\n"
+    "\tmovq\t0x28(%rsp),%r8\n"
+    "\tmovq\t0x20(%rsp),%rdi\n"
+    "\tmovq\t0x18(%rsp),%rsi\n"
+    "\tmovq\t0x10(%rsp),%rdx\n"
+    "\tmovq\t0x08(%rsp),%rdx\n"
+    "\tmovq\t(%rsp),%rax\n"
+    "\taddq\t$0x38,%rsp\n"
+    "\tretq\n"
+    );
+#else
 /* Solaris 2 libraries use _mcount.  */
 asm(".globl _mcount; _mcount: jmp internal_mcount");
 /* This is for compatibility with old versions of gcc which used mcount.  */
 asm(".globl mcount; mcount: jmp internal_mcount");
+#endif
 
-internal_mcount()
+internal_mcount(
+#ifdef __x86_64__
+		char *selfpc,
+		char *frompcindex
+#endif
+)
 {
+#ifndef __x86_64__
 	register char			*selfpc;
 	register unsigned short		*frompcindex;
+#endif
 	register struct tostruct	*top;
 	register struct tostruct	*prevtop;
 	register long			toindex;
 	static char already_setup;
 
+#ifndef __x86_64__
 	/*
 	 *	find the return address for mcount,
 	 *	and the return address for mcount's caller.
@@ -269,12 +316,16 @@ internal_mcount()
 	/* 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 etext();
 	  already_setup = 1;
-/*	  monstartup(0, etext); */
+#ifdef __x86_64__
+	  monstartup(0, etext);
+#else
 	  monstartup(0x08040000, etext);
+#endif
 #ifdef USE_ONEXIT
 	  on_exit(_mcleanup, 0);
 #else
@@ -395,7 +446,7 @@ moncontrol(mode)
       /* start */
       profil((unsigned short *)(sbuf + sizeof(struct phdr)),
 	     ssiz - sizeof(struct phdr),
-	     (int)s_lowpc, s_scale);
+	     (size_t)s_lowpc, s_scale);
       
       profiling = 0;
     } else {


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