【ARM 嵌入式编译系列 1 -- GNU/GCC/GDB/GNU binutils介绍】

本文介绍了GNU项目及其编译器GCC,包括GCC的多语言支持和与binutils工具集的协同工作。重点讨论了ARM架构下的GCC交叉编译器,如arm-none-eabi-gcc,以及EABI在嵌入式系统中的作用。此外,还讲解了binutils中的objdump、readelf和addr2line等工具在调试和分析中的应用。
摘要由CSDN通过智能技术生成


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


下篇文章:ARM 嵌入式 编译系列 2 – GCC 编译过程介绍

1.1 GNU 介绍

GNU(GNU’s Not Unix)是一个自由的操作系统,也是一个大量集成软件的集合。这个项目由Richard Stallman在1983年9月27日公布,并在1984年1月创立了自由软件基金会(Free Software Foundation)来支持该项目。GNU的目标是给用户创造一个完全自由的Unix-like的操作系统。

GNU的哲学观念是"软件应该是自由的",因此,所有的GNU软件都遵循一种名叫 "GNU 通用公共许可证"(GNU General Public License,简称GNU GPL)的协议。GNU GPL 是一种自由软件许可证,允许软件自由地被复制,分发和修改。

GNU项目包含了一个完整的操作系统的所有要素,包括内核,所有的设备驱动,所有的基本的系统工具和所有的基本的桌面环境。此外,GNU还包含了各种应用软件,包括文本编辑器,网页服务器,电子邮件客户端,编程工具和许多其他工具。

GNU操作系统的内核是GNU Hurd。Hurd是一个由微内核(如Mach)加上一系列用户空间服务/守护进程组成的操作系统内核。然而,由于Hurd开发速度缓慢,许多基于GNU工具和应用程序的系统(如流行的Linux发行版)选择使用Linux内核。

GNU项目是开源和自由软件运动的重要组成部分,对当今计算机软件领域产生了深远影响。

1.1.1 GNU与编译器

GNU 编译器套件(GNU Compiler Collection,简称GCC)是GNU项目的一个重要部分,它是一个支持多种编程语言的开源编译器集合,包括C,C++,Objective-C,Fortran,Ada,Go,以及D等等。

最初,GCC仅仅是GNU C编译器的缩写,因为当时只支持C语言。随着项目的发展,GCC开始支持更多的编程语言,于是它的全称也被更改为GNU编译器套件

GCC不仅可以在GNU操作系统上运行,也可以在大多数UNIX类系统以及Microsoft Windows等平台上运行。GCC是自由软件,任何人都可以自由地使用、复制、研究,和修改并发布这个软件。

GCC的另一个特点是跨平台。开发者可以在一个平台上开发GCC,然后用它来为另一个平台编译代码。例如,可以在Linux平台上使用GCC编译出运行在 ARM 平台上的程序。

GCC在全球范围内的使用非常广泛,尤其是在开源和自由软件社区中。许多现代软件,包括Linux内核,都是用GCC编译的。

1.1.2 GCC 编译器种类

GCC 编译器支持多种编程语言,包括:

  • gcc:GNU C编译器,用于编译C语言代码。
  • g++:GNU C++编译器,用于编译C++语言代码。
  • gfortran:GNU Fortran编译器,用于编译Fortran语言代码。
  • gcj:GNU Compiler for Java,用于编译Java语言代码。
  • gobjc:GNU Objective-C编译器,用于编译Objective-C语言代码。
  • gnucobol:GNU COBOL编译器,用于编译COBOL语言代码。
  • gdc:GNU D编译器,用于编译D语言代码。
  • ghdl:GNU VHDL编译器,用于编译VHDL语言代码。
  • gnat:GNU Ada编译器,用于编译Ada语言代码。
  • go:GNU Go编译器,用于编译Go语言代码。

这么多种类的编译器使得GCC能够满足几乎所有主流编程语言的编译需求。

1.1.3 GNU binutils

GNU binutils是一套由GNU项目提供的编程工具集合。这包括了很多用于处理二进制文件的工具,例如链接器和二进制工具。以下是一些主要的组件:

  • ld:这是GNU链接器,用来将编译生成的目标文件链接成可执行文件。
  • as:这是GNU汇编器,用来将汇编代码转换为目标文件。
  • objdump:这个工具可以显示二进制文件的信息,例如它的段信息,符号表等。它也可以将二进制文件反汇编。
  • nm:这个工具可以列出目标文件的符号表。
  • size:这个工具可以显示目标文件或者可执行文件的节区大小。
  • strings:这个工具用来从二进制文件中提取字符串。
  • ar:这个工具用来创建,修改以及提取静态库。
  • strip:这个工具可以从目标文件或可执行文件中删除符号信息,以减小文件大小。
  • readelf:这个工具用来显示ELF格式文件的信息。
  • addr2line:这个工具用来将程序计数器值转化为文件名,函数名和行号,常用于程序崩溃时的调试。

这些工具在编程中具有广泛的用途,例如链接、调试、性能分析等等。

如下以arm 交叉编译工具链为例进行介绍:

gcc-arm-none-eabi/bin 目录包含了 GNU 工具链的所有可执行文件。该工具链主要用于编译 ARM 架构的嵌入式系统的代码。名字 gcc-arm-none-eabi 表示该工具链使用 GCC 编译器,目标架构是 ARM,没有指定操作系统(none),并且使用标准的 ABI(Application Binary Interface)。

在这个 bin 目录中,你会找到以下一些重要的工具:
arm-none-eabi-gcc: ARM 版本的 GCC 编译器,用于将源代码编译成目标代码;
arm-none-eabi-g++: ARM 版本的 G++ 编译器,用于编译 C++ 代码;
arm-none-eabi-as: ARM 版本的 GNU 汇编器,用于将汇编代码转换成目标代码;
arm-none-eabi-ld: ARM 版本的 GNU 链接器,用于将多个目标文件链接成一个可执行文件;
arm-none-eabi-ar: ARM 版本的 GNU 归档程序,用于创建、修改和提取归档文件;
arm-none-eabi-objdump: ARM 版本的 GNU objdump 工具,用于显示目标文件的信息;
arm-none-eabi-objcopy: ARM 版本的 GNU objcopy 工具,用于复制和转换目标文件;
arm-none-eabi-readelf: ARM 版本的 GNU readelf 工具,用于显示 ELF 格式文件的信息;
arm-none-eabi-nm: ARM 版本的 GNU nm 工具,用于显示目标文件的符号表信息;
arm-none-eabi-gdb: ARM 版本的 GNU 调试器。

这个目录中可能还会包含其他的工具和脚本,具体内容可能会因为 GCC 版本和工具链的配置选项而有所不同。

~/workbase/codingcose/tools/toolchains/gcc-arm-none-eabi/bin> ls
arm-none-eabi-addr2line  arm-none-eabi-elfedit     arm-none-eabi-gcc-ranlib     arm-none-eabi-gdb-add-index-py  arm-none-eabi-nm       arm-none-eabi-strings
arm-none-eabi-ar         arm-none-eabi-g++         arm-none-eabi-gcov           arm-none-eabi-gdb-py            arm-none-eabi-objcopy  arm-none-eabi-strip
arm-none-eabi-as         arm-none-eabi-gcc         arm-none-eabi-gcov-dump      arm-none-eabi-gprof             arm-none-eabi-objdump
arm-none-eabi-c++        arm-none-eabi-gcc-10.2.1  arm-none-eabi-gcov-tool      arm-none-eabi-ld                arm-none-eabi-ranlib
arm-none-eabi-c++filt    arm-none-eabi-gcc-ar      arm-none-eabi-gdb            arm-none-eabi-ld.bfd            arm-none-eabi-readelf
arm-none-eabi-cpp        arm-none-eabi-gcc-nm      arm-none-eabi-gdb-add-index  arm-none-eabi-lto-dump          arm-none-eabi-size

1.1.4 GNU binutils和GCC

GCC是 GNU 编译器集合,包含了各种语言的编译器,如C、C++、Fortran等。在编译源代码文件的时候,GCC首先会把源代码转换成汇编代码,然后调用 GNU binutils 中的 b工具将汇编代码转换为目标文件。

当有多个目标文件需要链接成一个可执行文件时,GCC会调用GNU binutils中的 ld工具进行链接。

此外,GNU binutils中的其他工具,如nm、objdump、readelf等,也经常被用于程序调试和性能分析,这些工作通常和GCC编译的程序密切相关。

1.1.5 GCC 与 GDB 关系

GCCGDB 都是GNU项目的一部分,是开源软件的代表作,它们都在开发和调试程序中发挥作用。

GCC(GNU 编译器套装)是一个支持多种编程语言(如C、C++、Java、Fortran等)的编译器,它的职责是将源代码编译成机器语言的代码,生成可执行文件。

GDB(GNU 调试器)是一个强大的源码级调试工具,它可以在程序执行时进行观察和控制,比如设置断点、单步执行代码、查看变量值等,以帮助开发人员找到和修复程序的错误。

GCC和GDB的关系在于:GCC生成的可执行文件可以被GDB进行调试。GCC在编译时如果使用 -g选项,可以在生成的可执行文件中包含额外的调试信息,这会使GDB的调试功能更强大,例如能够显示源代码行号、变量名等信息。

1.1.6 GDB 简单使用介绍

GDB是一个功能强大的调试器,可用于调试C、C++和其他编程语言的程序。下面是一些常用的GDB命令及其使用示例:

启动GDB调试器

  • gdb <可执行文件>

设置断点

  • 在指定行上设置断点:break <行号>
  • 在指定函数内设置断点:break <函数名>
  • 在指定文件和行号设置断点:break <文件名>:<行号>

运行程序

run

单步执行

  • 单步执行一行代码:next
  • 单步执行一条指令:step

查看变量的值

  • 查看全局变量:print <变量名>
  • 查看局部变量:print <函数名>::<变量名>

修改变量的值

set <变量名> = <新值>

查看堆栈信息

backtrace

跳转到指定的行号

jump <行号>

继续执行程序

continue

退出GDB调试器

quit

x(examine)命令:这个命令用于查看内存中的内容。语法格式为 “x/NFU 地址”。

  • N表示显示的单元数;
  • F表示显示方式;
  • U表示显示的单元长度。
    例如,x/4hb 0x12345678表示以16进制和字节为单位,显示地址0x12345678开始的四个单元的内容。

list命令:这个命令用于列出源代码。

  • list 行号”查看指定行号的源代码;
  • list 函数名”查看指定函数的源代码;
  • list”查看当前执行点附近的源代码。

display命令:这个命令用于设置自动显示的表达式。在每次暂停程序执行后,GDB会自动计算并显示这些表达式的值。例如,你可以使用“display 变量名”设置在每次停止后自动显示某个变量的值。

1.2 GCC ARM 编译器

GCC为ARM设计的交叉编译器主要有以下几种:
arm-none-eabi-gcc:这是ARM嵌入式系统最常用的交叉编译器。

  • "none"表示没有指定厂商;
  • "eabi"表示使用嵌入式ABI。

这种编译器主要用于裸机开发或RTOS。

arm-linux-gnueabi-gcc:这是ARM Linux系统的交叉编译器,主要用于开发Linux下的应用程序。

arm-linux-gnueabihf-gcc:这也是ARM Linux的交叉编译器,与arm-linux-gnueabi-gcc的区别在于,它默认启用了硬浮点支持。

使用 arm-none-eabi-gcc,开发者可以在一个平台(如PC)上编写和编译代码,生成可以在另一个平台(如ARM架构的嵌入式设备)上运行的程序。这种编译方式被称为交叉编译

1.2.1 EABI 介绍

EABI是 Embedded Application Binary Interface 的缩写,意为嵌入式应用二进制接口。它是用于嵌入式系统中的软件接口标准。

在GCC(GNU编译器集合)中,GCC为ARM提供了支持EABI的编译器。这种编译器可以生成满足EABI规范的二进制代码,这种代码可以在遵循EABI规范的系统上运行。

EABI规定了系统调用的规则、数据类型的大小和对齐方式、寄存器的使用规则等,以确保不同的编译器产生的二进制代码可以在同一个系统中共存和互操作。

总的来说,GCC EABI是指GCC编译器支持生成符合EABI规范的二进制代码。

1.2.2 反汇编 objdump

objdump 是 GNU binutils工具集中的工具,常常与GCC一起使用,以便对编译后的目标文件进行进一步的处理和分析。这个工具可以显示二进制文件的详细信息,包括其头部信息、节区信息、反汇编代码等。它通常用于分析目标文件或可执行文件的内部结构和代码。

arm-none-eabi-objdump -D *elf   > dump

1.2.3 符号表读取 readelf

可以通过下面命令读取函数地址及全局变量的地址

arm-none-eabi-readelf -s *.elf  >  dump

也可以通过 arm-none-eabi-nm 显示二进制目标文件的符号表,主要是一些函数和全局变量等,

局部变量 nm 看不到

1.2.4 指令地址2函数名 addr2line

这个工具可以将程序的地址转换为源代码中的文件名和行号。它通常用于调试或分析程序崩溃时的调用堆栈,以便找到出错的位置。

arm-none-eabi-addr2line -e *.elf -a addr -f
  • -a: 在函数名、文件名和行号信息之前,以十六进制形式显示地址;
  • -e: 指定需要转换地址的可执行文件名,通常为*.elf 文件;
  • -f: 在显示文件名、行号信息的同时显示函数名。

下篇文章:ARM 嵌入式 编译系列 2 – GCC 编译过程介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

主公讲 ARM

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

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

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

打赏作者

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

抵扣说明:

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

余额充值