This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFC: AMD64 gprof support for Solaris 2.10
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 26 Apr 2007 17:42:49 -0700
- Subject: RFC: AMD64 gprof support for Solaris 2.10
- Reply-to: mark at codesourcery dot com
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 {