静态链接和静态库

简介: 静态链接和静态库

1.静态链接和静态库


静态链接是由链接器在链接时,将库的内容加入到示例程序中的过程。其中使用的库就是我们通常所说的静态库。


静态库可以简单的看成成一组目标文件的集合,即多个目标文件经过压缩打包形成的一个文件。(通过ar工具)


2.静态链接过程


现在的链接器空间分配策略基本上采用一种叫两步链接的方法。然后整个链接过程分为两步:


  • 第一步:空间与地址分配。


扫描所有的输入目标文件,获得他们的各个段的长度,属性和位置,并且将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到一个位数符号表。


这一步中,链接器将能够获得所有输入目标文件的段长,变为他们合并,计算出输出文件中各个段合并后的长度和位置,并建立映射关系。


  • 第二步:符号解析与重定位。


使用初步中收集到的所有信息,读取输入文件中段的数据,重定位信息,并进行符号解析和重定位,调整代码中的地址等。


image.png


3.静态库的制作和使用


查看静态库包含的目标文件


-t表示列出包含的所有目标文件



ar -t libc.a


    截取部分。可以看到glibc库包含了很多目标文件。


image.png


解压目标文件


-x表示解压库文件,交替解压所有

ar -x libc.a //解压指定文件
ar -x libc.a printf.o //从libc.a中解压指定printf.o


制作目标文件


-r:替换替换文件中已有的文件或加入新文件;-c:没有创建库的时候发出警告;-s:创建索引



ar -rcs libab.a a.o b.o
ar -rcs *.o libc.a


静态库使用


-L:指定链接链接;-l后面跟随链接的库名(去掉lib)


gcc -Llinkpath -lname
gcc -L./ -lab (libab.a 恰头去尾)


4.实例分析:最小的程序


知道了静态链接过程,以及程序大部分运行时都离不开libc,那么可不可以绕开glibc,写一个最小程序呢?


另外程序可以没有main 函数吗?


答案是可以,这里涉及到操作系统的系统调用和底层知识,如果对操作系统和汇编体系比较熟悉,当然可以绕开。系统调用留待后续介绍。


如图,为一个最小的程序,并且没有 main 函数入口:


image.png


手动链接


编译:gcc -c -fno-builtin nomain.c -m32


-fno-builtin:关闭 GCC 内置函数功能

-m32:指定 32 为系统。默认是 64 位的,不加会报错。


链接:ld -m elf_i386 -static -e nomain -o helloworld nomain.o


-m :设置文件输出格式为 elf_i386。

-static:表示静态链接.

-e nomain:设置程序入口函数为 nomain


使用链接脚本


事实上,链接器在链接时默认有个链接脚本。函数的入口地址,以及各段分部,都可以通过链接脚本控制。我们程序当然也可以指定链接脚本。链接脚本的语法规则本文暂不介绍。


链接:ld -m elf_i386 -static -T nomain.lds -o helloworld nomain.o


image.png


通过该脚本指定入口符号为nomain、将代码段、数据段和只读数据段合并为tinytext,同时舍弃.comment,编出来的程序只有几百个字节,大大缩小了空间。


-ENTRY:指定符号的值为入口地址。

-. = 0x80480000 + SIZEOF_HEADERS 。将当前虚拟地址设置为 0x80480000 + SIZEOF_HEADERS(为输出文件头大小)。

-tinytext : {*(.text) *(.data) *(.rodata)}。将代码段、数据段或者只读数据段合并为 tinytext 段。

-/DISCARD/ : {*(.comment)}。将.comment 丢弃


5.总结


本文主要介绍了,静态链接的过程以及静态库的制作和使用。旨在帮助大家理解库文件和目标文件的关系。


了解静态链接过程,有助于我们调试和分析问题。尤其是在没有源码的情况下,可以通过objdump找到符号表,对应的目标文件位置,然后通过ar将对应目标文件解压出来,最后通过反汇编来分析问题。


另外,main函数作为程序入口已经成为约定俗称,修改入口函数,仅作娱乐使用,切勿使用正式项目,毕竟代码还是要有可读性。


细心的朋友已经发现了,静态链接占的空间大,而且如果多个程序都用了同一份静态库,会极大的浪费资源。那么它存在的价值在哪里呢?

相关文章
|
Linux C语言 开发者
深入解析Linux环境下的scanf()、sscanf()和fscanf()函数
在C语言中,`scanf()`、`sscanf()`和`fscanf()`是用于输入的三个常用函数。它们允许开发者从标准输入、字符串和文件中按照指定的格式读取数据。在Linux环境下,这些函数被广泛用于处理各种输入。本文将详细介绍这三个函数的用法,包括格式化字符串的语法和一些常见的使用场景。
1559 1
|
人工智能 自然语言处理 测试技术
什么是通义灵码?
什么是通义灵码?
2743 0
|
6月前
|
机器学习/深度学习 弹性计算 应用服务中间件
阿里云服务器租赁价格标准整理汇总:一年/按月/按小时报价明细出炉
最新的阿里云服务器价格多少钱1年?阿里云服务器产品包含 ECS 云服务器、轻量应用服务器和 GPU 服务器,涵盖多种实例规格与配置,满足不同使用需求。今天小编总结一篇关于最新的阿里云服务器租赁价格标准整理汇总:包含一年/按月/按小时报价明细。
|
Java 数据安全/隐私保护 开发者
【潜意识Java】深入理解 Java 面向对象编程(OOP)
本文介绍了Java中的面向对象编程(OOP)核心概念,包括封装、继承、多态和抽象。封装通过访问控制保护数据,提高安全性;继承支持代码复用,减少冗余;多态实现灵活的行为调用;抽象则隐藏细节,简化接口设计。掌握这些概念有助于编写高效、灵活且易于维护的代码。文章通过实例详细讲解了每个概念在Java中的应用,并总结了它们的优势。
800 3
|
监控 关系型数据库 MySQL
云数据库:从零到一,构建高可用MySQL集群
在互联网时代,数据成为企业核心资产,传统单机数据库难以满足高并发、高可用需求。云数据库通过弹性扩展、分布式架构等优势解决了这些问题,但也面临数据安全和性能优化挑战。本文介绍了如何从零开始构建高可用MySQL集群,涵盖选择云服务提供商、创建实例、配置高可用架构、数据备份恢复及性能优化等内容,并通过电商平台案例展示了具体应用。
|
机器学习/深度学习 人工智能 算法
从 OpenAI-o1 看大模型的复杂推理能力
深入解析OpenAI o1模型的复杂推理技术与发展历程
从 OpenAI-o1 看大模型的复杂推理能力
|
存储 Cloud Native API
Docker镜像管理:为什么Harbor是首选
Docker镜像管理:为什么Harbor是首选
|
人工智能 算法 新能源
【2023高教社杯】A题 定日镜场的优化设计 问题分析及数学模型
本文介绍了2023年高教社杯数学建模竞赛A题的定日镜场优化设计问题,涉及问题分析和数学模型构建,旨在提高太阳能光热发电效率并实现电力系统的新能源转型。
596 1
【2023高教社杯】A题 定日镜场的优化设计 问题分析及数学模型
|
程序员
入职必会-开发环境搭建10-Typora下载和安装
Typora 是一款备受推崇的 Markdown 写作软件,旨在提高生产效率和简化写作体验。它通过实时预览功能,去除了预览窗口和其他干扰,让用户专注于内容创作。Typora 使用 GitHub Flavored Markdown,支持 Markdown 和富文本编辑,并提供了诸如字数统计、文章大纲、页面布局等功能,使写作更加便捷。此外,Typora 也支持插入图片,用户可以通过 Markdown 语法或直接拷贝粘贴的方式插入图片。
408 1
|
运维 监控 API
自动化运维实践指南:Python脚本优化服务器管理任务
本文探讨了Python在自动化运维中的应用,介绍了使用Python脚本优化服务器管理的四个关键步骤:1) 安装必备库如paramiko、psutil和requests;2) 使用paramiko进行远程命令执行;3) 利用psutil监控系统资源;4) 结合requests自动化软件部署。这些示例展示了Python如何提升运维效率和系统稳定性。
1469 8