Toolchain wrestling

Wasted a lot of coding time/effort on stupid toolchain stuff over the last two days. I discovered I was unable to printf floating point numbers. After some head scratching, I determined that my arm-none-elf toolchain and newlib were disagreeing about the endianness of a double, as using a union to swap the two 32-bit halves caused newlib to printf the correct value.

Note: the following is my highschool, unverified by anyone who might actually know what they’re talking about, incomplete understanding of some pretty complex stuff that I’m posting in case parts of it are correct and it helps someone.

Once the cause was determined, the solution seemed simple: somehow get newlib to use the correct endiannes, after all its portable right? Well, I determined that newlib had auto-detected the endianness of the double to be little-endian, and yet since this was wrong I had to assume GCC was using big-endian floats. Some research pulled up some interesting info: when compiling with software floating point GCC uses big endian doubles, which used to be the standard (known as ‘FPA’) before ARM rolled out newer FPUs (known as ‘VFP”). I’m guessing nobody felt like fixing up the floating routines.

I tried compiling both my code and all of GCC with -mfpu=vfp, but this ended up producing a very paradoxical toolchain. Best I could tell, I ended up with vfp-formatted literals that could be printed directly with newlib, but my floating point math library was still stuck on big endian because doing any arithmatic at all on them instantly produced garbage.

The next attempt was then to convince newlib that my doubles were big endian. After greping through the source a bit I arrived at ieeefp.h, which seemed simple enough. It had some autodetection that looked quite correct, at least according to the aforementioned research. Some playing around determined that GCC was actually setting the __VFP_FP__ preprocessor flag, indicating that it was operating under vfp formatted doubles (little endian), even though it was actually using fpa (big endian) literals and soft float routines. This seems like a bug to me, maybe I’ll try and post it one day.

The header file was also designed to allow you to simply specify big endian or little endian preprocessor flags on the command line to skip the autodetection. However, when I set big endian on the command line, I got a memory management fault. Great. I eventually grepped some more and discovered that some logic in endian.h would actually define the system’s endianness in terms of the float endianness if you specified it on the command line, a big no-no. I wanted a little endian build with big endian doubles, hold the mayo. After fixing this, the segfaulting was gone, but I simply couldn’t find a combination of endiannesses that worked correctly… so I fell back to the good ol botball KISS principle and…

Started over from scratch! A new version of GCC had come out since I’d made my earlier toolchain, so I got to upgrade to the latest as well. I build a tried and true arm-elf toolchain instead of the newer arm-none-eabi that seems to have floating point confusion. I also cut the multilibs, and specified –with-float=soft and –with-cpu=cortex-m3 when building. This actually is the simplest way to get a working cortex-m3 toolchain; the thumb2 multilibs aren’t built by default so if you go multilib you won’t get a correct libgcc.a (if you want them head to gcc/config/arm/t-arm-elf and uncomment the thumb2 related block).

This new, simple toolchain for once Just Worked. My advice to anyone with multilib or floating point troubles on cortex-m3 is just to do a non-multilib arm-elf toolchain, in a special prefix if that would conflict with anything. Here’s my configure lines, based on GCC 4.4.1, Binutils 1.19.1, and newlib cvs (earlier attempt to fix the problem, not sure it did anything).

../binutils*/configure --target=arm-elf --prefix=/usr/local --with-float=soft \
--with-cpu=cortex-m3 --with-gnu-ld --with-gnu-as \
--with-mode=thumb --disable-werror 

../gcc*/configure --target=arm-elf --disable-werror --prefix=/usr/local \
--enable-languages="c" --with-newlib --disable-shared --with-gnu-as \
--with-gnu-ld --with-float=soft --with-mode=thumb --with-cpu=cortex-m3 \
--disable-multilib 

../newlib*/configure --target=arm-elf --prefix=/usr/local --with-gnu-as \
--with-gnu-ld --disable-nls --with-float=soft \
--with-cpu=cortex-m3 --disable-multilib

With this I’m currently having no issues at all, with floats, doubles, C99, printf(), anything. I’ll have a more “fun” post with something running soon, I just felt like I had to post this so that either someone can come and enlighten me on how arm-none-eabi was supposed to handle this, or if someone comes with the same problem and can then use my Just Worked toolchain

0 Responses to “Toolchain wrestling”



  1. Leave a Comment

Leave a comment




Project Quadcopter

Welcome to our quadcopter blog! We're a bunch of high school seniors from Florida attempting to create an awesome flying robot before we all have to go our separate ways for college. To learn more, see the about pages!