[En-Nut-Discussion] Realy strange linker problem with NutOS 4.4.0 for Ethernut 3.0 (ARM)

3 views
Skip to first unread message

Ole Reinhardt

unread,
Feb 11, 2008, 5:36:05 PM2/11/08
to Ethernut User Chat (English)
Hi all,

I have a strange linker problem.

My application uses the phat filesystem and therefor needs the _open,
_close and similar functions.

Everything works fine until I use the strdup() function in my sources.

If I use strdup() anywhere in my code I get the following linker errors:


arm-elf-gcc ../../xxxxxx/logout.o ../../xxxxxx/version.o ....
-mcpu=arm7tdmi -nostartfiles
-T/home/ole/work/xxxxxx/xxxxxx/ethernut-4.4.0/arch/arm/ldscripts/at91_ram.ld -Wl,-Map=xxxxxx.map,--cref,--no-warn-mismatch -L/home/ole/work/xxxxxx/xxxxxx/arm/nut-build/lib -Wl,--start-group /home/ole/work/xxxxxx/xxxxxx/arm/nut-build/lib/nutinit.o -lnutpro -lnutos -lnutarch -lnutdev -lnutnet -lnutfs -lnutcrt -lm -Wl,--end-group -o xxxxxx.elf
/opt/arm-elf/lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib/libc.a(lib_a-syscalls.o): In function `_open':
../../../../../../src/newlib-1.15.0/newlib/libc/sys/arm/syscalls.c:412:
multiple definition of `_open'
/home/ole/work/xxxxxx/xxxxxx/arm/nut-build/lib/libnutcrt.a(open.o):open.c:(.text+0x0): first defined here
/opt/arm-elf/lib/gcc/arm-elf/4.1.2/../../../../arm-elf/bin/ld: Warning:
size of symbol `_open' changed from 172
in /home/ole/work/xxxxxx/xxxxxx/arm/nut-build/lib/libnutcrt.a(open.o) to
32
in /opt/arm-elf/lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib/libc.a(lib_a-syscalls.o)
/opt/arm-elf/lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib/libc.a(lib_a-syscalls.o): In function `_close':
../../../../../../src/newlib-1.15.0/newlib/libc/sys/arm/syscalls.c:434:
multiple definition of `_close'
/home/ole/work/xxxxxx/xxxxxx/arm/nut-build/lib/libnutcrt.a(close.o):close.c:(.text+0x0): first defined here

(Sorry for obfuscating file names, but this is a project under NDA)

What in hell triggers this symbol mixup? Does NutOS uses its own strdup
function or the one from newlib? And what could be the reason to link
the lib_a-syscalls.o?

Has anybody experienced similar problems? Again: Without using strdup
everything works fine!

Btw: I'm using a self build arm-elf-gcc (GCC) 4.1.2 toolchain with
newlib-1.15.0 on my Debian/Sid Linux box.

Bye,

Ole Reinhardt

--
_____________________________________________________________
| |
| Embedded-IT Hard- und Softwarelösungen |
| |
| Ole Reinhardt Tel. / Fax: +49 (0)271 7420433 |
| Luisenstraße 29 Mobil: +49 (0)177 7420433 |
| 57076 Siegen eMail: ole.re...@embedded-it.de |
| Germany Web: http://www.embedded-it.de |
| UstID / VAT: DE198944716 |
|_____________________________________________________________|

_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion

Harald Kipp

unread,
Feb 12, 2008, 8:40:32 AM2/12/08
to Ethernut User Chat (English)
Ole Reinhardt schrieb:

> Everything works fine until I use the strdup() function in my sources.

strdup() is not supplied by Nut/OS. Thus, it will collect the missing
routine from the newlib, which is part of your ARM toolchain. However,
more dependencies are created and finally you end up with lots of linker
errors and duplicates.

Specific solution: Add an strdup() implementation to your application code.

General solution: Always check your map file for functions supplied by
libraries which are not part of any Nut/OS library.

Harald
_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion

Ole Reinhardt

unread,
Feb 12, 2008, 9:45:59 AM2/12/08
to Ethernut User Chat (English)
Hi,

> > Everything works fine until I use the strdup() function in my sources.
>
> strdup() is not supplied by Nut/OS. Thus, it will collect the missing
> routine from the newlib, which is part of your ARM toolchain. However,
> more dependencies are created and finally you end up with lots of linker
> errors and duplicates.

Ok. I did not dig into what is linked and what not. Strdup is supplied
in nut/c/string/strdup.c. After looking a bit deeper, it seems only to
be compiled for platforms not providing these libs.

Strange is, that all other funcions provided in nut/c/string/ are not
linked either and seem to be provided by newlib. Using them does not
trigger this problem.

> Specific solution: Add an strdup() implementation to your application code.

That's what I've done.

Thanks,

Ole

Harald Kipp

unread,
Feb 12, 2008, 9:59:44 AM2/12/08
to Ethernut User Chat (English)
Ole Reinhardt schrieb:

> Strange is, that all other funcions provided in nut/c/string/ are not
> linked either and seem to be provided by newlib. Using them does not
> trigger this problem.

nut/c/ provides all required function in case the toolchain comes
without any runtime library. This had been the case in early times when
Nut/OS was ported to the GameBoy Advance.

Today the ARM runtime library is provided by newlib and the AVR runtime
by avrlibc. nut/c/ is not used in these cases.

Those runtime functions, which need special OS support, are located in
nut/crt, like stdio functions as well as malloc() and friends.
Unfortunately strdup() is not just a simple string function, but
requires malloc(). However, libraries like newlib do not simply
reference malloc() within strdup() but do more complex things, which in
turn create additional system specific references like syscall().

Actually strdup() should be in nut/crt, although the header string.h
refers to functions in nut/c/string. Actually the strdup() prototype
should be in memory.h, but that would break well established standards.

Harald
_______________________________________________
http://lists.egnite.de/mailman/listinfo/en-nut-discussion

Nathan

unread,
Feb 12, 2008, 6:55:33 PM2/12/08
to osdeve.mirror.rtos.En-Nut-Discussion


On Feb 12, 9:59 am, Harald Kipp <harald.k...@egnite.de> wrote:
> Ole Reinhardt schrieb:
>
> > Strange is, that all other funcions provided in nut/c/string/ are not
> > linked either and seem to be provided by newlib. Using them does not
> > trigger this problem.

I had run into a similar problem on AVR with strdup and ended up
writing my own. I hadn't realized that there was one already that
just wasn't getting linked in.
After looking at the implementation in nut/c/string I'd like to make a
couple of implementation changes that will encourage compilers to
produce slightly faster and smaller code.
char *strdup(CONST char *str)
{
size_t siz;
char *copy;

siz = strlen(str) + 1;
if ((copy = malloc(siz)) == NULL) {
- return NULL;
+ return copy;
}
- memcpy(copy, str, siz);

- return copy;
+ return memcpy(copy, str, siz);
}

In the first change 'copy' is already likely to be in the register(s)
that the return from strdup wants to put the NULL it's gonna return
into since 'copy' was returned from malloc, but many compilers won't
realize that they don't need to write NULL to that location again.
In the second change it is likely that 'copy' won't have to be moved
to be passed to memcpy but will have to have been copied and then
placed into the register(s) that memcpy's return value already is, but
since memcpy returns it's destination pointer this value equals the
value of 'copy'.
These changes aren't going to save a whole lot of space since there's
only one copy of strdup linked in, but they are improvements.

Nathan
Reply all
Reply to author
Forward
0 new messages