[En-Nut-Discussion] Probable GCC Compiler error, was: Re: Problem with ARM floating point, again
Bob Wirka
bobwirka at yahoo.com
Mon Sep 16 16:47:47 CEST 2013
Will try replying again; looks like I've got issues with my email...
Yes, this is a compiler issue. Again, I'm using the Codesourcery compiler for an AT91SAM7X512 project.
The "nut" of it is that the va_arg() macro fails for 8-byte values if the va_list pointer ends in '0'.
Example va_arg() math from line 449 of putf.c:
449 _double = va_arg(ap, double);
- 0xa104 <_putf+2412>: ldr r3, [r11, #-124] ; 0x7c
- 0xa108 <_putf+2416>: add r3, r3, #7
- 0xa10c <_putf+2420>: bic r3, r3, #7
- 0xa110 <_putf+2424>: add r2, r3, #8
- 0xa114 <_putf+2428>: str r2, [r11, #-124] ; 0x7c
- 0xa118 <_putf+2432>: ldm r3, {r3, r4}
- 0xa11c <_putf+2436>: str r3, [r11, #-76] ; 0x4c
- 0xa120 <_putf+2440>: str r4, [r11, #-72] ; 0x48
In this case, r11 holds a pointer to the va_list (ap). If that value ends
in '0', the "add 7, and ~7" operation leaves the pointer ending with 0
instead of the intended "pointing to the next 8 byte boundary"
operation. So, for this example, the double value was taken from r1-r2
instead of r2-r3 (on the stack).
The code was "printf("%f" , fval)". The compiler loads r0 with a pointer to the format, then promotes the floating point value to a double and
loads it into r2-r3 before calling printf(). R1 IS NOT USED, as 8 byte
values MUST be passed in r2-r3 per the ARM standard.
Printf() then pushes r0-r3. It passes r0 and a pointer to r1 on the stack to
vfprintf(). That pointer to r1 on the stack is the va_list, and if it
happens that the pointer ends in '0', the va_arg() call mucks up the
arithmetic.
This error can surface in a long printf with lots of parameters if the
va_list pointer ends up ending in '0' and va_arg() wants a double or
long long.
So, one way to fix this is to modify _putf() so it doesn't use va_arg(). Ugly, I know.
This can be done, however, and we don't need to worry about freeing memory
or any unintended consequences (I think), as the va_end() macro in
printf does nothing. So the va_list pointer passed to _putb() can be
manipulated to provide correct values. I'll see if it works.
I wonder if anyone at GCC is listening?
Best,
Bob Wirka
Realtime Control Works
Janesville, WI
________________________________
From: "bon at elektron.ikp.physik.tu-darmstadt.de" <bon at elektron.ikp.physik.tu-darmstadt.de>
To: Bob Wirka <bobwirka at yahoo.com>; Ethernut User Chat (English) <en-nut-discussion at egnite.de>
Sent: Sunday, September 15, 2013 4:02 PM
Subject: Probable GCC Compiler error, was: Re: [En-Nut-Discussion] Problem with ARM floating point, again
>>>>> "Bob" == Bob Wirka <bobwirka at yahoo.com> writes:
Bob> Hello, I'm having issues with printf("%f") on my AT91SAM7X512
Bob> platform (using ethernut-4.10.3). We're using the Codesourcery
Bob> compiler (gcc version 4.5.1 (Sourcery G++ Lite 2010.09-51)).
Sending a working, stripped down example may lower the barrier for others
to enter that problem...
Anyway, I tried on STM32F4 with Launchpad gcc and I can see the problem
too. Debugging and stepping a lot through the code, I am quite sure that it
is a compiler problem. I can get things to print right with substituting
_double = va_arg(ap, double);
by
uint32_t *l = (uint32_t *)&_double;
if (*(uint32_t*)&ap & 4) {
l[0]= va_arg(ap, uint32_t);
l[1]= va_arg(ap, uint32_t);
}
else {
l[0]= va_arg(ap, uint32_t);
l[0]= va_arg(ap, uint32_t);
l[1]= va_arg(ap, uint32_t);
}
When pushing the arguments on the stack, the arm calling convention tells to
put 64-bit units in R0/1 or R2/3 or stack aligned. I see this happening. It
seems as va_start doesn't care for that alignment. The 64-bit data has also
either its 32-bit words swapped in the va_list, or va_arg(ap, double) uses the
wrong order.
Can anybody confirm that this may not me caused by some strange compiler
option we give?
Bye
--
Uwe Bonnes bon at elektron.ikp.physik.tu-darmstadt.de
Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
More information about the En-Nut-Discussion
mailing list