Hi Konstantin

Konstantin Belousov wrote:
Author: kib
Date: Mon Oct 13 12:45:18 2008
New Revision: 183818
URL: http://svn.freebsd.org/changeset/base/183818

Log:
  MFC r180756 (by luoqi):
  Unbreak cc -pg support on i386 by changing mcount() to always preserve %ecx.
Approved by: re (kensmith)

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/i386/include/profile.h

Modified: stable/7/sys/i386/include/profile.h
==============================================================================
--- stable/7/sys/i386/include/profile.h Mon Oct 13 12:28:33 2008        
(r183817)
+++ stable/7/sys/i386/include/profile.h Mon Oct 13 12:45:18 2008        
(r183818)
@@ -115,7 +115,15 @@ void user(void);
 void                                                                   \
 mcount()                                                               \
 {                                                                      \
-       uintfptr_t selfpc, frompc;                                      \
+       uintfptr_t selfpc, frompc, ecx;                                 \
+       /*                                                              \
+        * In gcc 4.2, ecx might be used in the caller as the arg       \
+        * pointer if the stack realignment option is set (-mstackrealign) \
+        * or if the caller has the force_align_arg_pointer attribute   \
+        * (stack realignment is ALWAYS on for main).  Preserve ecx     \
+        * here.                                                        \
+        */                                                             \
+       __asm("" : "=c" (ecx));                                             \
        /*                                                              \
         * Find the return address for mcount,                          \
         * and the return address for mcount's caller.                  \
@@ -132,6 +140,7 @@ mcount()                                                    
        \
        __asm("movl (%%ebp),%0" : "=r" (frompc));                   \
        frompc = ((uintfptr_t *)frompc)[1];                             \
        _mcount(frompc, selfpc);                                        \
+       __asm("" : : "c" (ecx));                                    \
 }
 #else /* !__GNUCLIKE_ASM */
 #define        MCOUNT

This fix is conceptually broken and an accident waiting to happen. There is no way to prevent the compiler from shuffling instructions and clobbering %ecx. Here is a simple example, which demonstrates this problem:

unsigned f(unsigned a)
{
        unsigned ecx;
        asm("nop" : "=c" (ecx));
        a = 1 << a;
        asm("nop" : : "c" (ecx));
        return a;
}

GCC compiles this to:
f:
#APP
        nop
        nop
#NO_APP
        movl    4(%esp), %ecx
        movl    $1, %eax
        sall    %cl, %eax
        ret

As you can see, %ecx gets destroyed (GCC does not emit the #APP marker for empty asm statements, so I added "nop" for clarity. Even then GCC merged the two #APP blocks!). In mcount() the compiler could choose to place selfpc or frompc into %ecx and change the order of statements, which would destroy the contents of %ecx. In fact, if -mstackrealign is used, the stack realignment in mcount() destroys %ecx before any of the inline assembler statements is executed for sure. The only safe way is to implement mcount() using a global asm statement:

#define _MCOUNT_DECL static __attribute((cdecl,noinline)) void _mcount

#define MCOUNT                                         \
asm(                                                   \
        ".globl mcount\n\t"                            \
        ".type     mcount, @function\n"                   \
        "mcount:\n\t"                                  \
        "pushl %ecx\n\t"                               \
        "pushl 4(%esp)\n\t" // my return address       \
        "pushl 4(%ebp)\n\t" // caller's return address \
        "call  _mcount\n\t"                            \
        "addl  $8, %esp\n\t"                           \
        "pop   %ecx\n\t"                               \
        "ret\n\t"                                      \
        ".size   mcount, .-mcount");

Considering the whole issue, I think this is a bug/misfeature of GCC. It could easily restore %ecx after calling mcount(), which it does for any normal (i.e. non-pg-induced) function call().


On a related note, I have submitted PR i386/127387 with patch (http://www.freebsd.org/cgi/query-pr.cgi?pr=i386/127387) about a similar problem in _start() in crt1.c for x86.

Regards
        Christoph
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to