arm-coff-gcc function prologue w/ unsigned short parameter
The Chazman
chaz@devastator.extern.ucsd.edu
Tue May 9 21:37:00 GMT 2000
We've got both gcc 2.95.2 and egcs 2.91.57 compiling for an arm-coff target,
and both are exhibiting an identical strange behavior in some cases with
unsigned short parameters to functions and unsigned short local variables.
Unfortunately, I can only find one brief code snippet that clearly
exhibits the problem (others are long and complicated), and it uses inline
assembly. But I'll post it anyway, hoping that the inline assembly is
straightforward enough. It crops up other places that are pure ANSI C, so
I don't think the use of assembly is causing the problem.
pcx09> cat testus2.c
#include <stdio.h>
static unsigned short
swabw(unsigned short x)
{
__asm__("orr %0, %0, %0, lsl #16 ; mov %0, %0, lsr #8" : "+r" (x) );
return x & 0xffff;
}
void
testus2(unsigned short x)
{
printf("x = 0x%04x, swabbed = 0x%04x\r\n", x, swabw(x));
}
pcx09>
The swabw function swaps bytes within a short. Normally we inline that
function, but when we don't, we get this output from runs through the
testus2() function...
x = 0x1234, swabbed = 0x3412
x = 0x789a, swabbed = 0x9a78
x = 0x89ab, swabbed = 0xff89
In general, the failure mode is that whenever bit 15 is set in the input
to swabw, the output comes out with bits 15-8 all set regardless of what
bits 7-0 of the input were.
Again, when we inline swabw, this does not happen, as the bug appears in
the function prologue. Here's the assembly generated by this source file...
pcx09> odarm -d testus2.o
testus2.o: file format coff-arm-big
Disassembly of section .text:
00000000 <LM1>:
0: e1a0c00d mov ip, sp
4: e92dd800 stmdb sp!, {fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4
c: e1a00800 mov r0, r0, lsl #16
10: e1a00840 mov r0, r0, asr #16
00000014 <LM2>:
14: e1800800 orr r0, r0, r0, lsl #16
18: e1a00420 mov r0, r0, lsr #8
0000001c <LM3>:
1c: e1a00800 mov r0, r0, lsl #16
20: e1a00820 mov r0, r0, lsr #16
24: e91ba800 ldmdb fp, {fp, sp, pc}
00000028 <_testus2>:
28: e1a0c00d mov ip, sp
2c: e92dd810 stmdb sp!, {r4, fp, ip, lr, pc}
30: e24cb004 sub fp, ip, #4
34: e1a04800 mov r4, r0, lsl #16
38: e1a04824 mov r4, r4, lsr #16
3c: e1a00004 mov r0, r4
40: ebffffee bl 0 <LM1>
44: e1a02800 mov r2, r0, lsl #16
48: e1a01004 mov r1, r4
4c: e59f0008 ldr r0, 5c <L4>
50: e1a02822 mov r2, r2, lsr #16
54: ebfffffe bl 54 <_testus2+0x2c>
00000058 <LM6>:
58: e91ba810 ldmdb fp, {r4, fp, sp, pc}
0000005c <L4>:
5c: 00000000 andeq r0, r0, r0
pcx09>
The bug is at offset 0x10 into the disassembly. The parameter is
declared unsigned short, which should generate a mov r0, r0, lsr #16
instruction as it does elsewhere in the file. But an arithmetic shift
is generated instead of a logical one, which, considering the value
signed, fills the top 16 bits with ones if bit 15 is set. This is
the cause of the errant behavior we see with our printfs.
Has anyone seen this behavior before, erroneously treating unsigned
shorts as signed while zeroing out their top 16 bits before using them?
Is there an explanation for it? Should I report it as a gcc bug?
Thanks for your help...
-------------------------------------------
Carl Miller Firmware Engineer
chaz@gordian.com Gordian, Inc.
(714) 850-0205 http://www.gordian.com
(posted from my personal e-mail address since that's the one that's
subscribed to the list)
------
Want more information? See the CrossGCC FAQ, http://www.objsw.com/CrossGCC/
Want to unsubscribe? Send a note to crossgcc-unsubscribe@sourceware.cygnus.com
More information about the crossgcc
mailing list