14
votes

I'm trying to get the following simple 'Hello World' program to compile using a cross compiler (GCC 4.9.2) targeting mips:

#include <stdio.h>

int main()
{
  int x = 5;
  printf("x = %d\n", x);
}

The x variable is there to stop GCC changing printf to puts, which it seems to do automatically for a simple newline-terminated string.

I've built a cross compiler under ${HOME}/xc and am executing it using the following command:

${HOME}/xc/bin/mips-gcc -v hello.c

However, I'm getting the following error:

/tmp/ccW5mHJu.o: In function `main':
(.text+0x24): undefined reference to `printf'
collect2: error: ld returned 1 exit status

I'm assuming this is a problem with the linker, as I'd expect the process to fail earlier if for example stdio.h couldn't be found on the search path. I can compile a simpler program which simply returns zero, so it's not the case that the entire toolchain is broken, presumably just the standard library linking (I'm using newlib 2.2.0-1).

I get the same error regardless of whether I run the cross compiler under Linux (Ubuntu 14.10) or Cygwin (Windows 8).

The full output from GCC is:

Using built-in specs.
COLLECT_GCC=/home/paul/xc/bin/mips-gcc
COLLECT_LTO_WRAPPER=/home/paul/xc/libexec/gcc/mips/4.9.2/lto-wrapper
Target: mips
Configured with: /home/paul/xc/mips/tmp/gcc-4.9.2/configure --prefix=/home/paul/xc --target=mips --enable-languages=c --with-newlib --without-isl --without-cloogs --disable-threads --disable-libssp --disable-libgomp --disable-libmudflap
Thread model: single
gcc version 4.9.2 (GCC) 
COLLECT_GCC_OPTIONS='-v'
 /home/paul/xc/libexec/gcc/mips/4.9.2/cc1 -quiet -v hello.c -quiet -dumpbase hello.c -auxbase hello -version -o /tmp/ccCpAajQ.s
GNU C (GCC) version 4.9.2 (mips)
    compiled by GNU C version 4.9.1, GMP version 6.0.0, MPFR version 3.1.2, MPC version 1.0.3
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/home/paul/xc/lib/gcc/mips/4.9.2/../../../../mips/sys-include"
#include "..." search starts here:
#include <...> search starts here:
 /home/paul/xc/lib/gcc/mips/4.9.2/include
 /home/paul/xc/lib/gcc/mips/4.9.2/include-fixed
 /home/paul/xc/lib/gcc/mips/4.9.2/../../../../mips/include
End of search list.
GNU C (GCC) version 4.9.2 (mips)
    compiled by GNU C version 4.9.1, GMP version 6.0.0, MPFR version 3.1.2, MPC version 1.0.3
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: cffaaedf0b24662e67a5d97387fc5b17
COLLECT_GCC_OPTIONS='-v'
 /home/paul/xc/lib/gcc/mips/4.9.2/../../../../mips/bin/as -EB -O1 -no-mdebug -mabi=32 -o /tmp/ccW5mHJu.o /tmp/ccCpAajQ.s
COMPILER_PATH=/home/paul/xc/libexec/gcc/mips/4.9.2/:/home/paul/xc/libexec/gcc/mips/4.9.2/:/home/paul/xc/libexec/gcc/mips/:/home/paul/xc/lib/gcc/mips/4.9.2/:/home/paul/xc/lib/gcc/mips/:/home/paul/xc/lib/gcc/mips/4.9.2/../../../../mips/bin/
LIBRARY_PATH=/home/paul/xc/lib/gcc/mips/4.9.2/:/home/paul/xc/lib/gcc/mips/4.9.2/../../../../mips/lib/
COLLECT_GCC_OPTIONS='-v'
 /home/paul/xc/libexec/gcc/mips/4.9.2/collect2 -plugin /home/paul/xc/libexec/gcc/mips/4.9.2/liblto_plugin.so -plugin-opt=/home/paul/xc/libexec/gcc/mips/4.9.2/lto-wrapper -plugin-opt=-fresolution=/tmp/cc8TAJb9.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc -EB /home/paul/xc/lib/gcc/mips/4.9.2/crti.o /home/paul/xc/lib/gcc/mips/4.9.2/crtbegin.o -L/home/paul/xc/lib/gcc/mips/4.9.2 -L/home/paul/xc/lib/gcc/mips/4.9.2/../../../../mips/lib /tmp/ccW5mHJu.o -lgcc -lgcc /home/paul/xc/lib/gcc/mips/4.9.2/crtend.o /home/paul/xc/lib/gcc/mips/4.9.2/crtn.o
/home/paul/xc/lib/gcc/mips/4.9.2/../../../../mips/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400050
/tmp/ccW5mHJu.o: In function `main':
(.text+0x24): undefined reference to `printf'
collect2: error: ld returned 1 exit status

The build script I'm using is here (I wrote it based on half a dozen tutorials which all suggested slightly different things):

https://github.com/UoMCS/mips-cross-compile

Basically it does the following steps:

  1. Build binutils.
  2. Build GCC (stage 1).
  3. Build newlib.
  4. Build GCC (stage 2).

I'm aware that there are other tools such as crosstool-ng and builtroot, however the person I'm building this toolchain for wants to edit parts of binutils before setting off the build process, and the toolchain also has to work under Cygwin (crosstool-ng won't for various reasons, including case-sensitive file paths).

I think this is probably going to be something obvious, but I've been messing around with this for a week and can't see what it could be. Any help would be greatly appreciated!

5
Try dumping the list of symbols defined by newlib - M.M
How would I do that? - pwaring
Just out of curiosity: Does int main(void) {}; compile? - alk
Yes, I still get the cannot find entry symbol _start warning (which I think can be ignored based on my experience with ARM) but it does compile successfully. - pwaring
If i run gcc -v test.c on my Linux, in its output is a -lc for the c-library which is not present in your output hence the undefined reference to printf. - 4566976

5 Answers

5
votes

It is necessary to build libraries to go with your cross compiler. In particular, you need to have a cross-compiled version of glibc or some other implementation of the standard library, to get a version of printf().

Have a look at this link for an example of the type of things you need to consider to get all the things you need - the cross-compiler, the headers, and libraries.

0
votes

Try linking the library on the command line:

${HOME}/xc/bin/mips-gcc -v hello.c -lib

Including the std libraries (lib and io)header links the implementations by default (libc.so or .a). However, you are using a 'user-defined' implementation and may not be linking the proper one.

I suggest explicit linkage on the command line. I'm not certain of the syntax.

EDIT: Or better Still, use a makefile to compile with the following lines, and specifying other include directories in the INCLUDES place holder:

CC = gcc
CXX = g++
INCLUDES =
CFLAGS = -g -Wall $(INCLUDES)
CXXFLAGS = -g -Wall $(INCLUDES)
LDFLAGS = -g
hello: hello.o newlib.o
hello.o: hello.c newlib.h
newlib.o: newlib.c newlib.h

newlib.h is the header file you'll include in newlib.c (implementation/definition) source file (that declares the functions) and hello.c. It may be named differently from stdio.h.

Check this out, it may help:

Why do you have to link the math library in C?

and this too:

http://www.tldp.org/HOWTO/Glibc2-HOWTO-6.html

0
votes

A custom specs file could work:

cd /home/paul/xc/lib/gcc/mips/4.9.2/
${HOME}/xc/bin/mips-gcc -dumpspecs > specs

Add to the specs file:

*lib:
-lc

Note that there must be empty lines before *lib: and after -lc. Perhaps you have to change the library name to the name of your newlib-c-library. Perhaps more must be added than only -lc, e.g. the *lib:-section on my Linux looks more complex.


UPDATElib

In file gcc-4.9.2/gcc/gcc.c lines 527-530:

/* config.h can define LIB_SPEC to override the default libraries.  */
#ifndef LIB_SPEC
#define LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}"
#endif

In file gcc-4.9.2/gcc/config/mips/elf.h lines 40-42:

/* Leave the linker script to choose the appropriate libraries.  */
#undef  LIB_SPEC
#define LIB_SPEC ""

Perhaps the default LIB_SPEC in gcc.c works for you by commenting out lines 40-42 in elf.h. Perhaps you need to edit elf.h and replace the empty LIB_SPEC with "-lc" or something similar.


UPDATEgcc--target=mipsgcc-4.9.2\gcc\config.gccmips*-*-linux*LIB_SPEC


UPDATEmips-unknown-linux-gnumipsel-unknown-linux-gnusource


UPDATE

In your config.sh:

export ISL_VERSION="0.12.2"

In file gcc-4.9.2/gcc/config/mips/elf.h lines 40-42:

/* Leave the linker script to choose the appropriate libraries.  */
#undef  LIB_SPEC
#define LIB_SPEC "-lc -lcfe -lc"

If you don't want the modification in elf.h the libraries must be given when invoking mips-gcc.


UPDATE

newlib doesn't work at all, GCC fails in the second stage with an error about not being able to find crti.o etc.

Strange, using your build script crti.o was created:

[osboxes@osboxes 4.9.2]$ pwd
/home/osboxes/xc/lib/gcc/mips/4.9.2
[osboxes@osboxes 4.9.2]$ ll
total 6240
-rw-r--r--. 1 osboxes osboxes    3248 May 16 19:49 crtbegin.o
-rw-r--r--. 1 osboxes osboxes    1924 May 16 19:49 crtend.o
-rw-r--r--. 1 osboxes osboxes    1040 May 16 19:49 crti.o
-rw-r--r--. 1 osboxes osboxes    1056 May 16 19:49 crtn.o
drwxrwxr-x. 3 osboxes osboxes    4096 May 16 19:49 include
drwxrwxr-x. 2 osboxes osboxes    4096 May 16 19:45 include-fixed
drwxrwxr-x. 3 osboxes osboxes    4096 May 16 19:49 install-tools
-rw-r--r--. 1 osboxes osboxes 6289352 May 16 19:49 libgcc.a
-rw-r--r--. 1 osboxes osboxes   56844 May 16 19:49 libgcov.a
drwxrwxr-x. 3 osboxes osboxes    4096 May 16 19:49 plugin
-rw-rw-r--. 1 osboxes osboxes    6215 May 18 18:45 specs
-1
votes

printf() was implemented in libc,

Please check your c lib, such as glibc, oh, yours is newlib.


  1. try @4566976 's way
  2. use readelf -s check is there a printf section exists in libc.so libc.a

( i'm not sure the lib filename in newlib, mine is glibc )

-1
votes

The most convenient way to achieve this is to use putchar in place of printf. May be you have to change some of your code, or may be you have to add macros/functions that may run like printf.