svn commit: r183818 - in stable/7/sys: . i386/include
Christoph Mallon
christoph.mallon at gmx.de
Tue Oct 14 12:34:11 UTC 2008
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
More information about the svn-src-all
mailing list