[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Fwd: [avr-libc-dev] Problem with unsigned long long printf()
From: |
Theodore A. Roth |
Subject: |
Re: Fwd: [avr-libc-dev] Problem with unsigned long long printf() |
Date: |
Fri, 17 Sep 2004 14:18:31 -0700 (PDT) |
On Fri, 17 Sep 2004, Bernhard Walle wrote:
> Hello,
>
> did you read this on the list? Is it a bug or not?
>
>
> Regards,
> Bernhard
>
> ----- Forwarded message from Bernhard Walle <address@hidden> -----
>
> > Date: Tue, 24 Aug 2004 17:16:10 +0200
> > From: Bernhard Walle <address@hidden>
> > To: address@hidden
> > Subject: [avr-libc-dev] Problem with unsigned long long printf()
> > Mail-Followup-To: address@hidden
> > User-Agent: Mutt/1.5.6i
> >
> > Hello,
> >
> > following code:
> >
> > unsigned long long x = 0x1;
> > printf("%x|%x|%x|%x\n",
> > *((unsigned int*)(&x) + 0),
> > *((unsigned int*)(&x) + 1),
> > *((unsigned int*)(&x) + 2),
> > *((unsigned int*)(&x) + 3)
> > );
> > printf("X = %llu \n", x);
> >
> > The output is:
> >
> > 1|0|0|0
> > X = 1543650816
> >
> > While the first proves that the assignment is correct, the second
> > output is wrong. Does anybody know the reason? Bug?
> >
> > I'm using avr-libc 1.0.4.
There seems to be a few things going on here.
First, avr-libc currently does not handle the '%llu', '%lld', etc.
specifiers. This was probably by design so as not to bloat the vfprintf
function any more than is already is.
I modified your test case to look like this:
void
test_llu (void)
{
uint8_t buf[sizeof (uint64_t)];
uint64_t x = 0x1;
int i;
memcpy (buf, &x, sizeof (uint64_t));
for (i=0; i < sizeof (uint64_t); i++)
printf ("| %x ", buf[i]);
printf ("|\n");
printf ("X = %lu \n", (uint32_t)x);
printf ("X = %llu \n", x);
}
Then I dig into vfprintf.c to try adding support for '%llu' and friends.
See attached patch for my hack. I then got this output:
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
X = 1
X = 73091152686874624
So I dug a little deeper with the debugger and got this (this output is
more for Joerg than anyone else):
(gdb) b vfprintf.c:412
Breakpoint 3 at 0x460e: file ../../../../libc/stdio/vfprintf.c, line
412.
(gdb) c
Continuing.
Breakpoint 3, vfprintf (stream=0x8009a2, fmt=0x80014b " \n",
ap=0x8004ac)
at ../../../../libc/stdio/vfprintf.c:412
(gdb) p a
$2 = {
c = 0x1,
u8 = 0x1,
i8 = 0x1,
l = 0x1,
ll = 0x3100000000000001,
ul = 0x1,
ull = 0x3100000000000001,
pc = 0x800001 ""
}
(gdb) c
Continuing.
Breakpoint 3, vfprintf (stream=0x8009a2, fmt=0x800156 " \n",
ap=0x8004a6)
at ../../../../libc/stdio/vfprintf.c:412
(gdb) p a
$3 = {
c = 0x0,
u8 = 0x0,
i8 = 0x0,
l = 0x66200000,
ll = 0x103aa0466200000,
ul = 0x66200000,
ull = 0x103aa0466200000,
pc = 0x800000 ""
}
To me, this looks suspiciously like gcc is not handling the
a.ull = va_arg (ap, unsigned long long);
call correctly when the type is 64 bits. when passing a 64 bit variable
by value, gcc pushes the 8 bytes onto the stack instead of passing via 8
registers. If my analysis is correct, then there's a bug in gcc. I would
need to dig into this more to be certain, but I don't have any more time
to allocate to this at the moment.
Joerg, what's your take on this since you are the resident printf()
expert?
---
Ted Roth
PGP Key ID: 0x18F846E9
Jabber ID: address@hidden
avr-libc-llu-hack.diff
Description: Text document
- Re: Fwd: [avr-libc-dev] Problem with unsigned long long printf(),
Theodore A. Roth <=