Problems with sprintf and libgcc.a

Hi everyone,

im using "toolchain

-bu-2.15_gcc-3.4.3-c-c++-java_nl-1.12.0_gi-6.1.tar.bz2" to compile a simple program for an ARM920T based microcontroller (AT91RM9200). The development system is running Fedora Core 3.

i have not been able to use the "sprintf" function..the program does not compile if i do so. here are the details of my problem:

************************************************************

code snippet of my main.c program (where im calling sprintf):

============================== #include . sprintf( buf, "This is a test %d one and %d two", 420, 840 ); .==============================

This is the error i get:

============================== . arm-elf-gcc -c -Os -DAT91RM9200 -mlittle-endian -mapcs-32 -mcpu=arm920t

-fno-inline -o "init.o" "init.c" arm-elf-gcc -c -Os -DAT91RM9200 -mlittle-endian -mapcs-32 -mcpu=arm920t

-fno-inline -o "main.o" "main.c" arm-elf-ld -L --cref -Map BasicBoot.map -EL -T./ld_mk.script -o "./Mayank/Output/BasicBootDebug.elf" cstartup.o init.o main.o init.o(.text+0x100): In function `AT91F_US_Baudrate': : undefined reference to `__udivsi3' init.o(.text+0x10c): In function `AT91F_US_Baudrate': : undefined reference to `__umodsi3' init.o(.text+0x120): In function `AT91F_US_Baudrate': : undefined reference to `__udivsi3' init.o(.text+0x134): In function `AT91F_US_Baudrate': : undefined reference to `__udivsi3' init.o(.text+0x26c): In function `AT91F_CheckPLL_FrequencyRange': : undefined reference to `__divsi3' main.o(.text+0x60): In function `main': : undefined reference to `sprintf' make: *** [Mayank/Output/BasicBootDebug.elf] Error 1 ==============================

I had searched the net and found that undefined references to `__divsi3` and `__umodsi3' are caused because of problems or version mismatches related to libgcc.a . Heres my linker script:

============================== GROUP("/home/guest/mayank_arm/gnuarm-3.4.3/arm-elf/lib/libc.a" "/home/guest/mayank_arm/gnuarm-3.4.3/lib/gcc/arm-elf/3.4.3/libgcc.a")

MEMORY { ram : ORIGIN = 0x200000, LENGTH = 0x3000 /*12kb*/ }

SECTIONS {

.text : { __stext_start = . ; /*Start of the text section*/ *(.text) *(.rodata.*) . = ALIGN(4); __stext_end = . ; /*End of the text section*/ } > ram

.data : {

__sdata_start = . ; /*Start of the data section*/ *(.data) *(.glue_7*) *(.stack) *(.*) . = ALIGN(4); __sdata_end = . ; /*End of the data section*/ } > ram

.bss : { __sbss_start = . ; /*Start of the bss section*/ *(.bss) . = ALIGN(4); __sbss_end = . ; /*End of the bss section*/ } > ram } ==============================

This is how the liker is being called in my Makefile:

============================== LINK=arm-elf-ld -L --cref -Map BasicBoot.map -EL -T./ld_mk.script -o "$(OUTDIR)/$(OUTFILE)" $(OBJ) ==============================

******************************************************* (I have checked these archives im using, by issuing the command "nm -sC libc.a|grep sprintf" and libgcc.a for __umodsi3, they were shown to be present inside their respective files.)

I tried another approach: i commented out the GROUP() in the linker script, changed the linker invocation in the Makefile to this:

============================== CFG_LIB2='/home/guest/mayank_arm/gnuarm-3.4.3/arm-elf/lib/libc.a' CFG_LIB1='/home/guest/mayank_arm/gnuarm-3.4.3/lib/gcc/arm-elf/3.4.3/libgcc.a'

LINK=arm-elf-ld --cref -Map BasicBoot.map -EL -T./ld_mk.script -o "$(OUTDIR)/$(OUTFILE)" $(OBJ) --start-group $(CFG_LIB2) $(CFG_LIB1)

--end-group ==============================

These are the errors i get: ============================== arm-elf-gcc -c -Os -DAT91RM9200 -mlittle-endian -mapcs-32 -mcpu=arm920t

-fno-inline -o "init.o" "init.c" arm-elf-gcc -c -Os -DAT91RM9200 -mlittle-endian -mapcs-32 -mcpu=arm920t

-fno-inline -o "main.o" "main.c" arm-elf-ld --cref -Map BasicBoot.map -EL -T./ld_mk.script -o "./Mayank/Output/BasicBootDebug.elf" cstartup.o init.o main.o

--start-group '/home/guest/mayank_arm/gnuarm-3.4.3/arm-elf/lib/libc.a' '/home/guest/mayank_arm/gnuarm-3.4.3/lib/gcc/arm-elf/3.4.3/libgcc.a'

--end-group arm-elf-ld: region ram is full (./Mayank/Output/BasicBootDebug.elf section .text) arm-elf-ld: region ram is full (./Mayank/Output/BasicBootDebug.elf section .data) arm-elf-ld: section .data [00200000 -> 00221fd7] overlaps section .text [00200000 -> 002084a3] arm-elf-ld: section .bss [00200000 -> 00200003] overlaps section .text [00200000 -> 002084a3] /home/guest/mayank_arm/gnuarm-3.4.3/arm-elf/lib/libc.a(syscalls.o)(.text+0x69c): In function `_sbrk': ../../../../../../newlib-1.12.0/newlib/libc/sys/arm/syscalls.c:508: undefined reference to `end' make: *** [Mayank/Output/BasicBootDebug.elf] Error 1 ==============================

Please note that this particular program had originally been built for Arm Developer Suite 1.2, and the size of the compiled code was 5k only. I have made the requisite changes for it to work with GNU tools.

Where am i going wrong ?!

Thanx in anticipation, Mayank

Reply to
Mayank Kaushik
Loading thread data ...

Generaly speaking, it's rarely a good idea to invoke 'ld' yourself when linking C or C++ programs. Have 'gcc' invoke it for you instead. Unless the GCC port is buggy, it'll know how to invoke ld correctly. In particular, it'll put in all necessary references -lgcc, -lc and the startup file(s) for you.

Your description shows that the GROUP() thing you put into the linker script didn't have any effect at all.

The problems with memory space overlaps and such suggest that your linker script is probably not correct, or at least not compatible with the GCC output you use it on.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

I've rarely found that to be true when working in an embedded environment. I've always had to use a custom linker script and disable most of the default startup file linkage.

How does gcc know what startup files to use for my hardware platform? Likewise, I don't want gcc linking in a "libc" file behind my back. I don't really even like it pulling a libgcc file out of it's hat either.

--
Grant Edwards                   grante             Yow!  My CODE of ETHICS
                                  at               is vacationing at famed
                               visi.com            SCHROON LAKE in upstate
                                                   New York!!
Reply to
Grant Edwards

Please do not call ld directly, use arm-elf-gcc to link, instead.

These are entries into the GCC support library, libgcc.a. If you used the proper command line, you'd get them correct.

This is an entry into the C runtime library, which would also be included if you used gcc to link.

The linker script can be included with the -Wl switch.

--- snip snip ---

You do not have enough memory for your code and data. Prune the code or get more RAM.

Depending on your version of the C runtime, use of sprintf() may hoist in the whole file system interface and dynamic memory allocation, which are alone more than your 12 kbytes.

--

Tauno Voipio
tauno voipio (at) iki fi
Reply to
Tauno Voipio

===SNIP===

You are using an OS now (Linux). All of the AT91F_' initialization stuff has been performed even before Linux got bootloaded. You need to use a makefile, link script, etc. that one would use to build a Linux application, not something that would be executed shortly after RESET is released.

-- Dan Henry

Reply to
Dan Henry

In general, I'd have to disagree on this point. I'd rather know what my tools are doing rather than have them do it behind my back. I've found that the more specific your needs and the more you deviate from the hosted model of the particular model the more likely know-it-all compile drivers are to get it wrong.

Robert

Reply to
R Adsett

I did write "generally speaking" for a reason. This may indeed not as strictly true in embedded work as it is for hosted-environment GCCs, but it's still worth to be kept in mind.

The rationale behind letting GCC invoke ld is that this is how GCC is supposed to work --- it makes certain assumptions about the target platform, and some of those are reflected in pieces of the ld invocation composed by the "compiler driver program", gcc, including things like specs file, linker script, startup files, libgcc.a and libc. Not letting GCC do this effectively means you're fighting your tools, instead of configuring them correctly.

That's nothing a little hack of the 'specs' file couldn't fix.

It was supposed to be informed about these as part of the job of porting GCC to that hardware platform. If that job was never properly completed, you'll have to do keep telling it on each invocation.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

Knowing what they're doing is one thing --- that's what gcc and ld each have a '-v' switch for. It's a totally different thing to jump in and do-it-yourself every single time, just because you don't believe the compiler driver can get it right. Our OP clearly demonstrates that individual programmers can get that completely wrong at least as easily as the GCC porters.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

Maybe you work a lot differently than I do, but I don't want to build a different version of GCC for every variant of a core that I program.

Just let me provide those and let the compiler produce the object code from the source. That seems a fair and equitable division of responsibilities to me :)

Robert

Reply to
R Adsett

I have found it handy command line options to ask gcc what library files it thinks it should use for libgcc, libc, libm, etc. That allows one to manually link in files that are automatically selected by gcc based on architecture options.

I've never been brave enough to hack on a specs file. That's proably the right way to do it, but it assumes that a given port of the compiler will only be used for a single project on a single hardware platform. I'm often using the same compiler for multiple projects that have different linkage requirements.

If I had to port GCC to each hardware platform I'd never get anything done. I use a single arm-elf-gcc port for a half-dozen different target platofrms.

Yup, that's what makefiles are for.

--
Grant Edwards                   grante             Yow!  This is PLEASANT!
                                  at               
                               visi.com
Reply to
Grant Edwards

It won't give you all the machinery behind what it'll output in a given case, though (most of which is encoded in the specs file). E.g. looking at what "gcc -v -O2 -g3 -Wall foo.c" does won't tell you much of anything about what it might do for "gcc -v -O0 bar.cpp".

If you're brave enough to hack linker scripts, you can brave spec files, too. It's no more difficult to read and fiddle with a specs file than it'd be to second-guess what gcc would do for a given command line you've never used before. Nowadays, the syntax of spec files format is even documented properly.

The specs file is (among other things) GCC's way of encoding the dependencies between compile-time flags and linker invocations.

No. It only assumes that you're prepared to pass gcc a suitable specs file for each of them. You don't even have to write a complete specs file of your own --- you can override only those parts that need changing, and you can start with the existing specs file of the GCC you're using (or a --dumpspecs, if it's using the integrated one).

I don't think it's significantly harder to do the port than to experiment with your general-purpose GCC until it fits the new platform. It involves nothing more than to formalize the knowledge you have about that platform a little more strictly. It's an exercise in putting information in one place (the GCC target specification) rather than repeating it in the Makefile of every piece of software you'll ever write to run on that particular target.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

It is? That's good news, where? Documentation is GNUs greatest weakness.

I didn't find GCCs linker scripts particularly difficult other than a marked absence of information on what sections the compiler will produce. They are certainly nor more difficult than any other linker script I've worked with. And at some point they are needed in order to deal with application specific memory maps, such as forcing particular information to a particular location.

Experiment???

All I do is call GCC to compile and then call ld to link in the appropriate startup and libraries with the compiled source and memory map. Why would that involve any experimentation?

Since the repeat at most involves an include of the appropriate definitions (not even a cut and paste), I don't see that as particularly burdensome. And the information is only in one place, the included file.

Robert

Reply to
R Adsett

My vote to this, too. No need to re-build GCC & co for each target system.

The trick is to use -Wl for gcc command line (in Makefile):

LDFLAGS = -g -nostartfiles -Wl,-Map=$(TRG).map,--cref,-T,aif.ld

--

Tauno Voipio
tauno voipio (at) iki fi
Reply to
Tauno Voipio
[...]

info gcc "Invoking GCC" "Spec Files"

(of GCC-3.4.1), or in the equivalent space of whatever format of the docs you're looking at.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

But since I've got to write a linker script anyway, why bother with a specs file? I don't really see much of an advantage. It seems simpler to have the target-specific stuff in one file.

It's an interesting idea. I'll have to try it on my next project.

Not sure what you mean. I don't have to experiment with gcc at all. I just write a linker script.

That's a good point.

--
Grant Edwards                   grante             Yow!  I just had my entire
                                  at               INTESTINAL TRACT coated
                               visi.com            with TEFLON!
Reply to
Grant Edwards

Hmm, all that gets me are some errors and in particular

Unable to find node referenced by `Spec Files' in `(gcc.info.gz)Invoking GCC'.

I did find

formatting link

which I will take a look at.

Robert

Reply to
R Adsett

... snip ...

Sounds as if you haven't got the info system properly installed. "Info" by itself should bring up a master menu and an optional tutorial.

--
"If you want to post a followup via groups.google.com, don't use
 the broken "Reply" link at the bottom of the article.  Click on 
 "show options" at the top of the article, then click on the 
 "Reply" at the bottom of the article headers." - Keith Thompson
Reply to
CBFalconer

Come, now, you sure know that "some errors" is no way to report a problem...

That means you have info installed, and a gcc info file installed in a place where info finds it --- but it's not the one for a recent GCC. There's a reasion I mentioned the version number being referred to, see?

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

Seems likely, although it's a straightforward cygwin install.

I just did a little more exploration and it seems that some of the nodes are missing and that's one of them. Odd, I'll have to fix that. In any case the web link seems to be the same source.

Robert

Reply to
R Adsett

You're right, I was brushing quickly past it since they weren't visible long enough to decipher. Which just left the following which yo kindly deciphered.

Ahh, I'll have to update, although as a documentation medium info doesn't shine. In any case the web link I found does seem to be what you were referring to. It'll do for my initial explorations.

Robert

Reply to
R Adsett

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.