EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Problems with sprintf and libgcc.a

Started by Mayank Kaushik April 10, 2005
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<stdio.h>
.
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

Mayank Kaushik <prehistorictoad2k@yahoo.com> wrote:

> arm-elf-ld -L --cref
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.
On 2005-04-10, Hans-Bernhard Broeker <broeker@physik.rwth-aachen.de> wrote:
> Mayank Kaushik <prehistorictoad2k@yahoo.com> wrote: > >> arm-elf-ld -L --cref > > 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.
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.
> In particular, it'll put in all necessary references -lgcc, > -lc and the startup file(s) for you.
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.
> 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.
-- Grant Edwards grante Yow! My CODE of ETHICS at is vacationing at famed visi.com SCHROON LAKE in upstate New York!!
Mayank Kaushik wrote:
> 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: > > arm-elf-ld -L --cref -Map BasicBoot.map -EL -T./ld_mk.script -o > "./Mayank/Output/BasicBootDebug.elf" cstartup.o init.o main.o
Please do not call ld directly, use arm-elf-gcc to link, instead.
> 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'
These are entries into the GCC support library, libgcc.a. If you used the proper command line, you'd get them correct.
> main.o(.text+0x60): In function `main': > : undefined reference to `sprintf'
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 ---
> > 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)
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
"Mayank Kaushik" <prehistorictoad2k@yahoo.com> wrote:

>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<stdio.h> >. >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 >==============================
===SNIP===
>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 ?!
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
In article <3bstklF6g5rsjU2@news.dfncis.de>, broeker@physik.rwth-
aachen.de says...
> Mayank Kaushik <prehistorictoad2k@yahoo.com> wrote: > > > arm-elf-ld -L --cref > > 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.
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
Grant Edwards <grante@visi.com> wrote:
> On 2005-04-10, Hans-Bernhard Broeker <broeker@physik.rwth-aachen.de> wrote:
> > 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.
> I've rarely found that to be true when working in an embedded > environment.
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.
> I've always had to use a custom linker script and disable most of > the default startup file linkage.
That's nothing a little hack of the 'specs' file couldn't fix.
> How does gcc know what startup files to use for my hardware > platform?
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.
R Adsett <radsett@junk.aeolusdevelopment.cm> wrote:

> 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.
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.
In article <3bsvn4F6fmv0bU1@news.dfncis.de>, broeker@physik.rwth-
aachen.de says...
> Grant Edwards <grante@visi.com> wrote: > > On 2005-04-10, Hans-Bernhard Broeker <broeker@physik.rwth-aachen.de> wrote: > > > > 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. > > > I've rarely found that to be true when working in an embedded > > environment. > > 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. > > > I've always had to use a custom linker script and disable most of > > the default startup file linkage. > > That's nothing a little hack of the 'specs' file couldn't fix. > > > How does gcc know what startup files to use for my hardware > > platform? > > 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.
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
On 2005-04-10, Hans-Bernhard Broeker <broeker@physik.rwth-aachen.de> wrote:

> 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.
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.
> 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. > >> I've always had to use a custom linker script and disable most of >> the default startup file linkage. > > That's nothing a little hack of the 'specs' file couldn't fix.
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.
>> How does gcc know what startup files to use for my hardware >> platform? > > It was supposed to be informed about these as part of the job of > porting GCC to that hardware platform.
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.
> If that job was never properly completed, you'll have to do > keep telling it on each invocation.
Yup, that's what makefiles are for. -- Grant Edwards grante Yow! This is PLEASANT! at visi.com

The 2024 Embedded Online Conference