【ARM 嵌入式 编译系列 2 -- GCC 编译过程介绍】


请阅读【ARM GCC 编译专栏导读】


上篇文章:ARM 嵌入式编译系列 1 – GNU/GCC/GDB/GNU binutils介绍
下篇文章:ARM 嵌入式 编译系列 2.1 – GCC 编译参数学习

1.1 GCC 编译介绍

GCC,全称GNU Compiler Collection(GNU编译器套件),起初是GNU项目的一部分,为Unix和类Unix系统(包括Linux)提供一个免费的编译器,现已成为大多数类Unix系统的标准编译器。

GCC是一个跨平台的编译器,能够支持多种编程语言,如C、C++、Objective-C、Fortran、Ada、D等,而且还能为多种处理器架构生成目标代码,包括x86、ARM、MIPS、PowerPC等。

GCC主要由四部分组成:预处理器(cpp)、编译器本身(cc1)、汇编器(as)和链接器(ld)。

1.1.1 gcc-arm-none-eabi toolchain 介绍及安装

gcc-arm-none-eabi 是一个开源的ARM开发工具链,适用于Arm Cortex-MCoretex-A 系列处理器,我们可以从从 ARM 官方下载链接选择合适的版本下载。

关于 gcc arm 更多的内容请见文章ARM 嵌入式编译系列 1 – GNU/GCC/GDB/GNU binutils介绍

注意:编译前需要指定交叉编译工具的路径,可以使用下面方法设置,在linux环境下需要根据自己的目录设定绝对路径

$ vim ~/.bashrc //add the below 
export CROSS_COMPILE
declare -x CROSS_COMPILE=/.../gcc-arm-none-eabi/bin/arm-none-eabi-"

在终端中输入:

$ source ~/.bashrc

然后输入命令 :

arm-none

然后按三下 Tab(一定不要输入全部),检查系统是否可以自动补全。

1.1.2 编译过程

一个完整的GCC编译过程通常包括预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)和链接(Linking)这四个步骤。

预处理:预处理器拿到源代码后,会处理源代码中的预处理指令,如宏定义(#define)、头文件包含(#include)、条件编译(#ifdef#ifndef#if等)等。预处理器的输出是一个纯文本的源码文件。

例如,以下命令将执行预处理步骤:

gcc -E source.c -o source.i

这将生成一个预处理后的文件source.i

编译:编译器会把预处理后的源码编译成汇编语言代码。编译器在这一步会进行词法分析、语法分析、语义分析和优化等操作。

例如,以下命令将执行编译步骤:

gcc -S source.i -o source.s

这将生成一个汇编语言文件source.s

汇编:汇编器会将汇编代码转换成机器指令,即目标代码。输出的文件叫做目标文件(Object File),这是一个二进制文件。

例如,以下命令将执行汇编步骤:

gcc -c source.s -o source.o

这将生成一个目标文件source.o

链接:链接器会把多个目标文件和库文件链接成一个可执行文件。链接器需要处理全局变量和函数的引用,并决定它们在可执行文件中的地址。

例如,以下命令将执行链接步骤:

gcc source.o -o output

这将生成一个可执行文件output。

通常,我们会一次性执行这四个步骤,如以下命令:

gcc source.c -o output

这将会编译source.c并生成一个可执行文件output

由于编译涉及内容过多,所以通常会将编译相关的部分单独写入一个脚本中,如py脚本或者shell脚本,或者几个脚本中。如下的编译参数是 rt-thread 中在一个 python 脚本 rtconfig.py 中配置的:

if PLATFORM == 'gcc':
    # toolchains
    PREFIX = 'arm-none-eabi-'        //指定交叉编译工具为arm-noe-eabi-
    CC = PREFIX + 'gcc'
    AS = PREFIX + 'gcc'              //用于编译
    AR = PREFIX + 'ar'               //用于lib/.a文件的处理:添加/删除/生成/解压等
    CXX = PREFIX + 'g++'
    LINK = PREFIX + 'gcc'
    TARGET_EXT = 'elf'               //用于读取elf 头信息
    SIZE = PREFIX + 'size'
    OBJDUMP = PREFIX + 'objdump'     //用于对elf文件进行反汇编等操作
    OBJCPY = PREFIX + 'objcopy'      //主要用于将elf文文件copy为binary文件
    
    TOOLS_PATH = TOP_ROOT + '/tools/misc'   //指定编译工具所在的路径
    GENIMG = TOOLS_PATH + '/gen_rtos_img.sh' //指定mkimage工具所在的脚本

    DEVICE = ' -mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard   \
    				-ffunction-sections -fdata-sections'     //设定编译参数
    CFLAGS = DEVICE + ' -Dgcc'
    AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb '
    LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,
                             -u,Reset_Handler -T board/link.lds' \
    CPATH = ''
    LPATH = ''
    if BUILD == 'debug':
        CFLAGS += ' -O0 -gdwarf-2 -g'
        AFLAGS += ' -gdwarf-2' // 调试信息的存放格式按照 dwarf2标准来
    else:
        CFLAGS += ' -O2'
    CXXFLAGS = CFLAGS
    CFLAGS += ' -std=gnu99' //指定支持的C标准
    CFLAGS += ' -Werror'  // 将将警告升级为错误

由于使用工具 gcc-arm-none-eabi 编译出来的是个可执行的 elf 文件,里面包含了很多信息,可以通过objcpy将一些不需要的信息去掉,然后再通过 mkimage 给生成 .bin 文件添加上 header

POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + \
              GENIMG + ' 0x0 rtthread.bin rtthread.img\n' + \
              SIZE + ' $TARGET\n'

关于objcpy的内容一 关于objcpy的内容二

目标文件的内容是编译后的机器指令代码,数据,符号表,调试信息,字符串等,同时,是分别以"段"的形式存储。

objcopy 是 GNU的一个工具,其作用是将 elf 目标文件的一部分或者全部内容拷贝为一个二进制binary文件,或者进行目标文件的格式转换。

  • 通过 arm-none-eabi-objcompyrtthread.bin 生成为 rtthread.elf
  • 通过 gen_rtthraed_img.sh 调用 mkimagertthread.bin 添加 header,生成 rtthread.bin

1.2 ELF 文件

ELF 代表"可执行和可链接格式"(Executable and Linkable Format),是一种常见的对象文件格式。在 Linux 和许多其他类Unix系统中,ELF是标准的二进制文件格式。

GCC 创建的可执行文件、目标文件、共享库以及核心转储文件都是ELF格式的。

GCC使用链接器(通常是ld)来链接ELF目标文件,并可以使用 objdumpreadelfnm等工具来查看ELF文件的内容和结构。

1.2.1 ELF 文件组成

ELF文件主要由以下部分组成:

  • ELF头(ELF Header):包含了文件的类型(如可执行文件、共享库或目标文件)、文件的体系结构(如x86或ARM)、段表和节表的位置等信息。

  • 程序头表(Program Header Table):这部分在可执行文件和共享库中存在,描述了系统如何创建进程映像。

  • 节区头表(Section Header Table):这部分在目标文件中存在,描述了文件的节区结构。

    • text section 里装载了可执行代码;
    • data section 里面装载了被初始化的数据;
    • bss section 里面装载了未被初始化的数据;
    • 以 .rec 打头的 sections 里面装载了重定位条目;
    • symtab 或者 .dynsym section 里面装载了符号信息;
    • strtab 或者 .dynstr section 里面装载了字符串信息。
  • 数据(Data):包含了代码和数据等。

这是一个使用GCC创建ELF文件的例子:

gcc -o output source.c

在这个命令中,GCC将源文件"source.c"编译并链接成一个可执行的ELF文件,文件名为"output"。

你可以使用file命令来查看一个文件的类型,例如:

file output

如果"output"是一个ELF文件,你将会看到类似"ELF 64-bit LSB executable"的输出。

1.3 bin 文件

bin 文件和 elf文件 基本上都是可执行文件,但它们的格式和使用方式有一些重要的区别。

elf 文件是一种复杂的二进制格式,它包含了很多元数据,如程序的入口点、程序需要的共享库、程序的段和节的信息等。因此,elf文件不仅可以被执行,还可以被调试和反向工程等。在Linux系统中,大多数可执行文件、库和驱动都是elf格式的。GCC默认生成的就是elf格式的可执行文件

bin文件通常是一种简单的二进制格式,它通常只包含了程序的机器代码和数据,而没有elf文件那么多的元数据。bin文件通常用在嵌入式系统或者引导加载程序等,这些环境中可能没有操作系统来解析elf文件的元数据。bin文件可以被直接加载到内存中并执行,但是它们不能被轻易的调试或反向工程。

转换 elf 文件到 bin文件,通常可以使用 objcopy 这个工具,如下命令:

objcopy -O binary input.elf output.bin

在这个命令中,-O binary 指定了输出文件的格式为 binary,input.elf 是输入的 elf文件,output.bin 是输出的 bin文件。

Linux下可以使用下面命令查看:

hexdump -C *.bin 

1.3.1 elf 文件到 .image 文件

GCC 编译之后会先生成 xxx.elf,然后再通过 arm-none-eabi-objcopy 加上相应的参数生成 xxx.bin, 最后再通过mkimage 工具对 xxx.bin 添加 header 生成 xxx.img

1.4 map 文件

在使用GCC编译链接程序时,可以使用 -Wl, -Map, output.map 选项来生成一个名为 output.map 的链接映射文件(Map文件)。Map文件包含了编译链接后的程序中各个模块在内存中的布局信息:

  • 模块的地址分配;
  • 各个函数在程序中的地址;
  • 全局变量的地址等。

该文件对于调试程序、分析程序的内存使用很有帮助。

例如,你可以使用以下命令来生成一个Map文件:

gcc -o output source.c -Wl,-Map,output.map

在这个命令中,-Wl,-Map,output.map 选项告诉GCC生成一个名为output.map的Map文件。output 是最终生成的可执行文件,source.c 是源代码文件。

生成的Map文件中,主要包含以下几个部分:

  • 头文件列表(Header File List):列出了参与编译的所有头文件。

  • 文件成员列表(File Members List):列出了参与链接的所有目标文件(Object Files)。

  • 段列表(Sections List):列出了程序中的所有段(Sections),如.text、.data、.bss等。

  • 符号列表(Symbols List):列出了程序中的所有全局符号(如函数和全局变量),以及它们在内存中的地址。

注意,Map文件中的信息可能会暴露程序的一些内部细节,因此在发布软件时,通常不会包含Map文件。

上篇文章:ARM 嵌入式编译系列 1 – GNU/GCC/GDB/GNU binutils介绍
下篇文章:ARM 嵌入式 编译系列 2.1 – GCC 编译参数学习

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 交叉编译工具arm-linux-gcc-3.4.1.tar.bz2是一个用于在x86架构的计算机上编译生成运行在ARM架构处理器上的软件的工具。ARM处理器通常用于嵌入式系统和移动设备。 这个工具是一个tar.bz2格式的压缩文件,需要通过解压缩来获取其中的文件。一般的解压缩软件如tar和bzip2可以用来解压这个文件。解压缩后,我们可以得到一个目录,其中包含了交叉编译工具链的各个组件。 这个工具中最关键的组件是arm-linux-gcc,它是一款ARM架构的C编译器。它允许我们在x86架构的计算机上编译ARM平台的C语言源代码,并生成适用于ARM处理器的可执行程序。除了C语言,arm-linux-gcc还支持C++和其他一些常用的编程语言。 使用交叉编译工具arm-linux-gcc,我们可以在开发软件时将代码编译ARM平台可执行文件,而不需要在ARM设备上进行开发和编译。这样可以提高开发效率并简化调试过程。开发人员可以直接在自己的PC上编写和测试代码,然后使用交叉编译工具生成ARM平台可执行文件,再将其上传到ARM设备上运行。 总之,交叉编译工具arm-linux-gcc-3.4.1.tar.bz2是一个用于在x86架构计算机上编译ARM平台可执行文件的工具链,它提供了一系列的工具和组件,其中最重要的是arm-linux-gcc编译器。使用这个工具,开发人员可以在PC上进行ARM开发和调试,提高开发效率并简化部署过程。 ### 回答2: arm-linux-gcc-3.4.1.tar.bz2是一种交叉编译工具。交叉编译是指在一种操作系统上编译运行在另一种操作系统中运行的程序。 arm-linux-gcc-3.4.1.tar.bz2是专门为ARM架构设计的编译工具。ARM架构是一种广泛应用于嵌入式设备中的处理器架构。由于ARM处理器具有低功耗、低成本和高性能的特点,因此在移动设备、智能家居、工业自动化等领域得到广泛应用。 arm-linux-gcc-3.4.1.tar.bz2是GNU Compiler Collection(GCC)的一个特定版本。GCC是一种开源的编译器套件,支持多种编程语言,包括C、C++和Fortran等。通过使用arm-linux-gcc-3.4.1.tar.bz2,开发人员可以在主机操作系统(通常是x86架构)上编译适用于ARM处理器的程序。 交叉编译工具arm-linux-gcc-3.4.1.tar.bz2使用.tar.bz2的压缩格式打包。用户需要先解压缩该文件,然后根据安装指南进行安装和配置。安装成功后,用户可以使用该工具链进行ARM架构的程序开发和编译。 在交叉编译过程中,需要设置正确的目标架构和其他相关参数,以确保生成的可执行文件可以在ARM设备上正确运行。交叉编译工具可以生成与目标设备兼容的二进制代码,并处理与特定硬件平台相关的问题,如指令集、内存管理等。 通过使用arm-linux-gcc-3.4.1.tar.bz2,开发人员可以更加方便地进行ARM设备上的软件开发。这个工具链为ARM平台上的开发者提供了编译链接和调试等必要的工具。它有助于简化开发流程,提高开发效率,并确保生成的程序在ARM设备上的正确运行。 ### 回答3: 交叉编译工具arm-linux-gcc-3.4.1.tar.bz2 是一个用于ARM架构的交叉编译工具。交叉编译是指在一种平台上开发、编译和生成另一种平台上可执行的程序。ARM是一种广泛应用于嵌入式设备的处理器架构,通过使用交叉编译工具,开发者可以在PC机上编写并编译ARM架构的程序。 arm-linux-gcc-3.4.1.tar.bz2 是一个tar压缩和bzip2压缩的文件。tar是一种文件打包的格式,bzip2是一种压缩格式。因此,首先需要将该文件解压缩。可以使用tar和bzip2命令来进行解压缩操作。 解压缩后,可以得到一个目录,里面包含了arm-linux-gcc-3.4.1工具链的文件。工具链是一组可以在一台计算机上生成可在另一种架构上运行的程序的工具。 在使用交叉编译工具之前,还需要将工具链的路径添加到系统的环境变量中,这样系统才能够找到正确的工具链。 使用arm-linux-gcc-3.4.1工具链可以在PC机上编写ARM架构的程序,并通过交叉编译生成可在ARM设备上运行的可执行程序。通过交叉编译,开发者可以更方便地开发和调试ARM设备的程序,同时提高了开发效率。 总之,arm-linux-gcc-3.4.1.tar.bz2 是一个交叉编译工具,通过解压缩该文件并配置环境变量后,开发者可以在PC机上编写并编译ARM架构的程序。这样可以简化ARM设备的开发和调试过程,提高开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

主公CodingCos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值