Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Oct 2008 14:08:41 +0200
From:      Christoph Mallon <christoph.mallon@gmx.de>
To:        Kostik Belousov <kostikbel@gmail.com>
Cc:        svn-src-stable@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   Re: svn commit: r183818 - in stable/7/sys: . i386/include
Message-ID:  <48F5DD49.6040003@gmx.de>
In-Reply-To: <20081015112810.GN7782@deviant.kiev.zoral.com.ua>
References:  <200810131245.m9DCjIsR076490@svn.freebsd.org> <48F48B7F.5030009@gmx.de> <20081015112810.GN7782@deviant.kiev.zoral.com.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
Kostik Belousov wrote:
> On Tue, Oct 14, 2008 at 02:07:27PM +0200, Christoph Mallon wrote:
>> 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.

[...]

>> 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().
> I was worried too about suspiciously looking direct asm manipulations of
> the registers that could interfere with optimizer, when I have seen the
> patch committed to the HEAD. On the other hand, it magically works for
> the present version of the gcc and used compiler flags.

No, it does not work. I exactly described the scenario in which it plain 
breaks: If you use -mstackrealign, then mcount() gets realignment code 
too, which destroys the contents of %ecx *before* any of the inline 
assembler statemets get executed. The first thing the compiler inserts 
into mcount() is this line:

	leal    4(%esp), %ecx

This immediately destroys %ecx. And even if you do not use 
-mstackrealign - as I explained - you have *no* guarantee that you get 
the contents of %ecx from before the function call. It depends on the 
exact switches (which GCC has dozens of) to not explode - have you 
tested *all* combinations?

> We cannot have any other fix for 7.1, I suspect.

We should, for the reasons explained above.

> Feel free to submit more accurate patch.

Um, I *did*. See the code above.

Regards
	Christoph



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?48F5DD49.6040003>