gcc交叉编译的实现
转载
gcc支持多种不同的语言,也支持多种不同的CPU架构。
在它的实现上,不同语言编译的实现是通过
const
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
这个结构体的不同定义来实现的。比如c语言的编译器就通过gcc/c-lang.c指定了lang_hooks这个结构体的一个实现。而C++语言编译器对此结构体的实现则放在gcc/cp/cp-lang.c中,同样在gcc目录下还可以发现
gcc/objcp/objcp-lang.c
和gcc/treelang/treetree.c这两个文件也提供了lang_hooks的不同实现。由此就可以很容易发现gcc所支持的编程语言。
而要生成不同目标CPU的代码,gcc则提供了另一个结构体:
struct
gcc_target targetm = TARGET_INITIALIZER;
对此结构体的不同实现则是放在gcc/config/xxx/目录下的,其中xxx是具体的平台,如i386,bfin等等。
当然在后端,除了对gcc_target这个结构体提供不同的实现外,还必须重新定义一系列的宏,这些宏都是放在不同平台的config子目录下的,那么gcc如何知道要包含哪个目录下的头文件呢?
答案就在tm.h。以下是bf561交叉编译器下tm.h的内容:
#ifndef
GCC_TM_H
#define
GCC_TM_H
#ifdef
IN_GCC
# include
"options.h"
# include
"config/bfin/bfin.h"
# include
"config/dbxelf.h"
# include
"config/elfos.h"
# include
"config/bfin/elf.h"
# include
"defaults.h"
#endif
#if
defined IN_GCC && !defined GENERATOR_FILE && !defined USED_FOR_TARGET
# include
"insn-constants.h"
# include
"insn-flags.h"
#endif
#endif
/* GCC_TM_H */
tm.h并不是gcc源码包的一部分,而是动态生成的,在gcc/gcc目录下的Makefile有这样的部分:
tm.h: cs-tm.h ; @true
…
cs-tm.h: Makefile
TARGET_CPU_DEFAULT="$(target_cpu_default)" /
HEADERS="$(tm_include_list)" DEFINES="$(tm_defines)" /
$(SHELL) $(srcdir)/mkconfig.sh tm.h
这说明tm.h的生成要靠mkconfig.sh将tm_include_list这个变量中列出的文件。
再看看tm_include_list的定义:
tm_include_list=options.h config/bfin/bfin.h config/dbxelf.h config/elfos.h config/bfin/elf.h defaults.h
这个变量也是在Makefile中定义的,但是Makefile是由gcc/configure动态生成的,所以再看看gcc/configure中的相关部分:
tm_file_list="options.h"
tm_include_list="options.h"
for f in $tm_file; do
case $f in
defaults.h )
tm_file_list="${tm_file_list} /$(srcdir)/$f"
tm_include_list="${tm_include_list} $f"
;;
* )
tm_file_list="${tm_file_list} /$(srcdir)/config/$f"
tm_include_list="${tm_include_list} config/$f"
;;
esac
done
离目标越来越近了,顺藤摸瓜,看看在config.gcc中对$tm_file的定义:
tm_file=${cpu_type}/${cpu_type}.h
…
case ${target} in
# Support site-specific machine types.
…
bfin*-elf*)
tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h"
tmake_file=bfin/t-bfin-elf
use_collect2=no
;;
bfin*-uclinux*)
tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h bfin/uclinux.h"
tmake_file=bfin/t-bfin-uclinux
use_collect2=no
;;
bfin*-linux-uclibc*)
tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h linux.h bfin/linux.h"
tmake_file="t-slibgcc-elf-ver bfin/t-bfin-linux"
use_collect2=no
;;
bfin*-*)
tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h"
tmake_file=bfin/t-bfin
use_collect2=no
;;
…
呵呵,最后看看cpu_type的定义:
cpu_type=`echo ${target} | sed 's/-.*$//'`
…
case ${target} in
…
bfin*-*)
cpu_type=bfin
;;
…
至此,终于真相大白!
上一篇:GCC中SIMD指令的应用方法
下一篇:程序员成长的10个阶段
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Go程序的交叉编译
Go程序的交叉编译是每一位GO程序猿必须掌握的知识点。但是我没有。在昨天,我编译了一个项目,生成了二进制,放到目标机器上,执行报错,错误如下:bash: ./api.linux: cannot execute binary file: Exec format error提示很明显,可执行文件格式错误,不能执行二进制文件。直接定位到了,是目标机器的内核跟我的Macbook Pro不匹配;接着在目标系
cannot execute binar Exec format error GOARCH GO交叉编译 aarch64 -
gcc/交叉编译
gcc/交叉编译
linux基础知识 c++ linux 编译器 -
Ubuntu 下搭建 GCC 交叉编译工具链
Ubuntu 下搭建 GCC 交叉编译工具链
ubuntu linux arm开发 交叉编译 交叉编译器