编译链接实战
文章平均质量分 78
介绍了Linux平台下的编译链使用
奇妙之二进制
csdn博客专家,C/C++领域优质创作者,抖音搜奇妙之二进制,专注于Linux C/C++、嵌入式Linux开发,偶尔谈谈人生,目前致力于完成大约500篇的linux C/C++开发知识体系库,所有的文章都会一直保持更新(优化内容、排版),想学习的可以订阅我的专栏,也可以关注Linux 世界。
展开
-
关于《编译链接实战》专栏的创作初衷
超线程技术利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和应用软件,减少CPU的闲置时间,提高CPU的运行效率。Bogo 意思是“假的,伪造的”,之所以说是假的,是因为在计算 BogoMIPS 的值时,CPU 一直在单一的执行 NOP (空操作),而不是随机执行指令集中的任意指令,所以不能以此作为 CPU 的性能指标。举例来说,如果某个服务器”2 路 4 核超线程”,也就是 2 个插槽,4 核心,默认为 2 thread,也就是 2。原创 2023-02-18 14:11:08 · 546 阅读 · 0 评论 -
编译链接实战(25)ThreadSanitizer检测线程安全
ThreadSanitizer(又称为TSan)是一个用于C/C++的数据竞争检测器。在并发系统中,数据竞争是最常见且最难调试的错误类型之一。当两个线程并发访问同一个变量,并且至少有一个访问是写操作时,就会发生数据竞争。C++11标准正式将数据竞争定义为未定义行为。更多例子见https://github.com/google/sanitizers/wiki/ThreadSanitizerPopularDataRaces。原创 2024-03-02 22:15:38 · 627 阅读 · 0 评论 -
编译链接实战(25)gcc ASAN、MSAN检测内存越界、泄露、使用未初始化内存等内存相关错误
fsanitize=address是一个编译器选项,用于启用AddressSanitizer(地址清理器),这是一种快速的内存错误检测工具。它可以检测出程序中的两种常见错误:越界访问(out-of-bounds accesses)和使用后释放(use-after-free)错误。当你在编译程序时使用这个选项,编译器会插入额外的代码来检查每次内存访问是否合法,以便发现潜在的内存错误。原创 2024-03-02 16:20:59 · 394 阅读 · 0 评论 -
编译链接实战(24)禁用临时对象消除优化-fno-elide-constructors
后来经过查找发现是因为g++编译器实现省略创建一个只是为了初始化另一个同类型对象的临时对象。指定这个参数(-fno-elide-constructors)将关闭这种优化,强制g++在所有情况下调用拷贝构造函数。在fun函数中会返回一个class A的对象,那么编译器会在栈上构造一个临时对象,构造临时对象的方法则是调用拷贝构造函数。3.如果函数返回值是类对象,函数执行完成返回调用时。那么加上这个参数重新编译试试,运行结果如下。1.当用类一个对象去初始化另一个对象时。道理很简单,我写了个很简单的例子。转载 2024-03-02 10:52:27 · 105 阅读 · 0 评论 -
编译链接实战(22)C/C++代码覆盖率统计报告生成
gcov是一个测试代码覆盖率的工具,它是 gcc 自带的查看代码覆盖率的工具。使用效果如下图所示:程序运行完成后,可以查看每个文件的代码覆盖率情况,上面报告中展示了每个文件的行覆盖率,函数覆盖率和分支覆盖率。打开一个文件的覆盖率报告,页面对开始有文件的基本信息描述,以 FreeRTOS 的 task.c 为例,它的有效代码行数为 921 行,共 24 个函数(几千行的文件其实也没多少嘛~)蓝色表示运行被覆盖的代码,前面的数字表示代码执行次数。红色表示未执行代码。原创 2024-03-02 00:06:27 · 1621 阅读 · 0 评论 -
编译链接实战(21)链接过程的符号冲突问题
在解析引用的过程中,最常发生的问题就是符号重定义。当链接器将目标文件或静态库同时链接到最终的二进制文件时,是不能出现重复符号的,否则会导致链接失败,即对于静态链接,重复符号是零容忍的。但对于动态链接,链接器却采取了容忍的策略。在Linux下编译动态库的时候,所有的符号默认都是导出的,也就是动态库中的函数名,类名等,在外部都是可见的。当程序引用多个动态库时,由于各个动态库可能属于不同的团队来开发,不同团队使用相同的第三方库的可能性也是有的(例如openssl,libcurl,cjson等),转载 2024-01-21 20:31:08 · 143 阅读 · 0 评论 -
编译链接实战(20)链接究竟做了哪些事
为了更好地理解计算机程序的编译和链接的过程, 我们先简单回顾下计算机程序开发的历史。计算机的程序开发并非从一开始就有着这么复杂的自动化编译、 链接过程。原始的链接概念远在高级程序语言发明之前就已经存在了, 在最开始的时候, 程序员(当时程序员的概念应该跟现在相差很大了) 先把一个程序在纸上写好, 当然当时没有很高级的语言, 用的都是机器语言, 甚至连汇编语言都没有。当程序须要被运行时, 程序员人工将他写的程序写入到存储设备上, 最原始的存储设备之一就是纸带, 即在纸带上打相应的孔。转载 2024-01-21 14:06:25 · 97 阅读 · 0 评论 -
编译链接实战(19)常见编译链接错误汇总
-Wnon-virtual-dtor (C++ and Objective-C++ only)Warn when a class has virtual functions and an accessible non-virtual destructor itself or in an accessible polymorphic base class, in which case it is possible but unsafe to delete an instance of a derived c原创 2022-12-06 11:28:21 · 899 阅读 · 0 评论 -
编译链接实战(18)error: jump to case label
二、说明从上面的代码中可以看出,因为switch中没有单独的区域块来限定变量i的声明周期,所以变量的作用域是初始化点到switch的结尾处。这里由于我们无法确定其他case中是否会使用到这种变量,使用之前变量是否被初始化,所以编译器会报错。例如:test值为2,直接执行case 2的话,未定义变量就会出异常。这也是编译器报错的原因。经过检验发现,。三、修改方法1、【缩小作用域】将case 1的代码用{ }括起来,设定清楚变量i的作用域,避免其他case访问2、【扩大作用域】将变量i放到switch外转载 2022-12-06 17:47:58 · 1654 阅读 · 0 评论 -
编译链接实战(17)编译选项-fpermissive部分错误降低为警告--谨慎使用
该选项最好不要使用,因为会降低对于代码检查的严格性。该选项会将不一致代码的诊断从错误降级为警告。转载 2022-12-01 16:29:52 · 1132 阅读 · 0 评论 -
编译链接实战(16)编译器内置属性修饰符__attribute__((constructor))用法解析
请记住,全局变量的初始化顺序是依赖于编译器和链接器的具体实现的,可能在不同的编译器和平台上有所不同。需要注意的是,初始化函数的优先级仅用于确定它们的执行顺序,并不表示初始化的速度。默认情况下,没有指定优先级的初始化函数被视为具有中等优先级(0),而通过显式设置优先级,可以控制初始化函数的执行顺序。特性为开发者提供了一种方便的方式来定义在程序启动时自动执行的初始化函数,使得全局的初始化工作变得更加简单和方便。是GCC和兼容的编译器中的一个特性,用于指示编译器将一个函数标记为在程序启动时自动执行的初始化函数。原创 2023-11-23 20:14:00 · 1597 阅读 · 0 评论 -
编译链接实战(15)-rdynamic选项导出所有符号到动态符号表
而使用 -rdynamic 选项重新编译程序时,会将所有符号导出到动态符号表中,backtrace_symbols 函数可以从动态符号表中查询到相应的符号信息,从而得到更详细的调用链信息,例如函数名、参数和行号等。默认链接器在产生可执行文件时,只会将那些链接时被其他共享模块引用到的符号放到动态符号表中,这样可以减少动态符号表的大小,也就是说,在共享模块中反向引用主模块中的符号时,只有那些在链接时被共享模块引用到的符号才会被导出。这样,在运行时,可执行文件将包含完整的符号信息,包括函数名、全局变量等。原创 2023-09-03 01:00:17 · 1231 阅读 · 0 评论 -
编译链接实战(14)符号重定位与重定位表
符号重定位可以进行这种修正,使得程序中的符号引用指向正确的内存位置。这就是符号重定位的作用:将符号的引用解析为实际的内存地址。3、对于每个重定位条目,程序加载器通过符号表找到引用的符号,并将其地址与重定位类型和附加信息一起应用于重定位位置,以计算出最终的内存地址。符号重定位是实现动态链接和符号解析的关键步骤,它使得程序能够充分利用共享库和模块化设计,实现更高效和灵活的软件开发与部署。通过符号重定位,程序在运行时能够解析和访问其他对象文件或共享库中定义的符号,实现模块之间的符号引用和互操作。原创 2023-09-02 21:12:57 · 482 阅读 · 0 评论 -
编译链接实战(13)认识GOT表
GOT是一个特殊的数据段,存储着全局符号的地址。在程序启动时,动态链接器会填充GOT中的每个元素,将真正的地址写入其中。这样,当程序需要访问一个全局变量或调用一个外部函数时,它实际上是通过间接引用GOT中的对应元素来获取地址。需要注意的是,GOT是特定于体系结构和操作系统的,不同的体系结构和操作系统有不同的实现方式。时,编译器无法确定真正的地址,因为这些全局符号的地址是在程序运行时才被分配的。GOT的目的是提供一种机制,使得程序中的地址引用可以在动态链接的情况下解决。,从而支持动态加载和共享库的使用。原创 2023-09-02 19:54:15 · 410 阅读 · 0 评论 -
编译链接实战(12)crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o是什么东西
crt是c runtime 的缩写,用于执行进入main之前的初始化和退出main之后的扫尾工作。crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o 等目标文件和daemon.o(由我们自己的C程序文件产生)链接成一个执行文件。前面这5个目标文件的作用分别是启动、初始化、构造、析构和结束,它们 通常会被自动链接到应用程序中。转载 2023-02-20 20:30:23 · 2023 阅读 · 1 评论 -
编译链接实战(10)认识elf文件符号表
每个定义的符号有一个对应的值,叫做符号值(Symbol Value),对于变量和函数来说,符号值就是它们的地址。Ndx 表示其所在section的序号,初始化过的全局变量g_a肯定在数据段.data,函数在代码段.text,【未经初始化的全局变量】和static变量在.bss段(static不管是否初始化都在bss段)。Value 该符号的值(注意不是变量的值),符号的值就是指符号的地址,对于编译的中间文件.ol来说,value其实是该符号在其所在的section的偏移,是个相对值;原创 2023-02-21 16:13:47 · 1252 阅读 · 0 评论 -
编译链接实战(9)认识elf文件格式
链接器在链接可执行文件或动态库的过程中,它会把来自不同可重定位对象文件中的相同名称的section合并起来构成同名的section。接着,它又会把带着相同属性(比方都是只读并可加载的)的section都合并成所谓segment(段)。Segment作为链接器的输出,常被称为输出section。开发者可以控制哪些不同.o文件的section来最后合并构成不同名称的segment。原创 2023-02-16 14:38:42 · 935 阅读 · 0 评论 -
编译链接实战(5)gcc背后的步骤分解
从 hello.c 到 hello(或 a.out)文件, 必须历经 hello.i、 hello.s、 hello.o,最后才得到 hello(或。参数,将会生成 hello 文件,这个文件和 a.out 实际上是一样的,用 md5sum 命令计算文件校。将会产生 hello.i 文件,这就是 hello.c 经过预处理后的文件。一个原本连同空行才 8 行的代码,经过预处理,得到了一个 800 多行的预处理文件,文。(2) 编译,将预处理得到的源代码文件,进行“翻译转换”,产生出机器语言的目标。原创 2023-02-16 19:27:34 · 670 阅读 · 0 评论 -
编译链接实战(8)linux动态库运行时查找路径全面盘点
本文是一篇实操性文章,我们先上结论:Linux动态库.so搜索路径对于实操验证的过程不感兴趣的可以移步了。众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib。动态库被创建后,一般都复制到这两个目录中。当程序执行时需要某动态库,并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库提供的函数,以及该动态库的其它资源了。在Linux 中,动态库的搜索路径除了默认的搜索路径外,还可以通过以下三种方法来指定。原创 2023-02-26 23:58:31 · 4326 阅读 · 0 评论 -
编译链接实战(7)gcc和g++的区别
GCC:GNU 编译器集合,GNU 编译器支持的所有不同语言的参考。gcc: GNU C 编译器g++: GNU C++ 编译器主要区别:gcc 将.c/.cpp 文件分别作为 C 和 C++编译。g++将编译:.c/.cpp文件,但它们都将被视为C++文件。此外,如果您使用g++链接对象文件,它会自动链接std C++库(gcc不这样做)。gcc 编译 C 文件的预定义宏较少。gcc 编译.cpp和 g++ 编译 *.c/.cpp 文件有一些额外的宏。#define翻译 2022-05-03 14:34:52 · 2955 阅读 · 0 评论 -
编译链接实战(6)添加头文件路径和库路径
gcc/g++可以通过-i、-include来添加外部头文件路径,-L添加动态库路径,-l链接动态库。原创 2023-02-16 19:10:57 · 3088 阅读 · 0 评论 -
编译链接实战(4)--sysroot和-isysroot选项对编译的影响
在做交叉编译的时候,常常涉及到一个gcc编译选项–sysroot,这个选项是用来设置目标平台根目录的。–sysroot选项的官方说明如下从--sysroot的说明可以看出,其会对编译和链接过程中,查找头文件和链接库造成影响。例如:原本默认会从目录中搜索头文件、从/usr/lib中搜索依赖库,当设置了后则会从搜索头文件、从中搜索依赖库。通过。转载 2023-02-13 15:38:07 · 2279 阅读 · 0 评论 -
编译链接实战(3)编译链接时头文件、库搜索路径方式全面盘点
总之,在编译期间使用 -I、-isystem、-iquote 和 -idirafter 等选项,可以指定多个不同的目录,用于搜索头文件。-iquote dir指定的dir只用于#include ""的形式,而-i、-isystem、-idirafter 对于#include “”和#include 都适用。2、对于 #include “file” 形式的指令,接下来会按照命令行上 -iquote 选项出现的顺序,依次搜索这些由 -iquote 指定的目录。命令可以查看ld在链接时查找库的路径列表。原创 2023-02-15 13:14:32 · 1142 阅读 · 0 评论 -
编译链接实战(2)静态库vs动态库--概念及制作方法
我们把所有相关源代码进行编译,链接,最后生成可执行文件,这个文件不依赖于其他模块,是一个完整的可执行单元。操作系统处理这类文件的流程是直接将elf的所有段拷贝到内存中,然后将PC指针指向entry就可以运行了,什么场景下会这样使用呢?优点:程序是一个完整的可执行单元,不需要操作系统去进行重定向操作 缺点:每一个依赖于某个静态库的应用程序都会包含完整的静态库,这样每一个应用程序都会占用磁盘空间和内存空间,如果这样的应用程序有成千上万,那资源浪费很大。依赖于其他模块,其他模块以静态库的方式链接到应用程序。原创 2023-02-26 23:58:46 · 519 阅读 · 0 评论 -
编译链接实战(1)gcc新手教程,完成一个C程序的编译运行!
但是 Vim 和 Emacs 并不容易上手,使用者需要记忆很多命令和快捷键,熟练才能生巧,所以需要一段时间的学习和适应,这会增加初学者的学习成本,所以这里不推荐大家使用。Linux 下使用最广泛的 C/C++ 编译器是 GCC,大多数的 Linux 发行版本都默认安装,不管是开发人员还是初学者,一般都将 GCC 作为 Linux 下首选的编译工具。注意:不像 Windows,Linux 不以文件后缀来区分可执行文件,Linux 下的可执行文件后缀理论上可以是任意的,这里的。原创 2021-11-21 22:23:27 · 12674 阅读 · 0 评论 -
编译链接实战(0)了解gcc/g++编译器
GNU谈到 GCC,就不得不提 GNU 计划。GNU 全称 GNU’s Not UNIX,又被称为“革奴计划”,由理查德·斯托曼于 1983 年发起。GNU 计划的最终目标是打造出一套完全自由(即自由使用、自由更改、自由发布)、开源的操作系统,并初步将其命名为 GNU 操作系统(其 logo 如图所示)。GNU 计划的实施可谓一波三折,最重要的一点是,虽然该计划为 GNU 操作系统量身定做了名为 Thr Hurd 的系统内核,但由于其性能比不上同时期诞生的 Linux 内核,最终 GNU 计划放弃 T原创 2022-05-03 12:41:28 · 637 阅读 · 0 评论