GCC编译器原理(一)------交叉编译器制作和GCC组件及命令

1.1 交叉编译器制作

默认安装的 GCC 编译系统所产生的代码适用于本机,即运行 GCC 的机器,但也可将 GCC 安装成能够生成其他的机器代码。安装一些必须的模块,就可产生多种目标机器代码,而且可通过命令行选择一种希望使用的代码。

1.1.1 目标机

从网站 http://gcc.gnu.org/install/specific.html 可以得到有可能的最新目标机列表。在此站点中可找到更新过的目标机列表,以及向各种目标机进行移植的最新信息。关于每种可能的目标机都有一个简短介绍,可以查找说明得到有关移植的一些特殊需求。已知目标的列表非常长,而且也总在加入一些新端口。

1.1.2 创建交叉编译器---crosstool-ng

当前已经不需要我们从源码上进行编译安装一个交叉编译器了,我们可以通过工具crosstool-ng 或是 buildroot 工具来进行交叉编译器的制作

(1)下载

可以在官网上面直接下载

官网:http://crosstool-ng.github.io/

也可以通过git命令直接进行clone下载:

git clone https://github.com/crosstool-ng/crosstool-ng

直接执行git clone命令会在你的工作目录中建立一个crosstool-ng目录,里面存放的是源码。

(2)安装

可以进入如下网站查看具体的安装帮助信息:http://crosstool-ng.github.io/docs/

  • 进入crosstool-ng的源码目录,执行如下命令进行配置:./configure --prefix=/some/place

    • /some/place是自己的主机上的路径。
    • ./configure命令会检查出自己的主机上缺少哪些软件环境,检查出来了逐一安装即可。
  • 执行make命令
  • 执行make install命令
    • 注意以上两个命令可能会报权限不足,在命令前面加sudo解决
  • 将编译出来的bin文件加入到临时环境变量:export PATH="${PATH}:/some/place/bin"
    • 此环境变量只在当前终端中有效,关闭或者切换终端后立即失效。
    • 若要在主机的任何地方任何终端上使用,必须将环境变量写入 .bashrc中去:
      • 可以通过echo命令将其写入 .bashrc中,如下所示:

        • export PATH=/some/place/bin:$PATH
        • 使之生效:source /etc/bash.bashrc
      • 或者执行软链接也可以:sudo ln -s /some/place/bin/ct-ng /usr/local/bin/ct-ng

(3)测试

安装成功后,执行 ct-ng 命令会打印如下信息:

(4)建立S3C2440交叉编译工具链

【1】建立文件夹

建立工作文件夹:

[email protected]:~/work/tools/toolchain$ mkdir S3C2440_work src S3C2440

  • S3C2440_work:为S3C2440交叉编译工具链的工作目录
  • Src:存放下载下来的工具软件源码包
  • S3C2440:存放交叉编译工具链
【2】查看支持的交叉编译工具链类型

执行命令:ct-ng list-samples

里面会列出很多的交叉编译工具样本。介绍ARM的几种:

  • arm-unknown-eabi:基于裸板的,即无操作系统
  • arm-unknown-linux-gnueabi 是基于linux的
  • arm-unknown-linux-uclibcgnueabi是为uclinux用的。
  • arm-cortex_a8-linux-gnueabi为cortex-a8用的。
  • arm-cortexa9_neon-linux-gnueabihf:为cortex-a9带neon用的,exynos4412就可以用此种

S3C2440选择arm-unknown-linux-gnueabi 此种编译器。

所有的支持的编译器存放在[email protected]:~/work/tools/crosstool-ng/samples 此目录下。将其arm-unknown-linux-gnueabi 中的文件拷贝到我们建立的S3C2440_work目录下。

【3】工程配置

进入S3C2440_work目录中,将crosstool.config 文件改名为 .config,然后执行 ct-ng menuconfig命令进行配置

  • Paths and misc options:

    • Local tarballs directory:源码包存放位置,修改为 /home/rk3399/work/tools/toolchain/src
    • Prefix directory :交叉编译工具链存放位置,home/rk3399/work/tools/toolchain/S3C2440
    • Number of parallel jobs:工作线程,根据自己的CPU是多少核来选。
  • Target options:
    • Target Architecture:默认是ARM
    • Default instruction set mode:指令集模式,默认为ARM
    • Architecture level:架构指令集,S3C2440为armv4t
    • Emit assembly for CPU:指定目标处理器的名称,GCC通过这个名字来决定通过汇编代码来生成哪种指令。填入 arm9tdmi
    • Tune for CPU:新版本中填入上面两个选项就没有这个选项了,就管了。
    • Floating point:浮点类型,可以看芯片手册的方框图,看找不找不到对应的浮点数类型,S3C2440没有硬件浮点,选择软件浮点。softfp (FPU)
  • Toolchain options:
    • Tuple‘s vendor string:编译器前缀,设为s3c2440,编译之后就为arm-s3c2440-linux-gnueabi-
    • Tuple‘s alias:给产生的交叉编译工具起个别名,设置别名,这样会给每个工具创建一个软链接,比如arm-linux-gcc链接到到 arm-unknown-linux-gnueabi-gcc,可以省去自己建立软链接的功夫。设置为
  • Operating System:
    • Source of linux:linux源码,这里没有自己需要的源码包,可以在 .config中修改配置,系统会自动去下载。
  • 剩余的其他选项保持默认即可。

架构和处理器名称,可以在芯片手册的方框图中找到,如下:

【4】编译

执行命令 ct-ng build 即可开始编译。

制作完成会打印出下面的语句:

(5)制作 exynos 4412 编译器

基本步骤与上面类似,不同的是在crosstool-ng中编译器的选择方面和工程配置上面。

Exynos 4412 选择的是 arm-cortexa9_neon-linux-gnueabihf 编译器,exynos 4412本身就是带neon的,处理器本身就是属于cortexa9系列。

配置上只是更改下Target options 中的内容:

  • Target options:

    • Architecture level:架构指令集为armv7a
    • Emit assembly for CPU:指定目标处理器的名称为cortex-a9
    • Floating point:与2440不同的是,a9系列带应浮点,也就是neon,这里要选择硬件浮点
    • Use specific FPU:这里要填上 neon

之后就是保存编译了。

1.1.3 编译程序的功能

编译程序是一个翻译器。它读入一种语言格式的指令(通常是文本形式的编程语言),并将它们翻译成可在计算机上运行的指令集合(通常是二进制硬件指令的集合)。

  • 编译程序可以分为两部分:前端和后端。

    • 前端读出程序的源代码,将找到的内容以树的形式转换到内存驻留表(memory-resident table)中。一旦构造了该树,编译程序的后端就会读出树中保存的信息,并将它们转换成目标机器上的汇编语言。
    • 将源文件翻译成可执行程序的大致步骤:
      • 词法分析是编译程序前端的最开始部分。它从输入中读出字符,确定哪些是在一起的,形成符号、数字和标点符号。
      • 语法分析处理会读入来自词法浏览器的符号流,以及后面跟着的一个规则集合,确定它们之间的关系。 语法分析器的输出结果是树结构, 会被传递给编译程序的后端。
      • 语法分析树结构会被翻译成伪汇编语言(psuedo-assembly language) ,叫做寄存器传送语言(Register Transfer Language,RTL)。
      • 编译程序的后端由分析 RTL 代码开始,然后执行一些优化操作。代码中冗余和未被使用的部分会被去掉。树中有些部分会被移动到其他位置以防止语句被不必要地多次执行。总的说来,有十个以上的优化操作,而且有些优化操作会多次浏览代码。
      • RTL 被翻译成目标机器上的汇编语言。
      • 激活汇编器去将汇编语言翻译成目标文件。该文件不是可执行格式——它包括可执行的目标代码,但并不是最终运行的形式。另外,它更可能包括未解析的到其他模块例程和数据的引用。
      • 连接程序将来自汇编器的目标文件(其中有些可能保存在包含目标文件的库中)组合成可执行程序。
  • 所有的命令行选项大致可分为三类:
    • 指定语言 GCC 编译程序有能力编译多种语言,有些选项只可用于其中的一两种。例如,-C89 选项只应用于 C 语言,指定适用于 1989 年的标准。
    • 指定平台 GCC 编译程序可以为多种平台生成目标代码,而有些选项只能应用于为某个指定平台生成代码。例如,如果输出平台是 Intel 386,那么-fp-ret-in-387 选项可用来指出要将函数调用返回的浮点数保存在硬件的浮点寄存器中。
    • 普适 很多选项对所有语言和平台都适用。例如,-O 选项指示编译程序要优化输出代码。

例子:gcc -ansi -c muxit.c -o muxit.o

  • -ansi 即是指定语言

1.2 GCC组件及命令

1.2.1 GCC组件

GCC 是由许多组件组成的,但它们也并不总是出现的。有些部分是和语言相关的,所以如果没有安装某种特定语言,系统中就不会出现相关的文件。


组件


描述


c++


gcc 的一个版本,默认语言设置为 C++,而且在连接的时候自动包含标准 C++库。这和g++一样


cc1


实际的 C 编译程序


cc1plus


实际的 C++编译程序


collect2


在不使用 GNU 连接程序的系统上, 有必要运行 collect2 来产生特定的全局初始化代码 (例如 C++的构造函数和析构函数)


configure


GCC 源代码树根目录中的一个脚本。用于设置配置值和创建 GCC 编译程序必需的 make程序的描述文件


crt0.o


这个初始化和结束代码是为每个系统定制的,而且也被编译进该文件,该文件然后会被连接到每个可执行文件中来执行必要的启动和终止程序


cygwin1.dll


Windows 的共享库提供的 API,模拟 UNIX 系统调用


f77


该驱动程序可用于编译 Fortran


f771


实际的 Fortran 编译程序


g++


gcc 的一个版本,默认语言设置为 C++,而且在链接的时候自动包含标准 C++库。这和 c++ 是一样的


gcc


该驱动程序用于执行编译程序和连接程序以产生需要的输出


gcj


该驱动程序用于编译 Java


gnat1


实际的 Ada 编译程序


gnatbind


一种工具,用于执行 Ada 语言绑定


gnatlink


一种工具,用于执行 Ada 语言连接


jc1


实际的 Java 编译程序


libgcc


该库包含的例程被作为编译程序的一部分,是因为它们可被连接到实际的可执行程序中。它们是特殊的例程,连接到可执行程序,来执行基本的任务,例如浮点运算。这些库中的例程通常都是平台相关的


libgcj


运行时库包含所有的核心 Java 类


libobjc


对所有 Objective-C 程序都必须的运行时库


libstdc++


运行时库,包括定义为标准语言一部分的所有的 C++类和函数

1.2.2 GCC 编译器命令

GCC的命令很多,常用的选项如下:


选项


描述


-c


只编译不链接。

会明确指示 GCC 去编译源代码,在硬盘上留下目标文件,且跳过将目标文件连接到可执行程序这一步。

缺省情况下, GCC通过用`.o‘替换源文件名后缀`.c‘, `.i‘, `.s‘,等产生目标文件名.可以使用-o选项选择其他名字.

GCC忽略-c选项后面任何无法识别的输入文件(他们不需要编译或汇编).

如:gcc -c hello.c


-o file


指定输出的文件名

如果没有使用 `-o‘ 选项,默认的输出结果是:可执行文件为`a.out‘。如gcc -c hello.c -o hello.o


-x language


明确指出后面输入文件的语言为language (而不是从文件名后缀得到的默认选择).这个选项应用于后面 所有的输入文件,直到遇着下一个`-x‘选项. language的可选值有`c‘, `objective-c‘, `c-header‘, `c++‘, `cpp-output‘, `assembler‘,和`assembler-with-cpp‘.


-x none


关闭任何对语种的明确说明,因此依据文件名后缀处理后面的文件(就象是从未使用过`-x‘选项).

如果只操作四个阶段(预处理,编译,汇编,连接)中的一部分,可以使用`-x‘选项(或文件名后缀)告诉 gcc从哪里开始,用`-c‘, `-S‘,或`-E‘选项告诉gcc到 哪里结束.注意,某些选项组合(例如, `-x cpp-output -E‘)使gcc不作任何事情.


-S


指示编译程序生成汇编语言代码,然后停止。

缺省情况下, GCC通过用 `.o‘ 替换源文件名后缀 `.c‘、`.i‘ 等等,产生 目标文件名。可以使用-o选项选择其他名字。

汇编语言的形式依赖于编译程序的目标平台。如果编译多个源文件,会为每个源文件都生成一个汇编语言模块。

GCC忽略任何不需要编译的输入文件。

gcc -S helloworld.c


-E


预处理后即停止,不进行编译。预处理后的代码送往标准输出

GCC忽略任何不需要预处理的输入文件.

gcc -E helloworld.c

gcc -E helloworld.c -o helloworld.i


-C


告诉预处理器不要丢弃注释,配合 `-E‘ 选项使用。


-P


告诉预处理器不要产生 `#line‘ 命令,配合 `-E‘ 选项使用


-v


(在标准错误)显示执行编译阶段的命令.同时显示编译器驱动程序,预处理器,编译器的版本号.


-pipe


在编译过程的不同阶段间使用管道而非临时文件进行通信.这个选项在某些系统上无法工作,因为那些系统的 汇编器不能从管道读取数据. GNU的汇编器没有这个问题.


-ldl


表示生成的对象模块需要用到共享库:$ gcc say.c -ldl -o say

主要是用到了 dlopen 等函数需要用到此选项


-I


指定头文件路径


-e name


指定 name 为程序的入口地址


-ffreestanding


编译独立的程序,不会自动链接 C 运行库、启动文件等;他隐含声明了 `-fno-builtin‘ 选项,而且对main函数没有特别要求。


-finline-functions

-fno-inline-funcitons


启用内联函数

关闭内联函数


-g


以操作系统的本地格式(stabs,COFF,XCOFF 或 DWARF)产生调试信息,GDB能够使用这些调试信息。


-ggdb


以本地格式(如果支持)输出调试信息,尽可能包括GDB扩展。


-L <directory>


指定链接时查找路径,多个路径之间用冒号隔开


-nostartfiles


不链接系统标准启动文件,比如crtbegin.o、crtend.o,而标准库文件仍然正常使用。


-nostdlib


不链接系统标准启动文件和标准库文件,只把指定的文件传递给连接器。


-static


在支持动态连接(dynamic linking)的系统上阻止连接共享库。即只能使用静态链接。


-shared


生成一个共享目标文件,他可以和其他目标文件链接产生可执行文件。


-O
-O1


优化。对于大函数,优化编译占用稍微多的时间和相当大的内存。

不使用 `-O‘ 选项时,编译器的目标是减少编译的开销,使编译结果能够调试。

语句是独立的:如果在两条语句之间用断点中止程序,可以对任何变量重新赋值,或者在函数体内把程序计数器指到其他语句,以及从源程序中精确地获取你期待的结果。

不使用 `-O‘ 选项时,只有声明了register的变量才分配使用寄存器。编译结果比不用 `-O‘ 选项的GCC要略逊一筹.

使用了 `-O‘ 选项,编译器会试图减少目标码的大小和执行时间。

如果指定了`-O‘选项,,`-fthread-jumps‘ 和 `-fdefer-pop‘ 选项将被打开。


-O2


多优化一些。

除了涉及空间和速度交换的优化选项,执行几乎所有的优化工作。例如不进行循环展开(loop unrolling)和函数内嵌(inlining)。

和 -O 选项比较,这个选项既增加了编译时间,也提高了生成代码的运行效果。


-O3


优化的更多。除了打开 -O2所做的一切,它还打开了-finline-functions选项。


-O0


不优化。如果指定了多个 -O选项,不管带不带数字,最后一个选项才是生效的选项。


-Wall


对源代码中的多数编译警告进行启用


-fpic


如果支持这种目标机,编译器就生成位置无关目标码。适用于共享库(shared library)。


-fPIC


如果支持这种目标机,编译器就输出位置无关目标码。适用于动态连接(dynamic linking),即使分支需要大范围转移。


-fPIE


使用地址无关代码模式编译可执行文件


-Xlinker option


把选项option传递给连接器,可以用他传递系统特定的连接选项, GNU CC无法识别这些选项。

如果需要传递携带参数的选项,必须使用两次 `-Xlinker‘,一次传递选项,另一次传递他的参数。

例如,如果传递 `-assert definitions‘,必须写成 `-Xlinker -assert -Xlinker definitions‘,而不能写成 `-Xlinker "-assert definitions"‘,因为这样会把整个字符串当做一个参数传递,显然这不是连接器期待的。


-Wl option


把选项option传递给连接器。如果option中含有逗号,就在逗号处分割成多个选项。


-fomit-frame-pointer


禁止使用 EBP 作为函数帧指针


-fno-builtin


禁止 GCC 编译器内置函数


-ffunction-sections


将每个函数编译到独立的代码段


-fdata-sections


将全局/静态变量编译到独立的数据段

原文地址:https://www.cnblogs.com/kele-dad/p/9393500.html

时间: 2024-11-10 00:25:07

GCC编译器原理(一)------交叉编译器制作和GCC组件及命令的相关文章

Ubuntu 12.04 64bit GCC交叉编译器制作 原创

                                                                                                                             做嵌入式开发少不了跨平台操作,因此也少不了使用交叉编译器,我们可以自己动手制作属于我们自己的交叉编译器,其中可以定制一些东西,可以使之支持浮点运算等特殊要求.以下以适合嵌入式开发最常用的ARM平台的ARMGCC交叉编译器为例进行讲解:其他平台步骤和方

第一部分:为2440 制作自己的任意版本的交叉编译器

第一部分  安装交叉编译工具链 使用crosstool-0.43制作交叉编译工具链,随着gcc版本的增高,正确的制作已不太可能,crosstool-0.43制之后不再有更新,因此这个选用的是nt-ng工具制作交叉编译工具链. 1.nt-ng的安装 Crostool很多年不在维护了,下面尝试一下使用crosstool的下一代 crosstool-ng 具体使用说明见: http://www.crifan.com/files/doc/docbook/crosstool_ng/release/html

linux下交叉编译器制作

目前我用的交叉编译器是TQ2440配套光盘中制作好了的,解压后需要如下配置: 1.对于Fedora系统:修改/etc/profile文件,在其中添加交叉编译器的环境变量的设置. 对于Ubuntu系统,修改/etc/enviroment文件 2.我用的是Fedora系统,修改PATH值,在其后添加上交叉编译器的路径,添加pathmunge /opt/EmbedSky/4.3.3/bin 对于Ubuntu系统,修改PATH="/usr/local/sbin:/usr/local/bin:/usr/s

交叉编译器制作 - 升级版教程

大三那会写的一篇关于交叉编译工具制作的教程. crosstool-ng-1.20.0制作交叉编译工具 由于之前那篇实在太简单,很多东西都没有涉及介绍到.因此: 目录: ----1.配置选项详解 ----2.如何build最好最快 ----3.由交叉编译器引发的思考 1.配置选项详解 版权声明:本文为博主原创文章,未经博主允许不得转载.

GCC编译器原理(三)------编译原理三:编译过程---预处理

Gcc的编译流程分为了四个步骤: 预处理,生成预编译文件(.文件):gcc –E hello.c –o hello.i 编译,生成汇编代码(.s文件):gcc –S hello.i –o hello.s 汇编,生成目标文件(.o文件):gcc –c hello.s –o hello.o 链接,生成可执行文件:gcc hello.o –o hello 一.预处理 预编译程序读出源代码,对其中内嵌的指示字进行响应,产生源代码的修改版本,修改后的版本会被编译程序读入. 在 GNU 术语中,预处理程序叫

什么是交叉编译器?

由于项目的需要,我们需要一个能在x86平台上运行,生成mips应用程序的交叉编译器,最近几天一直在搞这个,看了很多的文章也试 了不少的方法,最后终于成功了,还不错,有些新的和大家交流一下. 什么是交叉编译器? 为什么叫“交叉编译器”(cross compiler),就是因为它跨平台来编译程序!做交叉编译器要弄清楚3个概念:host, build, target: build -- 你在什么平台上编译的这个编译器 host -- 这个编译器将来要在什么平台上运行 target -- 编译器最终会生

如何得到交叉编译器

了解了之前的交叉编译器的命名规则后,也就明白了交叉编译,针对不同架构,平台,目标系统等的区别. 而对于嵌入式开发,想要获得,针对我们所需要的,目标的CPU所合适的交叉编译器,就成了接下来,顺其自然要考虑的事情. 想要得到,可用的,针对自己的CPU的交叉编译器,主要有两种方式: 3.2.1. 拿来主义:直接去下载和使用别人已经编译好的交叉编译器 难度等级:1级 这个没有啥特殊要求解释的,就是,网上,总会有,免费的,好用的各种资源的. 其中就包括,别人,已经针对某些CPU,某些平台,编译好了交叉编译

交叉编译器的名字的命名规则

交叉编译器的名字的命名规则 在折腾嵌入式开发,用到交叉编译器的时候,常常会看到这样的名字: arm-xscale-linux-gnueabi-gcc arm-liunx-gnu-gcc 等等 其中,对应的交叉编译器的前缀为: arm-xscale-linux-gnueabi- arm-liunx-gnu- 而关于这些名字,我之前也是没注意其具体含义,或者说对于其含义也是很模糊的感觉,不是很清楚这些名字是从何而来的. 后来,经过折腾了crosstool-ng后,基本上明白了这些名字,是如何生成的.

[转载]arm交叉编译器gnueabi、none-eabi、arm-eabi、gnueabihf、gnueabi区别

arm交叉编译器gnueabi.none-eabi.arm-eabi.gnueabihf.gnueabi区别 (http://www.veryarm.com/296.html) 命名规则 交叉编译工具链的命名规则为:arch [-vendor] [-os] [-(gnu)eabi] arch - 体系架构,如ARM,MIPS vendor - 工具链提供商 os - 目标操作系统 eabi - 嵌入式应用二进制接口(Embedded Application Binary Interface) 根