[U-Boot-Users] Why objdump Creates 4G U-Boot Images

Jon Loeliger jdl at freescale.com
Thu Jan 20 23:26:28 CET 2005


Executive Summary:
    With this piece of mail, I hope to simply provide some
    documentation for a problem I've had building U-Boot
    where the u-boot elf file is made, but the u-boot.bin
    and u-boot.srec files are not made with objdump due to
    large file size limitations.

    In short, check your floating point code carefully and
    make sure you are _really_ creating a standalone executable.

Here we go.

Original Problem:

    The u-boot elf file is built, however the u-boot.bin
and u-boot.srec images are not created.  On my system,
objdump dies complaining that it "the file limit is exceeded."
In fact, it was trying to create a roughly 4GB file.  Cool.
I speculated that we were having either an unsigned problem,
a sign-bit problem or an endian issue and were somehow rolling
a full 32-bit address space.

I isolated the problem by locating a working 3.3.2 with
binutils 2.15 toolchain from Metrowerks(!) for my board.
This was an x86 to PPC cross compiling environment.

My non-working toolchain was GCC 3.4.3 with binutils 2.15
on a PPC box, not really cross compiling to PPC.

I managed to find a 3.4.3 cross compiling environment as well,
and could show that the objdump worked there on the elf image
created by 3.3.2.  Oh yeah.

Inspecting the "readelf -a" output from the working and
non-working elf images showed this critical difference:


    Program Headers:
      Type       Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      LOAD       0x000078 0xfe000000 0xfe000000 0x277b0 0x2c5fc RWE 0x8

     Section to Segment mapping:
      Segment Sections...
       00     .text .reloc .data .data.rel.local .data.rel .u_boot_cmd .bss 

Not Working:

    Program Headers:
      Type       Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      LOAD       0x000098 0x000002b0 0x000002b0 0x00010 0x00010 R   0x8
      LOAD       0x0000a8 0xfe000000 0xfe000000 0x257bc 0x2a5fc RWE 0x8
      STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4

     Section to Segment mapping:
      Segment Sections...
       00     .rodata.cst8 
       01     .text .reloc .data .data.rel .data.rel.local .u_boot_cmd .bss 

Now it was clear:  The two LOAD sections in the non-working image
were conspiring to place data at address 0x2b0 and at 0xfe000000,
thus producing an image with an address space roughly 4G large.
An srec file, with an expansion factor of about 2.5 ~ 3 per byte
was trying to make a 10GB file or so.  Oh yeah.  I can see why
Linux would want to kill -9 that large objdump file process dead....

So, where'd the 0x2b0 come from?  Turns out this section:

    Section Headers:
      [22] .rodata.cst8   PROGBITS    000002b0 000098 000010 08  AM  0   0  8

And what causes .rodata.cst8 sections?  Google suggested it was
a floating point intrinsic, and peering at the u-boot.map confirmed:

    .rodata.cst8    0x00000000000002b0       0x10
     .rodata.cst8   0x00000000000002b0       0x10 /usr/lib/gcc-lib/ppc64-yellowdog-linux/3.3.3/libgcc.a(_fixunsdfsi.oS)

Interesting.  It came from libgcc and was called _fixunsdfsi.
And, more grepping and nm'ing yielded a file (speed.c) in our
board port that did this:

		core_clk = 1.5 * csb_clk;

On a hunch, we converted that to this:

		core_clk = (3 * csb_clk) / 2;

Which suddenly worked splendidly!  Bad floating point.  Bad.

OK, so why did _fixunsdfsi get introduced in the first place?

Poking around showed that this symbol should have been resolved
with the -msoft-float and the "nof", no-floating-point form of
the libraries.  How come they didn't use the nof form of the libs?

And, the last piece of the puzzle, the load line on u-boot itself
at the very end of the main Makefile shows this:

u-boot:		depend $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
		UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
			--start-group $(LIBS) $(PLATFORM_LIBS) --end-group \
			-Map u-boot.map -o u-boot

where the last $(LD) is the important line, and the symbol

    PLATFORM_LIBS += --no-warn-mismatch -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc

is the key factor.  The call to $(CC) requesting the name of
the libgcc library file name _should_ in the case of using
the -msoft-float option, produce the "nof" form of the library.
Our tool chain was _not_ doing that.  It was supplying the same
non-nof library regardless of the -msoft-float option.

So, lesson one: If you are using soft-float, make sure your
toolchain has the "nof" multilib'ed into the build properly.

Lesson two: If you want to multiply by 1.5, instead
multiply by 3 and divide by 2. :-)

Finally, lesson three: In addition to (un)signed problems,
sign-bit issues and endian problems, another cause for very
large (~4G) files is floating point.  As we've all known for
a very long time now, floating point numbers are a pain and
should be avoided.

There are margaritas at home with my name all over them.


More information about the U-Boot mailing list