重新理解Linux交叉编译及编译流程

2023-10-27

参考书籍
1、编译原理
2、嵌入式Linux应用开发

一、交叉编译背景

当我们开发目标是一个嵌入式设备时,便需要在PC机上编译出能在该嵌入式设备上运行的可执行文件,这里编译主机与目标运行主机不是同一个设备,那么该过程就称为交叉编译;而编译是指一个源代码文件(这里指的是编译性程序源文件,与之对应的是解释性程序),如C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和链接(linking)等4步才能变成可执行文件,注意在日常交流中通常使用“编译”统称这4个步骤。

当我们在 Windows下利用IDE工具,即集成开发环境(比如 Visual studio、keil、IAR、Eclipse等等)进行开发时,只需要单击几个按钮即可编译,因为IDE工具已经将各种编译工具的使用封装好了。

Linux下也有很优秀的集成开发工具,但是更多的时候是直接使用编译工具;比如嵌入式开发中,运行在PC平台上的编译工具链为gcc、ld、objcopy、objdump等,它们编译出来的程序在x86平台上运行。要编译出能在 ARM 平台上运行的程序,则须使用交叉编译工具 arm-linux-gcc、arm-linux-ld、arm-linux-objcopy、arm-linux-objdump等;PC与ARM的编译工具使用方法一致,单纯就是名字不一样。

小插曲:关于开发工具的使用,搭建开发环境和熟悉工具使用是进行开发的第一步,也是一道难关,尤其面对多种多样的工具和环境,让人抓狂;其实这也无可厚非,因为各种系统、产品本身具有自己的特点以及软件工具的限制(知识产权),显然要做到一个工具通吃是不现实的,而一般在学习网络教程/公司企业工作时所使用的工具,有可能会直接采用某官方发布的软件,也有可能经过二次开发/封装而来,面对这种情况,我们其实不用去抗拒,学习开发工具本身就是开发过程中必要的一部分,熟练掌握一套工具后,同类的工具上手也会很快的,因此要积极对待。

上图更好理解:
在这里插入图片描述

二、gcc和arm-linux-gcc的常用选项

1、查询gcc帮助

先来简单认识下编译工具的使用,我们先看操作,再看原理,以gcc为例子(与arm-linux-gcc使用一致),查询使用帮助:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sVGTABYv-1647098293080)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312211258526.png)]

2、常用gcc选项介绍

gcc选项很多,一般大型开发项目都会使用很多控制选项,这里仅介绍简单常用选项:

-v:查看gcc编译器的版本,显示gcc执行时的详细过程
-o <file>         Place the output into <file> (指定输出文件名为file,这个名称不能跟源文件名同名)
                           
-E                       Preprocess only; do not compile, assemble or link(只预处理,不会编译、汇编、链接)
                           
-S                       Compile only; do not assemble or link(只编译,不会汇编、链接)
                           
-c                       Compile and assemble, but do not link(编译和汇编,不会链接 )

3、生成一个可执行文件的三种方法

以hello.c文件为例
在这里插入图片描述

1)方式1

gcc -E -o hello.i hello.c
gcc -S -o hello.s hello.i
gcc -c -o hello.o hello.s
gcc -o hello hello.o

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j6Djo2jB-1647098293085)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312215503760.png)]
gcc会对.c文件默认进行预处理操作,-c再来指明了编译、汇编,从而得到*.o文件(object file 即我们常说的目标文件),再通过gcc -o hello hello.o将.o文件进行链接,得到可执行应用程序。

小结:
1)输入文件的后缀名和选项共同决定gcc到底执行哪些操作。
2)在编译过程中,除非使用了-E、-S、-c选项(或者编译出错阻止了完整的编译过程),否则最后的步骤都是链接。

2)方式2 - 开发项目中常用的方式

gcc -c -o hello.o hello.c
gcc -o hello hello.o

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jgbLRjoG-1647098293087)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312215956177.png)]

3)方式3

gcc -o hello hello.c  输出hello,然后./hello来执行该应用程序。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TQGKkt0b-1647098293087)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312220125123.png)]

注:如果不指定输出文件名,则默认生成a.out

gcc hello.c  输出一个a.out,然后./a.out来执行该应用程序。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuF8bn91-1647098293088)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312220207527.png)]

二、交叉编译的四个流程及实例说明

1、预处理(preprocessing)

问:什么是预处理?

C/C++源文件中,以“#“开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令“#define”、条件编译命令“#if”、“#ifdef”等。预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些代码输出到一个".i"文件,也就是说还是源代码文件;

问:为什么需要预处理?

一般预处理都是些简单的替换、拷贝和选择,这些涉及多个文件,预处理的结果是将每个源文件所需要的代码都放在自己文件里,然后方便下一步处理(ps:因为编译时,编译器每次读入一个文件,输出一个文件,不支持同时处理多个文件 - 来源于“编译原理”);

对比hello.i与hello.c文件内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W3zylFPg-1647098293089)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312220805414.png)]
对比hello.i与hello.c大小:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCFeUudT-1647098293091)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312220946568.png)]
明显hello.i大很多,原因是从其他文件拷贝了很多代码过来。

2、编译(compilation)

问:什么是编译?

编译就是把C/C++代码(比如上述的“.i”文件)翻译成汇编代码,这部分涉及复杂的编译器原理,有兴趣可以自行去看书深究;

问:为什么要翻译成汇编,而不直接生成机器码?

1、其一由于最开始的底层开发语言是汇编,而高级语言是在底层语言基础上发展的,自然而然会将成熟的工具(汇编器)利用起来,同时实现软件分层可以有效地减弱编译器编写的复杂性,“编译”所拆分的四大步骤也是如此道理;

2、其二有一个好处是方便优化和调试,汇编语言是机器指令的助记 符,一个汇编指令就对应一条机器指令,因此汇编语言更贴近机器特性,因此比高级语言调试起来更有优势;

查看hello.s文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JSnlKdLy-1647098293091)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312223635993.png)]

3、汇编(assembly)

问:什么是汇编

汇编(注意这里的汇编指的是编译器的一个编译动作,不是汇编语言)是利用汇编器将第二步输出的汇编代码翻译成符合一定格式的机器代码,就是我们熟悉的目标文件(*.o),在Linux系统上一般表现为ELF格式文件;如果开发代码是汇编,则汇编+链接就可以生成可执行文件了;

查看hello.o,需要用readelf工具查看
在这里插入图片描述

问:什么是反汇编文件?

反汇编文件是由可执行文件逆向解析而来,内容是按照实际内存分布来排布的,包含地址信息,一般用来调试分析用,非常有用;

生成反汇编文件
在这里插入图片描述

查看
在这里插入图片描述

问:汇编文件与反汇编文件的区别?

反汇编文件比汇编文件多了调试信息,如物理地址、机器码等,而汇编文件单纯只是汇编代码;

4、链接(linking)

问:什么是链接?

链接就是将汇编生成的OBJ文件、系统库的OBJ文件、库文件链接起来,即将各个ELF文件重新排序成一个ELF文件,最终生成可以在特定平台运行的可执行程序。

查看hello,需要用readelf工具
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fGs8jYuz-1647098293094)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312225906363.png)]

问:什么是系统库文件?

系统库文件:一个应用程序要运行在系统上,就需要系统标准启动文件,提供给系统用的;注意裸机bootloader、linux内核等程序是不能使用启动文件以及标准库文件(因为启动文件和库文件的使用是需要系统支持)。

一般gcc自动加入的系统标准启动文件有:crt1.o、crti.o、crtbegin.o、crtend.o、crtn.o
对于一般应用程序,这些启动是必需的。

通过查看gcc详细编译过程可以看到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MEIwa5uz-1647098293094)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312231007888.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xhohe0DU-1647098293095)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312231106971.png)]

问:什么是标准库文件?

很好理解,即库文件,如果代码用到标准库函数,而gcc集成了常用的库,链接时自动检索加入;

问:什么是动态链接?

动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态库才能运行。
动态链接生成的程序体积较小,但是必须依赖所需的动态库,否则无法执行。

gcc默认使用动态库链接

问:什么是静态链接?

静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直接运行,
不过静态链接生成的程序体积较大。

gcc静态链接需加入选项-static
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oHJZ7ZQE-1647098293095)(C:\Users\Anson\AppData\Roaming\Typora\typora-user-images\image-20220312231622957.png)]
很明显静态链接比动态链接生成的可执行文件大很多。

最后,编译原理还有很多值得深究的问题,比如ELF格式是什么?系统如何支持动态链接的?边实践边学习,由浅及深,通过现象理解本质才能不急不躁。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

重新理解Linux交叉编译及编译流程 的相关文章

  • 动态加载库和共享全局符号

    由于我在动态加载的库中观察到全局变量的一些奇怪行为 因此我编写了以下测试 首先我们需要一个静态链接库 头文件test hpp ifndef BASE HPP define BASE HPP include
  • 如何更改 Kubernetes 中的文件系统观察程序限制 (fs.inotify.max_user_watches)

    我在用着pm2 https github com Unitech pm2查看保存我的应用程序服务器的 NodeJS 程序源代码的目录 该程序在 Kubernetes 集群中运行 但是 我收到此错误 ENOSPC System limit f
  • Linux shell 标题大小写

    我正在编写一个 shell 脚本并有一个如下所示的变量 something that is hyphenated 我需要在脚本中的各个点使用它 如下所示 something that is hyphenated somethingthati
  • C/C++ with GCC:静态地将资源文件添加到可执行文件/库

    有人知道如何使用 GCC 将任何资源文件静态编译为可执行文件或共享库文件吗 例如 我想添加永远不会改变的图像文件 如果它们改变了 我无论如何都必须替换该文件 并且不希望它们位于文件系统中 如果这是可能的 我认为这是因为 Visual C f
  • 对于客户端服务器程序,并行接收多个客户端连接请求的最佳方法是什么?

    该程序是在 Linux 上用 C 语言开发的客户端服务器套接字应用程序 每个客户端都连接到一个远程服务器并将其自身记录为在线 在任何给定时间点很可能有多个客户端在线 所有客户端都尝试连接到服务器以将自己记录为在线 忙碌 空闲等 那么服务器如
  • Tk 初始化失败:无显示名称且无 $DISPLAY 环境变量

    我试图从 Ubuntu 终端调用 Centos 服务器上的工具 我收到以下错误 Tk 初始化失败 没有显示名称 也没有 DISPLAY 环境变量 请帮我解决这个问题 提前致谢 连接到你的 CentOS 机器ssh Y其中 每man ssh
  • Python 线程与 Linux 中的多处理

    基于此question https stackoverflow com questions 807506 threads vs processes in linux我假设创建新流程应该几乎和创造新线程在Linux中 然而 很少的测试显示出截
  • 查找当前打开的文件句柄数(不是 lsof )

    在 NIX系统上 有没有办法找出当前正在运行的进程中有多少个打开的文件句柄 我正在从正在运行的进程中寻找在 C 中使用的 API 或公式 在某些系统上 见下文 您可以在 proc pid fd 中对它们进行计数 如果不属于其中之一 请参阅下
  • 如何从 swagger 文档生成静态 html 文件?

    我创建了一个 Swagger 文档yaml文件位于 api swagger swagger yaml 现在我想分享一个静态 HTML 文档及其定义 但它已在招摇项目 https github com swagger api swagger
  • “以下软件包将被更高优先级的频道取代”是什么意思?

    我正在尝试将 fuzzywuzzy 安装到 64 位 Linux 中的 Anaconda 发行版上 当我这样做时 它试图改变我的conda and conda env to conda forge渠道 如下 我通过以下方式在 anacond
  • 第一次如何配置postgresql?

    我刚刚安装了 postgresql 并在安装过程中指定了密码 x 当我尝试做的时候createdb并指定我收到消息的任何密码 createdb 无法连接到数据库 postgres 致命 用户密码身份验证失败 同样适用于createuser
  • 串口读取未完成

    下面的函数用于在Linux下从串口读取数据 我在调试时可以读取完整的数据 但是当我启动程序时 读缓冲区似乎并不完整 我正确接收了一小部分数据 但缓冲区的其余部分完全正确zero 可能是什么问题呢 int8 t serial port ope
  • tcmalloc/jemalloc 和内存池之间有什么区别(以及选择的理由)?

    tcmalloc jemalloc是改进的内存分配器 还引入了内存池以更好地分配内存 那么它们之间有什么区别以及在我的应用中如何选择它们呢 这取决于您的程序的要求 如果您的程序有更多的动态内存分配 那么您 需要从可用的分配器中选择一个内存分
  • 如何每周日运行 crontab 作业

    我想弄清楚如何每周周日运行 crontab 作业 我认为以下应该可行 但我不确定我是否理解正确 下面的说法正确吗 5 8 6 这是 crontab 格式的解释 1 Entry Minute when the process will be
  • 如何告诉 CMake 将构建文件放在哪里?

    我想告诉 CMake 将文件和文件夹输出到不同的文件夹而不是当前文件夹 我在下面讨论的是 CMake 生成的文件 文件 CMakeCache txt 目录 CMakeFiles 文件 生成文件 目录 bin 文件 cmake install
  • 如何在 .zip 文件中使用 grep

    有 3 个文件 a csv b csv c csv 压缩为 abh zip 现在可以在 abh zip 上执行 grep 命令 是否有任何通配符 仅对里面的 c csv 文件运行 grep压缩 如果你有zipgrep 据我所知 它是随zip
  • 如何让 VSCode 在当前工作区中打开?

    我在 Linux 上使用 VSCode 我有多个 Linux 工作区 当我在新工作区中的 VSCode 中打开新文件时 它会在原始工作区中的 VSCode 中打开一个新选项卡 而不是在当前工作区中打开 VSCode 的新实例 这确实是令人讨
  • 超立方体错误。非法的最小或最大规格

    尝试从这里运行示例代码http tess4j sourceforge net codesample html http tess4j sourceforge net codesample html我收到一条错误消息 Error Illega
  • 在linux中将包含word的行从一个文件复制到另一个文件

    我想复制包含某些单词的行file1 to file2 Suppose file1 ram 100 ct 50 gopal 200 bc 40 ravi 50 ct 40 krishna 200 ct 100 file2应该只有包含 ct 的
  • Centos/Linux 将 logrotate 设置为所有日志的最大文件大小

    我们使用 logrotate 并且它每天运行 现在我们遇到了一些情况 日志显着增长 阅读 gigabaytes 并杀死我们的服务器 所以现在我们想为日志设置最大文件大小 我可以将其添加到 logrotate conf 中吗 size 50M

随机推荐

  • task3:西瓜书第四章(1)

    本次是阅读西瓜书第四章 以下为笔者是在阅读第四章决策树时一些之前不曾关注地方的补充 1 实际决策树学习算法是基于启发式算法 如贪婪算法 寻求在每个节点上的局部最优决策 这样的算法思想决定了在执行过程中不能保证返回全局最优决策树 例如ID3算
  • 英特尔® 硬件加速执行管理器安装指南 — Microsoft Windows*

    介绍 本文将指导您安装英特尔 硬件加速执行管理器 英特尔 HAXM 这是一款可以使用英特尔 虚拟化技术 VT 加快 Android 开发速度的硬件辅助虚拟化引擎 管理程序 前提条件 英特尔 HAXM 要求首先安装 Android SDK 版
  • 几行代码搞定Android底部导航栏

    底部导航栏的实现也不难 就是下边是几个Tab切换 上边一般是一个FrameLayout 然后FrameLayout中切换fragment 网上有不少关于Android底部导航栏的文章 不过好像都只是关于下边Tab切的 没有实现Tab与fra
  • Hexo搭建博客教程-基于Butterfly主题

    title Hexo搭建博客教程 tags Hexo 博客教程 categories Hexo keywords Hexo 博客教程 description Hexo搭建博客 以及主题butterfly中一些常规配置 cover https
  • sqlite3交叉编译

    1 交叉编译sqllite3可以先从官网下载最新最新的源码进行编译 sqlite3下载sqlite3有两种版本的源代码 sqlite amalgamation 3420000 zip这种是将所有的操作放到sqlite3中进行使用的 虽然官方
  • synchronized 的原理

    文章目录 前言 通过一系列的问题 了解synchronized 总结 前言 synchronized 是一个关键字 在多线程中 为了同步代码块 或者同步方法就会使用到 在面试的过程中 也是非常常见的 所以很有必要掌握 通过一系列的问题 了解
  • 题5:字符串的压缩

    题目 利用字符重复出现的次数 编写一个方法 实现基本的字符串压缩功能 比如 字符串 aabcccccaaa 经压缩会变成 a2b1c5a3 若压缩后的字符串没有变短 则返回原先的字符串 给定一个string iniString为待压缩的串
  • Pymol入门教程--基础

    Pymol入门教程 基础 软件界面介绍 内置demo介绍 打开PyMOL 点击1 1菜单窗口的Wizard菜单 然后点击Demo gt Representations然后在2 3对象窗口和2 4模式窗口之间会出现各种示例 Represent
  • Docker-Compose的安装

    一 什么是Docker Compose Compose项目来源于之前的fig项目 使用python语言编写 与docker swarm配合度很高 Compose 是 Docker 容器进行编排的工具 定义和运行多容器的应用 可以一条命令启动
  • IDEA插件安装以及一些不错的插件的推荐

    IDEA有自己庞大的插件支持 来丰富生态 现在一个好用点的工具如果没有点插件都不好意思 当然了 微信除外 因为人家会告你 一 插件的安装 IDEA的插件安装和别的IDE工具 比如eclipse或者vscode的位置都差不多 还是具体说一下
  • TensorFlow二元-多类-多标签分类示例

    探索不同类型的分类模型 使用 TensorFlow 构建二元 多类和多标签分类器 二元分类 简述 逻辑回归 二元交叉熵 二元分类架构 案例 逻辑回归预测获胜团队 多类分类 简述 Softmax 函数 分类交叉熵 多类分类架构 案例 预测航天
  • Jenkins CI、CD入门操作

    基于Jenkins拉取GitLab指定发行版本的SpringBoot代码进行构建发布到生产环境实现CD实现持续部署 准备测试项目 准备一个简单的Spring boot 项目 Jenkins新建任务 Jenkins关联Gitlab自动拉取最新
  • 如果一个人真的懂你

    一辈子 遇见一个真正读懂你的人 真的很难 人的一生中会遇到几十甚至上百万个人 其中能和你打招呼 称得上是朋友的人就更少 而在这么多人当中 却很有可能连一个真正懂你的人都没有 有些人 就算相识再久 也无法成为知己 有些人 即使你说了千句 他都
  • 基于错误信息的SQL盲注

    何谓盲注 在SQL注入基础一文中介绍了SQL注入的基本原理 可以轻易注入的原因是知道SQL拼接代码是怎么写的 很多情况下 很难甚至无法知道对方的SQL拼接语句是怎么写的 这里情况下需要做尝试 分析代码是采用何种拼接结构 然后再写个万能注入公
  • python docx 表格样式的设置修改表格列宽

    我的需求是设置表格的列宽和高度 之前的代码使用网上找的方法 table cell y x width Cm 4 无论怎么修改都是无效的 最后正确的代码是 col table columns 1 col width Inches 5
  • 修改mt4服务器地址,修改mt4服务器地址

    修改mt4服务器地址 内容精选 换一换 云平台支持修改主网卡的私有IP地址 具体操作请参见本节内容 如需修改扩展网卡的私有IP地址 请删除网卡 并挂载新网卡 云服务器已关机 如果网卡绑定了虚拟IP或者DNAT规则 需要先解绑 如果网卡上有I
  • [译] APT分析报告:03.OpBlueRaven揭露APT组织Fin7/Carbanak(上)Tirion恶意软件

    这是作者新开的一个专栏 主要翻译国外知名的安全厂商APT报告文章 了解它们的安全技术 学习它们溯源APT组织的方法 希望对您有所帮助 前文分享了钓鱼邮件网址混淆URL逃避检测 这篇文章将介绍APT组织Fin7 Carbanak的Tirion
  • 什么浏览器好用稳定速度快?

    什么浏览器好用稳定速度快 说到浏览器 不知道你们是否有这样的困惑和烦恼 浏览器换了一款又一款 内存大就不说了 体验总是不尽人意 经常弹出一些莫名其妙的资讯 还会出现卡住 奔溃 网页打开不完全 打开速度慢等情况 就拿我最近用的两款360来说吧
  • Nginx+lua实现秒杀系统架构

    能今天做好的事就不要等到明天 以梦为马 学习趁年华 文章目录 前言 一 秒杀业务特点 1 瞬时高并发 2 热点数据 3 读多写少 二 技术难点 1 数据一致性 2 库存超卖 三 秒杀注意事项 1 数据预热 2 请求承载 3 请求拦截 四 微
  • 重新理解Linux交叉编译及编译流程

    参考书籍 1 编译原理 2 嵌入式Linux应用开发 文章目录 一 交叉编译背景 二 gcc和arm linux gcc的常用选项 1 查询gcc帮助 2 常用gcc选项介绍 3 生成一个可执行文件的三种方法 二 交叉编译的四个流程及实例说