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]"