EmbeddedRelated.com
Forums
Memfault Beyond the Launch

GCC/gnude can't use libc.a?

Started by Mike Pijl April 16, 2013
I can't quite believe i'm having this problem! i'm a professional
software/hardware developer but not in the GCC/Arm world. I'm a real
newbie in GCC but have C experience on other platforms.

I'm so stuck...but I suspect it must be something very simple.

I have a very basic GCC program that can't access any of the standard
functions. I'm targeting a philips LPC2129 ARM7 processor. I ripped the
program down to demonstrate this problem:



Pretty easy, huh?

Here's what GCC says when I call "make":

$ make
..linking
arm-elf-ld -Map main.map -T LinkerScript.cmd -L/gnude/arm-elf/lib -lc
-nostartfiles -o main.out start.o ivt.o main.o
main.o(.text+0xc): In function `__main':
*: undefined reference to `strlen'
*main.o(.text+0x14): In function `__main':
*: undefined reference to `malloc'
*main.o(.text+0x1c): In function `__main':
*: undefined reference to `free'
*makefile:53: recipe for target `main.out' failed
make: *** [main.out] Error 1

here's the make file I've been working with. I have spent **countless**
hours on this, finding/fixing little problems with the make file but
*still*have the original problem. i've read a book on GCC.

I'm using the latest version of GCC.

the most significant improvements are bolded:



i also find it strange that the .map file even mentions libc.a and yet it
won't find the functions!

<blah, blah, blah>
*LOAD /gnude/arm-elf/lib/libc.a
*LOAD start.o
LOAD ivt.o
LOAD main.o
OUTPUT(main.out elf32-littlearm)
the full source for my sad little project is here:

http://xrw.bc.ca/download/Stripped.zip

oh yes, other things i've done: uninstall all CygWin, gnude and
reinstall. no improvement!

i realize there are many ways to compile for Arm7. I have no special
allegiance to CygWin/GCC/GNUDE. Really, all I want is something that can
build code targeting this device without needing to buy the Keil compiler.
My program worked great in Keil but it was too big for the free keil
compiler. Since this is a low-budget project, I was hoping to use GCC for
it.

If you can confidently direct me another way to target the Arm7, I would
welcome your guidance. I'm so "tired" of trouble targeting Arm7 that i'm
no longer feeling very "adventurous". Just want to get back to coding
instead of struggling against "impossible" problems.

no special allegiances to this make file either.

my development system is windows XP with cygwin/gnude installed.

thank you for any ideas you can suggest! I am eager to get this finally
working.

mp

An Engineer's Guide to the LPC2100 Series

Hi

> int __main(void) {

I'd use main() not __main(). __main is a special function for GNU.

> arm-elf-ld -Map main.map -T LinkerScript.cmd -L/gnude/arm-elf/lib -lc

Do not use ld directly. Use always gcc, for compiling and linking.
If you use C++, use g++ for linking.
--
42Bastian
+
| http://www.sciopta.com
| Fastest direct message passing kernel.
| IEC61508 certified.
+
--- In l..., 42Bastian wrote:
>
> Hi
>
> > int __main(void) {
>
> I'd use main() not __main(). __main is a special function for GNU.
>
> > arm-elf-ld -Map main.map -T LinkerScript.cmd -L/gnude/arm-elf/lib -lc
>
> Do not use ld directly. Use always gcc, for compiling and linking.
> If you use C++, use g++ for linking.
> --
> 42Bastian
> +
> | http://www.sciopta.com
> | Fastest direct message passing kernel.
> | IEC61508 certified.
> +
>

I would lose the -O3 option until you have a program that works. Lots of strange things happen with high optimization. For example, a smart compiler would realize that between alloc() and free(), nothing happens. It would likely toss the code. I haven't tried it but I wouldn't be surprised.

A portion of my makefile for LPC2148



You can see that optimization is minimal and that, for my project, three libraries are used; two from $ARCHIVE1 and one from $ARCHIVE2

If I were just starting out using Windows for ARM development, I would probably use YAGARTO. Of course, a better solution is one of the low cost options from Rowley - CrossWorks is a really nice toolchain. Keil has a free version as well. It's works well.

I haven't shown any details re: crt.s - the startup file. I didn't look at your makefile in enough detail to see how you did that. You do need one, however.

Richard
If you want to use the heap on an ARM processor, YOU have to write the heap manager. sbrk() is part of that, you can Google for it. Also Google for 'newlib stubs' and 'newlib syscalls'.

There is some code at www.jcwren.com/arm that is targeted to the LPC2148 but it is close enough. Look in the 'newlib' folder and you will see 'syscalls.c'. If you want to use FILE I/O, you need some of the other functions to implement 'stdin', 'stdout' and 'stderr'.

For your project, I cut out all of the heap stuff, changed the __main stuff and used my own makefile and linker script. Sure, it compiled and linked. So, the two assembly files have the correct syntax (whether they work or not) and what was left of the C code was trivial.

There is a rather steep learning curve to any of these adventures. It all seems so obvious after you have been there and done that. In the meantime, it's a lot of work.

I highly recommend JC's work. It demonstrates everything that can be done on an LPC2148 including an implementation of FreeRTOS. His makefile(s) will take a little thought as they are quite advanced.

ARM7 processors don't have a virtual memory manager so it is entirely possible that the heap and stack will collide. For my trivial applications, a heap hasn't been necessary. I write my own simple libraries for string functions and, to the maximum extent possible, I avoid using functions in newlib. I can't avoid the C library, of course, but I can be pretty selective about newlib.

You will run across many implementations of a simplified printf() called, usually, rprintf(). The two main reasons are reduced code space and elimination of the heap requirement. BTW, I copy my string functions from "The C Programming Language" - Kernighan & Ritchie

Just for giggles, I used the Eclipse-YAGARTO toolchain to compile your project. It is based on the GCC tools.

One last thing: We are dealing with embedded processors, we don't let main() run off the end. Somewhere there is a while(1) loop that prevents that from happening. Some versions of the startup code trap for main() returning, other versions assume it doesn't happen.

Richard
;-) well gcc is telling you that there is no standart memory allocator )

so I think as a professional you can write your own _sbrk() system call )
thank you all for your comments. i've tried things people have mentioned
as well as studied the MAKE documentation to better understand that. still
having similar results.

i've become so accustomed to knowing how to do things in the world of
creating software that this has been a rude awakening...

rtstofer: i think i understand now. by using malloc, free, sprintf,
strlen, etc, i'm obligating myself to create a heap manager. i'm not at
all eager to do so. i presume if i define character arrays and generate a
pointer to the character array, i no longer have this obligation.

char c[100];
char* pc=&c[0];

i can wean myself off of sprintf, strlen, etc by using a stand-alone
routine for this from one of the sources you suggest.

it's like i have told people in the past about writing embedded
software...it's like camping: bring what you need with you or be prepared
to make it yourself (or not have it at all).

my little test application is only a test for compiling. my real
application (originally built & debugged using keil) does indeed have an
while (1) routine. regrettably, the program was too large for the free
version of keil otherwise that's where it would still be. for my
application, the keil compiler was entirely out of my price range.

when i replaced __main() with main(), the compiler complained about not
being able to find __main().

thank you for your tip about YAGARTO. and also your makefile. i don't know
anything about crt.s; the example i had did not include that. i'm
perplexed to hear there's something else i need but don't have or know
anything about.

as for not using "ld" directly, i suppose you mean i should not pass "-c"
to gcc?

>Hmm, is /gnude/arm-elf/lib valid WINDOWS path? ;-)

using unix paths because i'm running it from CygWin.

my plan is to (unless you disapprove):

1. migrate from malloc/free to arrays with pointers as described
2. port in a couple of replacements for strlen, sprintf
3. try again with most of the rest as it was

part of the reason i'm not being more ambitious is because by now, i'm not
as "offended" by things that are not satisfying my usual requirements.
today, my only requirement is that it compiles and actually works...after
all, it's a project only for me...

i'll come back to it in an evening (maybe tomorrow; maybe the next evening)
and see what i can do.

thank you all!
mp
[...]
when i replaced __main() with main(), the compiler complained about not
being able to find __main().
thank you for your tip about YAGARTO. and also your makefile. i don't know
anything about crt.s; the example i had did not include that. i'm
perplexed to hear there's something else i need but don't have or know
anything about.
Try Linaro. In my opinion is better.
As you not include crt.s or standard runtimes  main() is not called.
Then compiler in optimalization proces remove it.
But linker expected it
[...]
as for not using "ld" directly, i suppose you mean i should not pass "-c"
to gcc?
Pass it only for compile,
>Hmm, is /gnude/arm-elf/lib valid WINDOWS path? ;-)
using unix paths because i'm running it from CygWin.
OK. I meant if this path is propely resolved to dos path.
Albert
__
._,
There is a learning curve to using GNU tools, especially when you're doing
cross compiles.

Most people, such as yourself, start out using an IDE and miss out on the
underpinnings.

By convention, crt.s is an assembly language program that runs out of reset.

Here is where you set up the various stack pointers, zero out the .bss
section, initialize the data section, etc.

Toward the end, you call a function to initialize the processor -- set up
the oscillator and/or the PLL to run at the desired frequency. Initial
I/O must also be set up.

Now you're ready to jump to main. You don't really need a main if you
write your own crt.s. I've forgotten at the moment how to tell the linker
that there is no main -- maybe it's the nofiles option.

Makefiles suck! I finally got so sick of them I took a couple of weeks to
write a python program to handle builds. Once you know the options to
pass to gcc it's easy enough to walk lib dirs, determine dependencies and
compile as necessary.

I've always regarded compiler supplied libs as untrusted. In fact, there
is at least one function that assumes memory is writable. It's better to
write you're own.

DaveS
Hi there,

Take a look at this article
http://www.embedded.com/design/mcus-processors-and-socs/4007119/Building-Bare-Metal-ARM-Systems-with-GNU-Part-1--Getting-Started,
it helped me a lot when I was starting, maybe you'll find it usefull.
As for the heap management you'll find a lot of samples not too hard to
understand, it is no more than a half a dozen functions with little code.

Regards,
Bernardo Marques.
Quote "for my application, the keil compiler was entirely out of my price range."

There are lots of other professional quality tools out there, that are much cheaper than Keil (Crossworks, Code Red) and a lot of free tools too (LPCXpresso, Yagarto).

So how much have you spent on trying to 'roll your own'? I bet you could have better spent your time investigating the market for cheaper tools than Keil...

Memfault Beyond the Launch