[advanced programming] please find an error in source code

Ideas and dreaming will go this forum
Post Reply

geo650
Official SamyGO Developer
Posts: 303
Joined: Wed Oct 07, 2009 12:03 pm

[advanced programming] please find an error in source code

Post by geo650 »

Hello!
I am trying to find an error in source code of simple Content Library application. Maybe somebody else would see what causes the problem.

Here is the source code, compilation script and working executables of a simple Test application:
http://www.2shared.com/file/V-loZWGm/test.html
This app injects code for catching remote control buttons and blocks MUTE button as example task. Nothing more.

Now. Let's look at button_pressed() function in test_main.c file:

Code: Select all

int unused;

// function called when a button is pressed
static int button_pressed(int key) __attribute__ ((noinline));
static int button_pressed(int key)
{
  if (key == KEY_MUTE) key = KEY_NOTHING;	// example function: block MUTE button

  unused = key; 		// >>>>>> WITHOUT THIS IT CRASHES <<<<<<<< WHY? (Try to remove this line, recompile and see by yourself)
  return(key);
}
Then try to remove (or comment) the line with "unused = key;" command and recompile (using make.sh script). You'll see that test application is not working anymore. It will hang just after beeing loaded.

Now it is time to ask one simple question: WHY?

In my opinion, a variable called "unused" here shoud not have any influence on anything. But maybe the problem lays in a junction of high-level code and CPU/low-level-code (calling conventions, stack, alignment etc.) ??? Maybe I should use any additional compiler or linker directives? Please help me to understand what is going on. :?
sbav1
Official SamyGO Developer
Posts: 374
Joined: Fri Jan 15, 2010 10:20 am

Re: [advanced programming] please find an error in source code

Post by sbav1 »

geo650 wrote: Now it is time to ask one simple question: WHY?
My guess: button_pressed() call is probably "optimized out" completely by gcc. If button_pressed() gets simple enough, gcc optimizer concludes that this function is doing exactly nothing :).
Simplified stack pointer management in injection_press (no need to store LR register, w/o external function call) + "LDMFD SP!, {R4,LR}" == stack corruption.
geo650
Official SamyGO Developer
Posts: 303
Joined: Wed Oct 07, 2009 12:03 pm

Re: [advanced programming] please find an error in source code

Post by geo650 »

sbav1 wrote:My guess: button_pressed() call is probably "optimized out" completely by gcc. If button_pressed() gets simple enough, gcc optimizer concludes that this function is doing exactly nothing :).
Simplified stack pointer management in injection_press (no need to store LR register, w/o external function call) + "LDMFD SP!, {R4,LR}" == stack corruption.
Thank you for examining this problem.

I assume you are right. But it is strange that changing optimization flag from -O2 to -O0 doesn't help. Moreover, my button_pressed() function was much bigger before - with several "cases" in switch() command. I cut that function to make source code clear. It seems to be very strange why gcc "clears" button_pressed() function's contents. I think I must disassemble output binary to make sure what is done during compilation.

One more word:
After turning optimization off, an error was generated in cacheflush function:
Error: immediate expression requires a # prefix -- `mov r0,[fp,#-24]'
I had to modify one line to get rid of it:
// cache flush function for changes made (injected code area)
static void cacheflush(void *start, size_t size)
{
asm( // volatile(
"mov r0, %0\n"
"mov r1, %1\n"
"mov r2, #0\n"
"mov r7, #0xf0000\n"
"add r7, #0x02\n"
"swi #0\n"
: /* no outputs */
: "g"((unsigned long)start), "g"((unsigned long)start+size) /* inputs */
: "r0", "r1", "r2", "r7"); /* clobbered registers */
}
marcelru
Official SamyGO Developer
Posts: 171
Joined: Thu Oct 01, 2009 7:27 am

Re: [advanced programming] please find an error in source code

Post by marcelru »

Hi geo650
I think I must disassemble output binary to make sure what is done during compilation.
why not do

gcc -S -o filename.s filename.c?

Saves a disassembly run.
just my 2ct,


marcelr
sbav1
Official SamyGO Developer
Posts: 374
Joined: Fri Jan 15, 2010 10:20 am

Re: [advanced programming] please find an error in source code

Post by sbav1 »

geo650 wrote:It seems to be very strange why gcc "clears" button_pressed() function's contents.
Well, from gcc PoV, this is a null function (operates only on it's own arguments; return value seemingly discarded)..

Possible fixes:
1) move button_pressed() to separate .c file,
2) creative usage of 'volatile' statements
3) fix/rewrite injection sub (I know it basically works in its current form, but it's error-prone).
Last edited by sbav1 on Sun May 01, 2011 9:24 pm, edited 1 time in total.
geo650
Official SamyGO Developer
Posts: 303
Joined: Wed Oct 07, 2009 12:03 pm

Re: [advanced programming] please find an error in source code

Post by geo650 »

marcelru wrote:why not do

gcc -S -o filename.s filename.c?

Saves a disassembly run.
Thank you marcelr for your 2ct. Thanks to your idea, I quote two versions of compiled button_pressed() function, with my comments.
First, working version:

Code: Select all

.align	2
	.type	button_pressed, %function
button_pressed:                       <-------------- function entry point
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	cmp	r0, #15                      <-------------- if (r0_key != KEY_MUTE)...
	movne	r2, r0                     <-------------- ...r2_key = 0;
	moveq	r2, #255                   <-------------- ...else r2_key = KEY_NOTHING;
	ldr	r3, .L5                      <-------------- r3_unused = unused;
	mov	r0, r2                       <-------------- r0_key = r2_key;
	@ lr needed for prologue
	str	r2, [r3, #0]                 <-------------- unused = r3_unused;
	bx	lr                            <-------------- return; // while r0 register still contains new 'key' value
.L6:
	.align	2
.L5:
	.word	unused                     <-------------- int unused;
	.size	button_pressed, .-button_pressed
Next, hanging version, with extra operations on "unused" integer removed:

Code: Select all

.align	2
	.type	button_pressed, %function
button_pressed:                           <-------------- function entry point
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	cmp	r0, #15                          <-------------- if (r0_key == KEY_MUTE)...
	moveq	r0, #255                       <-------------- r0_key = KEY_NOTHING;   // else r0_key stays untouched
	@ lr needed for prologue
	bx	lr                                <-------------- return; // while r0 register still contains new 'key' value
	.size	button_pressed, .-button_pressed
Well, I can see no errors in the listings above. But the differences begin to come out in injection_press() function:

Again, a piece of working code:

Code: Select all

...
injection_press:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	str	lr, [sp, #-4]!
	sub	sp, sp, #4
#APP
	STMFD   SP!, {R0,R2,R3,R12}

	mov	r0, r1                   <------------- // set input argument (key)
	bl	button_pressed            <------------- // call button_pressed() function
#APP
	MOV     R1, R0 
...
And "bad" code:

Code: Select all

...
injection_press:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	@ lr needed for prologue
#APP
	STMFD   SP!, {R0,R2,R3,R12}
                                               <-------------- where it is ?????????????
	MOV     R1, R0
...
As you can see, calling of button_pressed() function disappeared.

@sbav1: I still don't understand how gcc could treat this function as a null one. Function looks like very "classic": it gets a value, processes that value and returns other value. I cannot see the reason to remove it since it is even called within another function, so it is used. Even R0 register returned in asm point of view, also is used later.
Maybe I will never understand this case, but please don't worry about me. Of course, it is always better to understand how code works - that's why I asked you for help. Anyways, I will try to re-design my code to get rid of this problem. Thanks for your suggestions.
sbav1
Official SamyGO Developer
Posts: 374
Joined: Fri Jan 15, 2010 10:20 am

Re: [advanced programming] please find an error in source code

Post by sbav1 »

BTW, this part:

Code: Select all

injection_press:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	str	lr, [sp, #-4]!
	sub	sp, sp, #4
        ...
looks a little suspicious.. after that, we do

Code: Select all

"LDMFD   SP!, {R4,LR}\n"
i.e "restoring" R4 with some random data from the stack. Anyway, it's most probably harmless (new value being stored in R4 later on, in original function).
geo650
Official SamyGO Developer
Posts: 303
Joined: Wed Oct 07, 2009 12:03 pm

Re: [advanced programming] please find an error in source code

Post by geo650 »

sbav1 wrote:BTW, this part... looks a little suspicious..
I didn't notice this before. Yes, it is odd. But... this is the working code :shock:

Bad code doesn't push LR register to SP and maybe it hangs because of "LDMFD SP!, {R4,LR}" instruction which is left untouched since it was intentionally programmed in asm block. Why R4 is set there in that way (I mean "LDMFD SP!, {R4,LR}"), I simply don't know (as you may know, it is not my code, hihi). LR register is stored - OK, but what about R4? As you wrote, R4 is replaced with a new value later in exeDSP so probably it is not important. I suppose, the first part of suspicious code you quoted is generated by gcc and stores "too many" data on stack, so R4 must be used later to restore the valid stack pointer.

Now I know the place where it starts to hang.
nbd
Posts: 160
Joined: Wed Jan 13, 2010 12:02 pm

Re: [advanced programming] please find an error in source code

Post by nbd »

Hello, I remember having similar problems when I first started fiddling around with the injection code (around the time when injectso was introduced on the forum). I think I never understood why.

Post Reply

Return to “[B] Brainstorm”