[BUG] avr32-linux-gcc ULL div error

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

While debugging some cruft I was doing inside the Linux LCDC framebuffer driver I came across something odd:

drivers/built-in.o: In function `cfb_copyarea':
: undefined reference to `__avr32_udiv64'
make: *** [vmlinux] Error 1

This was triggered if

-	pr_debug("  pixclk:     %llu Hz\n", 1000000000000ULL / var->pixclock);
+	printk(KERN_DEBUG "  pixclk:     %llu Hz\n", 1000000000000ULL / var->pixclock);

EDIT: ^^^ Code tag mangle, all that's happening is that the pr_debug is expanded to a printk, such as happens when you #define DEBUG before #include :)
This is in sidsafb.c around line 260. Trying to see where the offending symbol came from:

linux-2.6.18-at0 $ grep -r '__avr32_udiv64' .
Binary file ./drivers/built-in.o matches
Binary file ./drivers/video/built-in.o matches
Binary file ./drivers/video/sidsafb.o matches

So it seems to me the offending symbol is generated by the compiler, not by anything in the kernel source. Hence the post here rather than in the Linux forum.

That being said, I have not had any success recreating this outside the kernel code, though it can be recreated by doing a similar sum inside the kernel code but outside a printk.

I'm assuming Haavard would have #define DEBUG'd inside sidsafb.c at some stage while dev'ing this driver, turning on all the pr_debugs and, in my case, triggering buggage. I'm thinking then that this is a regression of some sort, I'm running avr32-linux-gcc from the atmel .deb repository:

$ avr32-linux-gcc --version
avr32-linux-gcc (GCC) 4.0.2-atmel.1.0.0

Still hanging out for .debs of GCC 4.1.whatever :)

Cheers,
-S.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah, forgot

$ avr32-linux-ld --version
GNU ld version 2.16.1.atmel.1.0.0 20060510

Where and when should I be getting 2.17, preferably in .deb form? Not up on the atmel.no repository atm at least.

Any response appreciated :)

Cheers,
-S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The repo on atmel.no will (should) be updated shortly... I will nag a bit ;)

Hans-Christian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Appreciated ^_^

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nagging was answered with start of next week, you could fetch the rpm's from atmel.com and do an alien conversion.

Hans-Christian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tried alien conversions on all three lots of RPMs (FC5/FC6/SLES), they all end in libelf fcxage in avr32program and avr32gdbproxy. Donno what it is with that darn library but it don't play nice cross-distro's.

Guess I'll wait ;)

Many thanks for the effort ^_^
-S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

squidgit wrote:

drivers/built-in.o: In function `cfb_copyarea':
: undefined reference to `__avr32_udiv64'
make: *** [vmlinux] Error 1

This was triggered if

-	pr_debug("  pixclk:     %llu Hz\n", 1000000000000ULL / var->pixclock);
+	printk(KERN_DEBUG "  pixclk:     %llu Hz\n", 1000000000000ULL / var->pixclock);

Hmm...I suspect this code hasn't been tested with DEBUG for quite some time. The kernel used to have an implementation of __avr32_udiv64, but it was removed during review before inclusion in mainline. Plain 64-bit division is illegal in the kernel -- you have to use do_div().

I suppose you can drop a few zeroes in the expression above and print out the result as kHz or MHz instead. That should make it possible to reduce the whole thing to a 32-bit division.

Quote:
This is in sidsafb.c around line 260. Trying to see where the offending symbol came from:

linux-2.6.18-at0 $ grep -r '__avr32_udiv64' .
Binary file ./drivers/built-in.o matches
Binary file ./drivers/video/built-in.o matches
Binary file ./drivers/video/sidsafb.o matches

So it seems to me the offending symbol is generated by the compiler, not by anything in the kernel source. Hence the post here rather than in the Linux forum.

That's correct. gcc generates 64-bit division out of line.

Quote:
That being said, I have not had any success recreating this outside the kernel code, though it can be recreated by doing a similar sum inside the kernel code but outside a printk.

libgcc provides __avr32_udiv64, so as long as you link with the standard libraries, you should be fine. The kernel does not use libgcc; it provides its own implementation of the libgcc functions as long as it does not break with kernel policy (which is the case with __avr32_udiv64 -- it's simply too easy to produce extremely slow code by accident.)

So the link failure is actually a feature -- it indicates that someone did a 64 bit division without properly thinking through the consequences. When it happens, it's usually possible to rework the code to avoid the 64-bit division altogether. For the few remaining cases, do_div() is the solution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

how wrote:
I suppose you can drop a few zeroes in the expression above and print out the result as kHz or MHz instead. That should make it possible to reduce the whole thing to a 32-bit division.
Indeed that's what I do now.
how wrote:
libgcc provides __avr32_udiv64, so as long as you link with the standard libraries, you should be fine. The kernel does not use libgcc; it provides its own implementation of the libgcc functions as long as it does not break with kernel policy (which is the case with __avr32_udiv64 -- it's simply too easy to produce extremely slow code by accident.)
Didn't realize 64-bit division came from the c library, all makes sense now :)!

Yes, very, very slow code. I remember testbenching the difference between incrementing a u32 and a u64 on an 8-bit arch, came to about 8 times faster by dropping the extra bits.

how wrote:
So the link failure is actually a feature -- it indicates that someone did a 64 bit division without properly thinking through the consequences. When it happens, it's usually possible to rework the code to avoid the 64-bit division altogether. For the few remaining cases, do_div() is the solution.
Hadn't thought of it like that ;)

-S.