-finstrument-functions problems

Jeffrey Lee me at phlamethrower.co.uk
Tue Jan 20 14:46:09 PST 2004


Hi,

I've spent ages tracking this down, and still have no real idea why the
code is going wrong. What happens is that if -finstrument-functions is
used, the call_site parameter given to the instrumentation functions is
the corrupt. For example, in the following program: (Note that you may
need my __builtin_return_address patch to get it working at all)

--------------

#include <stdio.h>

void __cyg_profile_func_enter(int a,int b)
	__attribute__ ((no_instrument_function));
void __cyg_profile_func_exit(int a,int b)
	__attribute__ ((no_instrument_function));

void __cyg_profile_func_enter(int a,int b)
	{ printf("enter: %08x %08x\n",a,b); }
void __cyg_profile_func_exit(int a,int b)
	{ printf("exit: %08x %08x\n",a,b); }

void foo() { printf("foo\n"); }
void bar() { printf("bar\n"); foo(); }

int main(int argc,char **argv) { printf("main\n"); bar(); return 0; }

-------------

When bar() calls foo(), all the documentation I've seen suggests that
call_site should be the return address of foo() (i.e. a pointer to the
function after the BL into foo). However under RISC OS call_site is the BL
instruction itself. The (slightly tidied) assembly produced for foo is as
follows:

--------------

|foo|	mov	__ip, __sp
	stmfd	__sp!, {__v6, __fp, __ip, __lr, __pc}
	sub	__fp, __ip, #4
	cmp	__sp, __sl
	bllt	|__rt_stkovf_split_small|
	mov	__v6, __sp
	mov	__a1, #0
	bl	|__builtin_return_address|
	mov	__ip, __a1
	ldr	__a1, |L..12|
	ldr	__a2, [__ip, #-4]
	bl	|__cyg_profile_func_enter|
	ldr	__a1, |L..12|+4
	bl	|printf|
	mov	__a1, #0
	bl	|__builtin_return_address|
	mov	__ip, __a1
	ldr	__a1, |L..12|
	ldr	__a2, [__ip, #-4]
	bl	|__cyg_profile_func_exit|
	b	|L..11|
|L..12|	DCD	|foo|
	DCD	|LC..2|
|L..11|	ldmea	__fp, {__v6, __fp, __sp, __pc}

---------------

As you can see, the code calls __builtin_return_address, then loads from
[a1,#-4] and passes it into __cyg_profile_func_enter as a2. This shouldn't
be happening; it's almost as if the compiler treats
__builtin_return_address as __builtin_frame_address. After looking through
the GCC source I think the problem lies in gccsdk/gcc/gcc/builtins.c's
expand_builtin_return_addr() function, or some other function called from
that. As far as I can tell what happens is the following:

* expand_builtin_return_addr is called (from gccsdk/gcc/gcc/function.c)
with the arguments BUILT_IN_RETURN_ADDRESS, 0, hard_frame_pointer_rtx

* HAVE_BUILTIN_RETURN_ADDR_FUNC is #defined and evaluates to non-0, so a
function call to __builtin_return_address is output

* ... then the '/* Scan back COUNT frames to the specified frame.  */'
code is skipped, because count is 0.

* Then RETURN_ADDR_RTX is called, and the function exits with the
generated rtl.

RETURN_ADDR_RTX is #defined to arm_return_addr (found in
gccsdk/gcc/gcc/config/arm/arm.c). This looks like it makes a call to
get_hard_reg_initial_val(Pmode, LR_REGNUM).

At this point I gave up looking, since the code gets quite involved and I
don't have enough time to decipher it, or add debugging code to GCC and
see what's really going on.

Does anyone have any ideas as to what's happening?


 - Jeffrey




More information about the gcc mailing list