16

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!

alk
  • 69,737
  • 10
  • 105
  • 255
pwaring
  • 3,032
  • 8
  • 30
  • 46
  • 1
    Try dumping the list of symbols defined by newlib – M.M May 03 '15 at 09:46
  • How would I do that? – pwaring May 03 '15 at 09:54
  • Just out of curiosity: Does `int main(void) {};` compile? – alk May 03 '15 at 10:31
  • 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 May 03 '15 at 10:32
  • 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 May 14 '15 at 13:33
  • The spec string "lib" in your `mips-gcc` seem to be missing to have an entry for the newlib-library. It is responsible for which libraries to include on the command line to the linker. The spec strings can be printed with `gcc -dumpspecs`. Documentation is [here](https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html). I could not figure it out where to configure these builtin spec strings. – 4566976 May 14 '15 at 15:18
  • I succeded in linking your example, see my updated answer, but I think you can't ignore `cannot find entry symbol _start`. The entry point is now the start of the `.text` section, whatever function resides there. – 4566976 May 16 '15 at 18:36

5 Answers5

7

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.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • I have used the instructions in the link you mentioned, but I could never get glibc to compile, which is why I've switched to newlib (which has compiled successfully). – pwaring May 03 '15 at 11:11
  • This is probably the closest answer to the eventual solution - I had to use glibc and play around with the various config options until I found ones which worked (`--disable-werror` was important). – pwaring May 18 '15 at 10:10
  • @pwaring You're almost done. `${HOME}/xc/bin/mips-gcc hello.c -lc -lcfe -lc` should yield an `a.out`. newlib should work. Just `_start` is still missing for the argv and calling the main function. – 4566976 May 18 '15 at 16:54
  • @4566976 newlib doesn't work at all, GCC fails in the second stage with an error about not being able to find `crti.o` etc. – pwaring May 19 '15 at 13:11
  • @pwaring strange, using your build script `crti.o` was created: see directory contents in the update of my answer. – 4566976 May 19 '15 at 17:19
  • That's the glibc version of the build script. `crti.o` isn't created using the newlib version (there are two branches other than master). – pwaring May 20 '15 at 08:35
0

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.


UPDATE: The builtin specs lib for the default libraries are configured here:

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.


UPDATE: When you configured gcc you gave --target=mips. In gcc-4.9.2\gcc\config.gcc there are other mips-targets which are more specific, e.g.mips*-*-linux*, perhaps selecting the appropriate one gives the right LIB_SPEC and linking will be successful.


UPDATE: big endian Linux target: mips-unknown-linux-gnu little endian Linux target: mipsel-unknown-linux-gnu source


UPDATE: Using your build script I was able to link your sample program with following modifications:

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
4566976
  • 2,419
  • 1
  • 10
  • 14
0

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

Community
  • 1
  • 1
paxmemento
  • 281
  • 4
  • 10
-1

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 )

yurenchen
  • 1,897
  • 19
  • 17
  • I'm aware that `printf` is defined in `libc`, what I want to know is how to fix the linker error. 'Check your C lib' isn't terribly helpful. – pwaring May 15 '15 at 13:44
-1

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.

totten
  • 2,769
  • 3
  • 27
  • 41
  • 2
    That won't work, `putchar` is part of the standard library so if there's a linker problem it will break on `putchar` just as it will for `printf`. – pwaring May 18 '15 at 09:59