Hello,
I'm trying to migrate to gcc 4.4.3 and eabi (from 4.0.3 non-eabi) for
the ARM targets of Rockbox[1]. I have the strong feeling I stumbled upon
a gcc bug here.
The story:
The core and codecs run fine under the new compiler, however at least 1
plugin is problematic: mpegplayer[2]. The cpu throws a data abort when
rendering begins.
I've narrowed down the problem to the following function call:
mpeg2_idct_add (last, decoder->DCTblock, dest, stride);[3]
mpeg2_idct_add itself is written entirely in assembler. gcc doesn't
touch it. However, its prototype for C callers is[4]:
void mpeg2_idct_add(const int last, int16_t * block,
uint8_t * dest, const int stride);
According to the (E)ABI, all parameters are supposed to be passed in the
registers r0-3.
The disassembly shows that this only happens for the old gcc4.0.3
new gcc:
30788e98: ebfff984 bl 307874b0 <get_non_intra_block>
30788e9c: e1a03000 mov r3, r0
30788ea0: e58d301c str r3, [sp, #28]
30788ea4: e59d3014 ldr r3, [sp, #20]
30788ea8: e59330d0 ldr r3, [r3, #208] ; 0xd0
30788eac: e59d2008 ldr r2, [sp, #8]
30788eb0: e58d2000 str r2, [sp]
30788eb4: e59d001c ldr r0, [sp, #28]
30788eb8: e1a02003 mov r2, r3
30788ebc: e59d300c ldr r3, [sp, #12]
30788ec0: ebffe28a bl 307818f0 <mpeg2_idct_add>
old gcc:
30794760: ebffc861 bl 307868ec <get_non_intra_block>
30794764: e1a03000 mov r3, r0
30794768: e58d3014 str r3, [sp, #20]
3079476c: e59d3010 ldr r3, [sp, #16]
30794770: e59330d0 ldr r3, [r3, #208]
30794774: e59d0014 ldr r0, [sp, #20]
30794778: e1a01003 mov r1, r3
3079477c: e59d2008 ldr r2, [sp, #8]
30794780: e59d3004 ldr r3, [sp, #4]
30794784: ebffb4ea bl 30781b34 <mpeg2_idct_add>
(the above disassemblies are from code generated with -O0 to make the
parameter passig obvious)
On 4.4.3, 1 parameter is passed via the stack (I figured it goes like
this from the old to the new compiler: r0 = r0; r1 > r2; r2 > r3; r3 >
stack). So, this call works fine with 4.0.3, but does not with 4.4.3.
Now the reason why I think this is a gcc bug:
If I change the prototype to (the 2nd and 4th argument are swapped, I
didn't change the callee or the caller, so gcc obviously throws warnings
but the effective parameter passing was the same):
void mpeg2_idct_add(const int last, const int stride,
uint8_t * dest, int16_t * block);
then the plugin runs fine, without data abort. And the disassembly shows
correct parameter passing.
EABI IIRC only mentions changed rules for passing 64bit types. This call
should have been the same with 4.4.3. It eventually is if the parameters
are in a different order.
If this is really a gcc bug, how should we proceed? I assume a bug
report on bugzilla?
Best regards.
[1]: http://www.rockbox.org/
[2]: http://www.rockbox.org/wiki/PluginMpegplayer
[3]:
http://svn.rockbox.org/viewvc.cgi/trunk/apps/plugins/mpegplayer/slice.c?revision=17904&view=markup
[4]:
http://svn.rockbox.org/viewvc.cgi/trunk/apps/plugins/mpegplayer/mpeg2_internal.h?revision=23677&view=markup