【问题标题】:Undefined reference to printf when using GCC cross compiler使用 GCC 交叉编译器时对 printf 的未定义引用
【发布时间】:2015-07-12 18:56:48
【问题描述】:

我正在尝试使用针对 mips 的交叉编译器 (GCC 4.9.2) 来编译以下简单的“Hello World”程序:

#include <stdio.h>

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

x 变量用于阻止 GCC 将 printf 更改为 puts,这对于简单的换行符终止的字符串似乎是自动执行的。

我在${HOME}/xc 下构建了一个交叉编译器,并正在使用以下命令执行它:

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

但是,我收到以下错误:

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

我假设这是链接器的问题,因为如果在搜索路径上找不到例如 stdio.h,我预计该过程会提前失败。我可以编译一个简单的程序,它只返回零,所以并不是整个工具链都被破坏了,大概只是标准库链接(我使用的是 newlib 2.2.0-1)。

无论我是在 Linux (Ubuntu 14.10) 还是 Cygwin (Windows 8) 下运行交叉编译器,我都会遇到相同的错误。

GCC 的完整输出是:

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

我正在使用的构建脚本在这里(我是根据六个教程编写的,这些教程都提出了略有不同的建议):

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

基本上它会执行以下步骤:

  1. 构建 binutils。
  2. 构建 GCC(第 1 阶段)。
  3. 构建新库。
  4. 构建 GCC(第 2 阶段)。

我知道还有其他工具,例如 crosstool-ng 和 builtroot,但是我正在为其构建此工具链的人希望在开始构建过程之前编辑 binutils 的某些部分,并且工具链也必须工作在 Cygwin 下(crosstool-ng 不会因为各种原因,包括区分大小写的文件路径)。

我认为这可能是显而易见的事情,但我已经搞砸了一个星期,看不出它会是什么。任何帮助将不胜感激!

【问题讨论】:

  • 尝试转储由 newlib 定义的符号列表
  • 我该怎么做?
  • 只是出于好奇:int main(void) {}; 是否编译?
  • 是的,我仍然收到cannot find entry symbol _start 警告(根据我使用 ARM 的经验,我认为可以忽略)但它确实编译成功。
  • 如果我在我的 Linux 上运行 gcc -v test.c,它的输出中是一个 -lc 用于 c-library,它不在您的输出中,因此是 undefined reference to printf

标签: c gcc mips cross-compiling undefined-reference


【解决方案1】:

有必要构建库以配合您的交叉编译器。特别是,您需要有一个 glibc 的交叉编译版本或标准库的其他一些实现,才能获得 printf() 的版本。

查看this link 示例,了解为获得所需的所有东西(交叉编译器、标头和库)需要考虑的事物类型。

【讨论】:

  • 我已经使用了您提到的链接中的说明,但是我永远无法编译 glibc,这就是为什么我切换到 newlib(已成功编译)。
  • 这可能是最接近最终解决方案的答案 - 我不得不使用 glibc 并尝试各种配置选项,直到找到可行的选项(--disable-werror 很重要)。
  • @pwaring 你快完成了。 ${HOME}/xc/bin/mips-gcc hello.c -lc -lcfe -lc 应该产生一个a.out。 newlib 应该可以工作。 argv 和调用 main 函数仍然缺少 _start
  • @4566976 newlib 根本不起作用,GCC 在第二阶段失败,出现关于无法找到 crti.o 等的错误。
  • @pwaring 奇怪,使用您的构建脚本 crti.o 已创建:请参阅我的答案更新中的目录内容。
【解决方案2】:

尝试在命令行链接库:

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

包括标准库(lib 和 io)标头默认链接实现(libc.so 或 .a)。但是,您使用的是“用户定义”实现,可能没有链接正确的实现。

我建议在命令行上显式链接。我不确定语法。

编辑: 或者更好的是,使用 makefile 编译以下行,并在 INCLUDES 占位符中指定其他包含目录:

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 是您将包含在newlib.c(实现/定义)源文件(声明函数)和hello.c 中的头文件。它的名称可能与stdio.h 不同。

看看这个,它可能会有所帮助:

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

还有这个:

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

【讨论】:

    【解决方案3】:

    自定义规格文件可以工作:

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

    添加到规格文件中:

    *lib:
    -lc
    

    注意*lib:之前和-lc之后必须有空行。也许您必须将库名称更改为 newlib-c-library 的名称。也许除了-lc 之外还必须添加更多内容,例如我的 Linux 上的*lib:-部分看起来更复杂。


    更新:默认库的内置规范lib 在此处配置:

    在文件 gcc-4.9.2/gcc/gcc.c 第 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
    

    在文件 gcc-4.9.2/gcc/config/mips/elf.h 第 40-42 行:

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

    也许gcc.c 中的默认LIB_SPEC 可以通过注释掉elf.h 中的第40-42 行来为您工作。 也许您需要编辑elf.h 并将空的LIB_SPEC 替换为"-lc" 或类似的东西。


    更新:当您配置gcc 时,您提供了--target=mips。在gcc-4.9.2\gcc\config.gcc 中还有其他更具体的 mips-targets,例如mips*-*-linux*,也许选择合适的目标会给出正确的LIB_SPEC,并且链接会成功。


    更新:大端 Linux 目标:mips-unknown-linux-gnu 小端 Linux 目标:mipsel-unknown-linux-gnu source


    更新:使用您的构建脚本,我能够通过以下修改链接您的示例程序:

    在你的config.sh:

    export ISL_VERSION="0.12.2"
    

    在文件 gcc-4.9.2/gcc/config/mips/elf.h 第 40-42 行:

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

    如果您不想修改 elf.h 中的库,则必须在调用 mips-gcc 时给出。


    更新

    newlib 根本不起作用,GCC 在第二阶段失败,出现关于找不到 crti.o 等的错误。

    奇怪,使用你的构建脚本 crti.o 创建了:

    [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
    

    【讨论】:

      【解决方案4】:

      printf()libc中实现,

      请检查你的c库,比如glibc,哦,你的是newlib


      1. 试试@4566976 的方法
      2. 使用readelf -s检查printf中是否存在libc.so部分libc.a

      (我不确定newlib中的lib文件名,我的是glibc)

      【讨论】:

      • 我知道printf 是在libc 中定义的,我想知道的是如何修复链接器错误。 “检查你的 C 库”并不是很有帮助。
      【解决方案5】:

      实现这一点最方便的方法是使用putchar 代替printf。可能您必须更改一些代码,或者您可能必须添加可能像 printf 一样运行的宏/函数。

      【讨论】:

      • 那行不通,putchar 是标准库的一部分,所以如果出现链接器问题,它将在 putchar 上中断,就像在 printf 上一样。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 1970-01-01
      • 2020-05-17
      • 1970-01-01
      • 2021-09-22
      • 2015-08-25
      • 2017-05-11
      相关资源
      最近更新 更多