Linux 之十九 编译工具链、.MAP 文件、.LST 文件

news2024/11/26 7:29:43

  .map 文件和 .lst 文件是嵌入式开发中最有用的俩调试辅助文件。现在主要从事 RISC-V 架构,开始与 GCC 打交道,今天就重点学习一下 GCC 的 .map 文件、.lst 文件,并辅助以 ARMCC 和 IAR 作为对比。

编译工具链

  .map 文件和 .lst 文件都是由编译工具链中相应的工具产生的。软件程序的编译过程由一系列的步骤完成,每一个步骤都有一个对应的工具。这些工具紧密地工作在一起,前一个工具的输出是后一个工具的输入,像一根链条一样,我们称这一系列工具为编译工具链。编译工具链主要包含 编译器等可执行程序标准库(常用函数通用实现) 两大部分。
在这里插入图片描述
  能独立提供编译工具链的厂家并不多,嵌入式平台则更少,主要就是 ARM、IAR、GNU、LLVM。其中,ARM、IAR 是收费的专用软件,其支持的架构有限,而 GNU 的 GCC 则是一款支持众多架构的开源编译套件;LLVM 则是后起之秀,同样也支持众多架构,目前用的不如 GCC 广泛!如下是常用编译器:
在这里插入图片描述
  第一代编程语言的是汇编语言,因此,第一代编译器是编译汇编语言的。后来,高级语言逐步流行,但是编译工具链中仍然保留了高级语言到汇编语言这一步骤。而原来的汇编语言的编译器被称为汇编器,高级语言的编译器则就称为编译器。除了编译器、链接器等,编译工具链中通常还会包含一些用来处理编译文件相关的辅助工具。例如,以 GCC 中的 objdumpreadelf 为代表的的用来处理对象文件的工具。

  至于标准库,绝大多数工具链都是提供一些预编译好的二进制文件(.o 文件),当我们编译自己的程序时,工具链自动以静态链接库的形式引入到我们的最终可执行程序中。通常,这些预编译的文件还会被打包成 存档文件(.a 文件) 来提供(编译工具链中有相应工具来解析执行存档文件,例如,GCC 中的 ar)。

  要编译出最终的可执行程序,通常需要编译、链接、转换这三个阶段。其中,编译即编译器将源码翻译成对象文件,链接即链接器将各个对象文件组合成最终可执行程序。现代编译器通常产生一个通用格式(通常是带有调试信息)的最终可执行程序(ELF 文件),然后使用相应的工具从中提取出实际的纯可执行程序。
在这里插入图片描述

  1. ELF 文件参见博文 Linux 之二十 详解 ELF 文件
  2. 链接脚本文件见独立博文 Linux 之二十一 链接脚本文件 GCC 的.ld、ARMCC 的 .sct、IAR 的 .icf

  有个问题需要注意,GCC 中的 gcc 实际是一个包装器,其会根据输入文件调用实际的编译器,链接器。我们通过相应的命令就可以打断这个流程,例如,-c 选项表示不运行链接器!

  具体到编译器,其编译过程通常也是分为多个阶段的。在编译原理这门课程中,我们学过三段式编译器架构,其在编译时要依次经过词法分析、句法分析、语义分析、中间代码生成、代码优化、代码生成 六大阶段。
在这里插入图片描述
  在编译工具链中,构建编译工具链使用的平台编译出的编译工具链运行的平台使用编译出的编译工具链编译出的程序运行的平台三者可以完全不同。其中关键的一步是设置 configure 的参数,该命令有三个参数 --build--host--target 非常重要,下图是 Windows 上的 MinGW 编译器配置信息:
在这里插入图片描述

  • --build:这个参数指出了构建编译工具链使用的平台。如果我们不显示指定这个参数的值,那么这个参数的值就会由 config.guess 自动识别。
  • --host:这个参数指出了编译出的编译工具链运行的平台。这个参数的值一般就等于 --build 的值。
  • --target:这个参数指出了使用编译出的编译工具链编译出的程序运行的平台。

  通常,本地编译工具链一般就是指的 --build = --host = --target 的情况,交叉编译工具链一般是--build = --host--target 的情况。不过,基本很少出现--build--host 的情况。

本地编译工具链

  在当前平台(例如 x86 架构的 PC)下,直接编译出来程序(或者库文件),其可以直接在当前的平台运行(或使用)。这个过程就叫做本地编译,使用的编译工具叫做本地编译工具链(简称编译工具链)。例如 PC 上的 VCGCCLLVMTCC 等。

交叉编译工具链

  在当前平台下(例如 x86 架构的 PC)下,直接编译出来程序(或者库文件),其不可以直接在当前的平台运行(或使用),必须放到目标平台上(例如 ARM)才可以运行(或使用),这个过程就叫做交叉编译,使用的编译工具叫做交叉编译工具链。例如 PC 中的 armcciar特定架构的 GCC特定架构的 LLVM 等。

  交叉编译工具链又可以根据是否支持 Linux 系统分为 裸机程序交叉编译工具链Linux 程序交叉编译工具链 这两大类。我们上面的举例中,armcciar 都属于裸机交叉编译工具链;而特定架构的 GCC特定架构的 LLVM 则根据需要可以支持 Linux 系统,也可以不支持 Linux 系统,因此它既有裸机程序交叉编译工具链,也有 Linux 程序交叉编译工具链。

  1. 裸机程序交叉编译工具链不能编译 Linux 应用程序,但是,可以用于编译一些嵌入式实时操作系统(FreeRTOS、RT-Thread 等)
  2. Linux 程序交叉编译工具链不止可以编译 linux 应用程序,也可以编译裸机程序

The xPack Project

  The xPack Project 是一个开源项目,其提供了一些列开发工具(重点是裸机下的 C/C++ 相关的)在不同平台的下的构建实例,其中就包含各平台的 GCC 交叉编译工具链,它使用一个多版本依赖管理器来管理各个实例。
在这里插入图片描述
  实际开发中,我们经常会独立使用它提供的某些工具。例如,Eclipse 的嵌入式 C/C++ 插件 Eclipse Embedded CDT 就包含一些 xPack 提供的工具,以此来实现创建、构建、调试和管理 Arm 和 RISC-V 项目。

  • xPack Windows Build Tools:包括在 Windows 上执行构建所需的额外工具( makerm 等)

  • xPack GNU Arm Embedded GCC:ARM 维护的官方 GNU ARM 嵌入工具链的一个代替,可以用于 Windows,MacOS和 GNU/Linux 平台。

  • xPack GNU RISC-V Embedded GCC:裸机 RISC-V GCC 发行版,由SiFive 维护。Windows、macOS 和 GNU/Linux 都有可用的二进制文件。

  • xPack OpenOCD:OpenOCD 的一个新发行版,为更好/更方便地与 OpenOCD 调试插件集成而定制。Windows、macOS 和GNU/Linux 都有可用的二进制文件。

  • xPack QEMU Arm:QEMU(开源机器仿真器)的一个分支,旨在为 Eclipse Embedded CDT 中 的Cortex-M 仿真提供支持。Windows、macOS 和 GNU/Linux都有可用的二进制文件。

.map 文件

  .map 文件对应的中文名应该是映射文件,用来展示(映射)项目构建的链接阶段的细节。通常包含程序的全局符号、交叉引用和内存映射等等信息。目前,常见的编译器套件(实际是其中的链接器),例如, GCC、ARMCC、IAR 都可以生成 .map 文件。

  MAP 文件是一个与链接脚本文件密切相关的文件,其内容取决于链接脚本文件,链接脚本文件的详细介绍见独立博文 Linux 之二十一 链接脚本文件 GCC 的.ld、ARMCC 的 .sct、IAR 的 .icf。

GCC

  GCC 编译工具链中的链接器、汇编器、objdump 等工具都位于 GNU Binutils 中,他们的相关文档可以直接在官网下载。相比于 ARMCC 和 IAR,GCC 的 MAP 文件中的内容比较少!

产生方式

  在 GCC 中,MAP 文件就是由链接器 ld 通过使用命令 -Map=mapfile 来输出 map 文件。需要注意,如果同时使用了 --print-map 则会只将 MAP 内容输出到编译窗口,而不会生成 MAP 文件。
在这里插入图片描述
  需要注意的是,如果使用了编译器 gcc 作为入口(通常都是这么做,不会直接调用链接器),则需要使用 -Wl,-Map,FILE 的方式来将参数传递给链接器。编译器参数 -Wl 是专门用来传递参数给链接器的。同样,如果使用了 -Xlinker --print-map 则只会将 MAP 信息输出到编译窗口,而不会再生成 MAP 文件!
在这里插入图片描述
  在实际开发中,ECLIPSE 的相关配置如下所示。目前没有该明白,为何它要以 g++ 作为链接器的入口!
在这里插入图片描述

内容介绍

  在理解内容之前,有必要先了解一下工具链提供的存档文件(Archive File)。前面说过,工具链提供了 lib 这一部分, lib 中的各个函数的实现是已经进行了预编译的,并且把预编译的各种 .o 文件打包成为存档文件(.a 文件)。编译单元即一个 .o 文件。

GCC 的 MAP 文件相比于 ARMCC 和 IAR 内容少了很多

存档文件引用关系

  MAP 文件的第一部分内容列出了我们项目中所使用的标准库中提供的函数的基本调用情况,基本格式如下:

存档文件 (编译单元)
    			调用存档文件中接口的文件(调用的符号)

  如下图所示的示例,表示 crt0.o 中正在调用 exit 这个接口,而 exit 位于 lib_a-exit.o 这个文件中,而 lib_a-exit.o 这个文件存在于 libg.a 这个存档文件中!
在这里插入图片描述

丢弃的输入段

  MAP 文件的第二部分内容列出了链接器在生成最终可执行文件时丢弃的输入段,每行一个,四列的含义从左到右依次为节区名、地址、节区大小、节区所在的编译单元。注意,如果节区位于存档文件中,则最后一列是存档文件 + (编译单元)。
在这里插入图片描述

内存配置

  MAP 文件的第三部分内容列出了我们的内存(存储)配置情况,每行一个,四列的含义从左到右依次为存储的名字、起始地址、大小(字节)、属性(r:读、x:执行、w:写)
在这里插入图片描述

链接脚本和内存映射

  关于链接脚本我们后面在详细介绍,这部分链接脚本就是一些 MRI 兼容的链接脚本命令,简单来说,使用 MRI 兼容的链接脚本命令引入一些对象文件(.o)。 MRI 兼容的链接脚本命令是用于早期链接器的,在 ld 手册中有说明,现在存在的唯一的目的就是兼容!
在这里插入图片描述
  这部分最有用的是紧随其后的内存映射,这部分列出了所有符号在内存(存储)中的物理地址,这部分就是在辅助调试时最常用的!
在这里插入图片描述

ARM

产生方式

  参见博文 ARM 之十 ARMCC(Keil) map 文件(映射文件)详解。

内容介绍

  参见博文 ARM 之十 ARMCC(Keil) map 文件(映射文件)详解。

IAR

产生方式

  由链接器参数 --map 来产生。当启用 MAP 文件后,链接器支持的其他一些参数的输出就会输出到 MAP 文件中。
暂无

内容介绍

  暂无,后续有需要再补充!

.lst 文件

  .lst 文件全称是 Assembler list file,主要用来存储汇编程序列表数据,它通常会拥有比 .map 文件更详细的信息。借助 .lst 文件,同时通过查看栈帧结构(可以通过查看相应的手册来确定栈帧的组成),通过在 .lst 文件中查找 lr 的地址所在的位置,就能立刻定位到问题。

GCC

  GCC 编译工具链中的链接器、汇编器、objdump 等工具都位于 GNU Binutils 中,他们的相关文档可以直接在官网下载。

产生方式

  .lst 文件通常是由汇编器产生的,对于 GCC 的汇编器 as,通过使用命令 -a[cdghlmns]=[FILE] 来输出 lst 文件。但需要注意的是,-a[cdghlmns]=[FILE] 参数是独立使用汇编器 as 的时候才生效的。
在这里插入图片描述
  与上面说的 MAP 文件产生一样,如果使用了编译器 gcc 作为入口(通常都是这么做,不会直接调用汇编器),则需要使用 -Wa,-a,FILE 的方式来将参数传递给汇编器。编译器参数 -Wa 是专门用来传递参数给汇编器的。
在这里插入图片描述
  在实际开发中,我们经常写 -Wa,-adhlns="$@.lst",这样,每编译一个源文件就会产生一个对应的 .lst 文件。需要注意的是,如果是高级语言文件(例如 C 语言),我们需要配置编译器的参数,不要以为仅仅配置汇编器 as 就行(在多数工具中编译器和汇编器是独立配置的)!
在这里插入图片描述
  注意:在 ECLIPSE 中,它把 objdump 输出文件名也定为了 .lstobjdump 实际是解析 ELF 文件的工具,与 LIST 文件本没啥关系。 在 ECLIPSE 中,通过如下配置就会默认启用命令 objdump --source --all-headers --demangle --line-numbers --wide "xxx.elf" > "xxx.lst" 来生成最终调试文件对应的 lst 文件,以此来辅助调试。
在这里插入图片描述

内容介绍

  在实际开发中,汇编器 as 产生的 LST 文件基本很少使用,使用最多的是使用 objdump 工具产生的最终调试程序对应的 LST 文件。这里我们主要就介绍 objdump 产生的 LST 文件。上面说过了, objdump 输出的实际是 ELF 文件内容,详细介绍见独立博文 Linux 之二十 详解 ELF 文件。

–source、–demangle、 --line-numbers、–wide

  就是将反汇编与 C 源码混合在一起显示出来。并且尽可能的翻译成人能看懂的代码(翻译符号名、对应行号)!

–all-headers

  该命令会输出 Program Header,Sections 以及 SYMBOL TABLE 这个三部分的内容。编译工具产生的最终可执行文件是符合 ELF 规范的二进制文件,这里的输出内容其实都是 ELF 文件的内容,关于 ELF 文件,可以参考 ARM 之一 ELF 文件、镜像(Image)文件、可执行文件、对象文件 详解。

  • Program Header:这个就是 ELF 文件的程序头
    在这里插入图片描述
  • Sections: 这个就是从 ELF 文件中的提取的节区信息,共由 8 列组成,每列的含义说明如下:
    在这里插入图片描述
    • 第一列(Idx):从 0 开始的索引号
    • 第二列(Name): 节的名字
    • 第三列(Size):节的大小(字节)
    • 第四列(VMA):Virtual Memory Address 的缩写,表示该节在运行时的地址
    • 第五列(LMA):Load Memory Address 的缩写,表示该节的加载地址
    • 第六列(File off):该节在文件中的偏移
    • 第七列(Algn):对齐字节数,只能是 2 的正整数次幂,由于纯文本没办法显示幂,这里使用 ** 表示!
    • 第八列(Flags):该节的属性标志
  • SYMBOL TABLE:这个就是从 ELF 文件中的提取的符号表,由 5 列组成,每列的含义说明如下:
    在这里插入图片描述
    • 第一列:符号的值,通常就是符号的物理地址
    • 第二列:这是一组符号标识,共由 7 个标识符组成,某些标识符可以是空格。
      • 第一个标识符:取值如下
        • l : local Symbol
        • g: Global Symbol
        • u: Unique global Symbol
        • ! :其他情况
      • 第二个标识符:取值为 w 表示弱符号(Weak),否则为空格表示强符号(Strong)
      • 第三个标识符:取值为 C 表示构造函数(Constructor ),否则为空格表示普通符号
      • 第四个标识符:取值为 W 表示警告符号(Warning),否则为空格表示普通符号。警告符号的名称是一条消息,当警告符号后面的符号被引用时显示出来。
      • 第五个标识符:
        • I: 该符号是对另一个符号的间接引用
        • i: 在 reloc 处理期间计算的函数
        • :空格表示普通符号
      • 第六个标识符:
        • d: 调试符号
        • D`: 动态符号
        • :空格表示普通符号
      • 第七个标识符:
        • F : 符号是函数的名称(Function )
        • f: 一个文件(file)
        • O: 一个对象(Object)
        • :空格表示普通符号
    • 第三列:符号对应的节区。如果该节是绝对的(即没有与任何节连接),则是 *ABS*,如果该节在被转储的文件中被引用,但在那里没有定义,则是 *UND*
    • 第四列:对于普通符号是对齐方式,对于其他符号则是大小
    • 第五列:符号名字

ARM

产生方式

  使用编译器 armcc 的参数 -asm 以及汇编器 armasm的参数 --list=file 来输出 lst 文件,两者分别针对 C 语言源文件和汇编源文件生效!
在这里插入图片描述

内容介绍

  暂无,后续有需要再补充!

IAR

产生方式

  使用编译器 iccarm 的参数 -l 以及使用汇编器 iasmarm 的参数 -L 来输出 lst 文件,两者分别针对 C 语言源文件和汇编源文件生效!
在这里插入图片描述

内容介绍

  暂无,后续有需要再补充!

参考

  1. https://dzone.com/articles/creating-disassembly-listings-with-gnu-tools-and-e
  2. https://interrupt.memfault.com/blog/get-the-most-out-of-the-linker-map-file
  3. https://sourceware.org/binutils/docs-2.40/binutils.html#index-objdump

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/477883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】第十三站:排序性质

文章目录 一、文件外与文件内排序二、非比较排序之计数排序1.绝对映射2.相对映射3.代码实现 三、排序的稳定性 一、文件外与文件内排序 如下图所示是我们常见的的排序算法,也是我们已经使用代码实现过的 上面这七种排序算法我们都可以称之为文件内排序。但是归并排…

Fetch

Fetch 也是前后端通信的一种方式。是 Ajax 的一种替代方案。 Fetch 的优缺点: Fetch 的优点: 原生就有 fetch 对象,使用简单。基于 Promise。 Fetch 的缺点: 兼容性没有 Ajax 好。原生没有提供 abort、timeout等机制。 fetc…

【笔记】cuda大师班7-11 索引

一. block,grid 的 idx & dim 注意区分threadIdx,blockIdx 1.1 blockIdx 每一个线程在cuda运行时唯一初始化的blockIdx变量只取决于所属的坐标,blockIdx同样也是dim3类型 1.1. 对比blockIdx和threadIdx blockIdx只取决于当前block在…

786. 第k个数(C++和Python3)——2023.4.30打卡

文章目录 QuestionIdeasCode Question 给定一个长度为 n 的整数数列,以及一个整数 k ,请用快速选择算法求出数列从小到大排序后的第 k 个数。 输入格式 第一行包含两个整数 n 和 k 。 第二行包含 n 个整数(所有整数均在 1∼109 范围内&…

每天一道算法练习题--Day16 第一章 --算法专题 --- ----------哈夫曼编码和游程编码

Huffman encode(哈夫曼编码) Huffman 编码的基本思想就是用短的编码表示出现频率高的字符,用长的编码来表示出现频率低的字符,这使得编码之后的字符串的平均长度、长度的期望值降低,从而实现压缩的目的。 因此 Huffman 编码被广泛地应用于无…

Vue——自定义指令

目录 介绍​ 指令钩子​ 简化形式​ 对象字面量​ 在组件上使用​ 介绍​ 除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。 我们已经介绍了两种在 Vue 中重用代码的方式:组件和组合…

【Android入门到项目实战-- 7.3】—— 如何调用手机摄像头和相册

目录 一、调用摄像头拍照 二、打开相册选择照片 学完本篇文章可以收获如何调用手机的摄像头和打开手机相册选择图片功能。 一、调用摄像头拍照 先新建一个CameraAlbumTest项目。 修改activity_main.xml,代码如下: 按钮打开摄像头,ImageView将拍到的…

一文打尽目标检测NMS(1): 精度提升篇

文章来自于:曲終人不散丶知乎, 连接:https://zhuanlan.zhihu.com/p/151914931, 本文仅用于学术分享,如有侵权,前联系后台做删文处理。 众所周知,非极大值抑制NMS是目标检测常用的后处理算法&…

黑客如何在攻击中使用生成式人工智能以及我们能做些什么?

生成式人工智能 (AI) 最近备受关注。AI 驱动的聊天机器人 ChatGPT 和 VALL-E 等其他支持自然语言处理的系统已将生成 AI 带给了公众,并释放了它的好处和坏处。 关于生成式 AI 的核心担忧之一是它可用于升级恶意攻击并提出更复杂的网络攻击。 那么,黑客…

简单有趣的轻量级网络 Shufflenet v1 、Shufflenet v2(网络结构详解+详细注释代码+核心思想讲解)——pytorch实现

这期博客咱们来学习一下Shufflenet系列轻量级卷积神经网络,Shufflenet v1 、Shufflenet v2。 首先学习一下,Shufflenet v1网络: 论文下载链接: Shufflene系列轻量级卷积神经网络由旷世提出,也是非常有趣的轻量级卷积神经网络,它提出了通道混合的概念,改善了分组卷积存…

IPsec中IKE与ISAKMP过程分析(主模式-消息3)

IPsec中IKE与ISAKMP过程分析(主模式-消息1)_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析(主模式-消息2)_搞搞搞高傲的博客-CSDN博客 阶段目标过程消息IKE第一阶段建立一个ISAKMP SA实现通信双发的身份鉴别和密钥交换&…

【Java笔试强训 15】

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥查找输入…

Vue中 引入使用 patch-package 为依赖打补丁 (以修改 vue-pdf 打包后 [hash].worker.js 路径问题为例)

1. patch-package 简介 patch-package npm地址 patch-package github文档 npm i patch-package如果不需要在生产中运行 npm (如:正在制作 web 前端,则可使用 --save dev) 1.2 使用方法 制作修补程序 首先更改 node_modules 文件夹中特定包…

大数据之Spark集群角色

文章目录 前言一、Spark集群角色介绍(一)Spark集群简介(二)集群角色介绍 总结 前言 #博学谷IT学习技术支持# 上篇文章主要介绍了Spark的运行流程,可以通过链接复习以加深印象:Spark运行流程,本…

redis面试重点------源于黑马

缓存问题三兄弟 是因为不同的原因让请求全部打到了数据库而造成的问题 什么是缓存穿透? 缓存穿透是指查询一个数据,在redis和MySQL中都不存在。也就是查询一个数据不存在的数据,导致每次请求都会到达数据库,给数据造成很大的压力…

如何选择最适合你的商城小程序开发公司

随着电子商务的快速发展,越来越多的企业开始认识到商城小程序的重要性。作为一个准备开发商城小程序的企业,你一定会面临一个重要的问题:商城小程序开发哪家好?如何选择最适合你的商城小程序开发公司? 在选择商城小程…

【Java笔试强训 17】

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥杨辉三角…

趣说数据结构 —— 3.线性表中的循环链表与双向链表

本节介绍线性表中的循环链表与双向链表,主要包括基本结构,主要特点以及适用场景三部分内容。 3.1 循环链表与双向链表 循环链表(Circular Linked List) 是另一种形式的链式存储结构。其特点是表中 最后一个结点的指针域指向头结…

sklearn.metrics 中的f1-score介绍

1 f1_score,averagebinary, macro, micro, weighted F1得分可以解释为精确度和召回率的调和平均值,其中F1得分达到其最佳值为1,最差得分为0。精确度和召回率对F1得分的相对贡献相等。F1得分的公式为: 在多类别和多标签的情况下,这…

4.30学习周报

文章目录 前言文献阅读摘要简介数据源和预处理理论基础与模型构建结果和讨论结论和未来工作 时间序列预测总结 前言 本周阅读文献《Water Quality Prediction Based on LSTM and Attention Mechanism: A Case Study of the Burnett River, Australia》,文献主要提出…