你真的懂Hello World!吗?(编译与链接,静态链接与动态链接)

💫Hello World!

  对于大家来说Hello World!应该是最熟悉不过的一句话,我们从Hello World!走进了计算机的世界,但是你真的了解Hello World!吗?你又思考过它背后蕴含的机理吗?他是怎么从代码变成程序的你真的思考过吗?
  今天本篇文章会对它的底层做最基本的讲解,后续博主会再次对它进行深入解析!!
  那么我们开始吧!!

💫被隐藏的部分——编译与链接

  对于visual studio这样的集成开发平台(编译,链接,调试集一体),要看到细节是很难的,所有本文将使用Linux的gcc编译器进行操作。
  一个源文件变成可执行程序需要经过以下几个步骤:
1.预处理(也叫预编译)  2.编译  3.汇编  4.链接
  每个步骤又包含有许多小步骤。

⭐️预处理

  预处理的工作主要有以下:
1.宏替换(删除所有的“#define”,展开所有的宏)
2.条件编译
3.头文件包含
4.去注释

  我们对以下程序做预处理:
在这里插入图片描述

  我们输入编译指令,查看预处理之后生成的.i文件
  输入指令gcc -E file.c -o file.i -Dversion1=1(与在文件内部#define version1 1作用相同)
  (-E指令表示进行程序翻译在预处理完成后停下来
  (-o指令表示命名,上面指令表示把经过预处理后的文件命名为file.I)
  (-D能够实现对程序进行动态裁剪,假如我们的version1,version2,version3分别表示程序的不同版本,那么通过条件编译就能控制程序不同版本的发布)
  我们截取file.i的一部分
在这里插入图片描述  我们可以看到,以上几个步骤实际发生了,这里需要提及一下头文件包含,实际上头文件包含就是把头文件里面的内容拷贝到了我们的文件里。

⭐️编译

  编译的过程就是对预处理后文件进行一系列的处理(词法分析,语法分析,语义分析,符号汇总以及优化过程)最后产生汇编代码的过程。
我们对一个最简单的表达式做以上处理:

int A=7+9

  词法分析简单来说就是记录符号的过程。

记号类型
A标识符
7数字
9数字

  语法分析是生成语法树的过程。
在这里插入图片描述

  语义分析就是对表达式做语义分析判断它是否有意义,语义又分为静态和动态语义,静态语义通常是声明和类型转换,动态语义指在程序运行出现的语义问题,例如除零错误。
语义分析后的语法树
在这里插入图片描述  我们在命令行输入
gcc -S file.i -o file.s
  (-S指令表示开始程序翻译,编译步骤结束后停下来)
  以下就是编译后的汇编代码
(注:我们不需要懂汇编代码,现在我们只需要知道有转汇编这个步骤)
在这里插入图片描述

⭐️汇编

  汇编就是将汇编代码变成机器可以执行的指令的过程,最后输出一个目标文件(可重定位二进制文件),汇编有一个重要的步骤——形成符号表这个需要我们注意。
  在命令行输入
gcc -c file.s -o file.o
(-c指令表示开始程序翻译,汇编步骤结束后停下来)
  打开.o文件
在这里插入图片描述  里面大部分都是乱码,但是我们可以看到ELF和.data这些符号,对。这个很重要。
  我们可以使用od指令打开它,但是并没有一点用,二进制我又看不懂。
在这里插入图片描述
  与其说它是一个二进制文件,但实际上他是一个ELF文件。它有重要的段表和符号表,就是基于这个文件才能进行后续的链接步骤。ELF文件类型很多(例如动态库文件,可执行文件,可重定位二进制文件都是ELF文件)。

  我们可以使用readelf工具读取ELF文件
命令行输入readelf -a file.o可以详细的查看ELF文件,包括ELF文件头,段表,符号表等等

文件头
在这里插入图片描述段表
包含段的信息,有address(段虚拟地址),offset(段偏移),flags(段标志)等等等一系列信息。
在这里插入图片描述符号表

在这里插入图片描述  细心的小伙伴可能发现符号表里面怎么有puts符号,懵逼了吧,其实这里是gcc搞的鬼,他把只打印一个字符串的printf自作聪明的换成了puts.

num:符号表数组下标
value:符号值
size:符号大小
type:符号类型
bind:绑定信息
ndx:在语言中是否使用
name:符号名

⭐️链接

  链接是重新翻译的最后一步,链接后就生成可执行程序。
  链接步骤中至关重要的就是段表的合并符号表的合并与重定位工作
  关于符号表
  通过上面的学习我们知道在编译过程中有对符号的汇总,汇编步骤形成符号表,最后链接对符号表进行合并与重定位,他是怎么实现的。
我们有以下程序:
在这里插入图片描述
在这里插入图片描述  我们就拿Add符号举一个例子。
  在编译时两个文件都对符号进行汇总,两个文件都有一个相同符号Add
  在汇编阶段形成符号表,对于Add.c文件形成的符号表会给Add符号一个实际地址,对于test.c文件形成的符号表编译器并不知道它的目标地址会把他的目标地址置为0.
  最后链接器将他们链接起来的时候会将地址修正,也就是重定位。
  分别查看三个文件的符号表

在这里插入图片描述在这里插入图片描述
  最后的可执行程序的符号表就不再展示,链接会链接库,最后的符号表有库文件的符号,使得可执行符号表很长,有兴趣的小伙伴可自行查看。
  关于段表
  我们可以使用objdump工具查看段
  命令行输入objdump -h test.o
在这里插入图片描述其中size表示段长,file off表示段的位置

  这里介绍一下常见且易于理解的段
   .text段(代码段):存放编译后的机器指令
   .data段(数据段):初始化的全局变量以及静态局部变量(如果初始化为0则将其放在.bss段)
  .bss段:未初始化的全局变量以及静态局部变量
  .rodata(只读数据段):只读变量,例如const变量,以及字符串常量
  .rel.text:重定位表,存储的重定位信息。
命令行输入objdump -x -s -d test.o
(-s表示把段内容以十六进制打印出来,-x表示反汇编)
在这里插入图片描述  我们看.data和.rodata段
  .data前四个从低到高是0x0a 0x00 0x00 0x00表示的就是global_init_var
  同理后四个字节是static_var
  .rodata的256400既是表示字符串常量%d
  命令行输入objdump -r test.o可查看重定位表
  以下是代码段重定位表
  offset表示重定位入口的偏移。
在这里插入图片描述

💫动态链接与静态链接

⭐️ 动态库与静态库

动态库静态库
Windows.dll.lib
Linux.so.a

  动态库用于动态链接,静态库用于静态链接
  动静态库的本质其实是目标文件的集合。
  在Linux中链接默认进行动态链接。
file查看文件类型,ldd查看库依赖
在这里插入图片描述在这里插入图片描述框出的部分是C运行库

⭐️ 静态链接

  静态链接就是把我们的.o文件和使用到库中的文件链接形成可执行程序的过程,在我们使用某个库的时候,可能我们所使用到的这个库可能也依赖其他库,那么对他也需要链接,但是这个琐碎的步骤是由链接器完成的。
  对于静态链接你可以把它理解成拷贝其他文件代码的过程,需要哪里就拷贝哪里,最后形成的可执行程序不再依赖其他库就能运行。

⭐️ 动态链接

  动态链接的基本思想是把程序按照模块拆分成各个相对独立的部分,在运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接一样把所有程序模块都链接成一个单独的可执行程序。
  动态链接形成的可执行程序每次运行都需要链接,重定位是不是很慢,确实,它相较于静态链接形成的可执行程序会慢,但是它有自己的解决方法即是延迟绑定,延迟绑定的基本思想就是:当函数第一次使用到的时候才会进行绑定,对于未使用到函数不会进行绑定。

⭐️ 对比

  动态链接节省资源但依赖库
  静态链接浪费资源但不再依赖库
我们对一个相同的程序分别采用两种链接方式生成一个可执行程序看一看。
在这里插入图片描述  file1和file2分别是动态链接和静态链接形成的可执行程序,我们通过上表可以明显看出他们在体积上的差别。
  对于静态库的安装

sudo yum install -y glibc-static
sudo yum install -y libstdc+±static

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

react18框架笔记

React React 是 facebook 出的一款针对视图层的库(library)。它是基于单向数据流思想开发的,主要的一个功能就是针对视图显示,让我们把一个项目拆分成一个一个组件进行开发维护。 官网 目前我们讲的 react 是基于 18.2 的版本。react 每一个版本更新之…

谷歌Linux内核自动测试平台架构介绍-用自动测试测试难以测试的问题

1 摘要 内核和硬件等低级系统已被证明极难进行有效测试,因此,许多内核测试都是以手动为主方式进行的。现有的大多数测试框架都是为测试与底层平台隔离的高级软件而设计的,而底层平台被假定是稳定可靠的。测试底层平台本身需要一套全新的假设…

命令行万年历程序

在linux终端里看不了日历,我不答应!代码仓库地址 一、命令行运行的效果图 如果输入的年份是目前所在年,会标注当天的日期 二、代码实现 1. 判断闰年 bool judge_leap_year(int year) {return ((year % 4 0) && (year % 100 ! 0)) …

听GPT 讲Rust源代码--src/tools(37)

File: rust/src/tools/clippy/clippy_lints/src/explicit_write.rs 在Rust源代码中,explicit_write.rs这个文件是Clippy的一个lint插件,其作用是检查代码中的write!、writeln!宏使用时的不当或繁琐的情况,并给出相关的警告或建议。 具体来说&…

浅谈冯诺依曼体系和操作系统

🌎冯诺依曼体系结构 文章目录 冯诺依曼体系结构 认识冯诺依曼体系结构       硬件分类       各个硬件的简单认识         输入输出设备         中央处理器         存储器 关于内存 对冯诺依曼体系的理解 操作系统 操作系统…

关键字:try-catch关键字

在 Java 中,try-catch关键字用于异常处理。它们允许编写代码来捕获和处理异常,以确保程序能够在出现问题时合理地处理它们而不会崩溃。 以下是try-catch关键字的基本语法: 在try块中编写可能会抛出异常的代码。如果在try块中的任何代码抛出…

2024年【安全员-B证】考试报名及安全员-B证新版试题

题库来源:安全生产模拟考试一点通公众号小程序 安全员-B证考试报名考前必练!安全生产模拟考试一点通每个月更新安全员-B证新版试题题目及答案!多做几遍,其实通过安全员-B证考试试题很简单。 1、【多选题】《中华人民共和国消防法…

单字符检测模型charnet使用方法,极简

Git链接 安装按照上面的说明,说下使用。 把tools下面的test做了一点修改,可以读取一张图片,把里面的单个字符都检测和识别出来。 然后绘制到屏幕上。 import torch from charnet.modeling.model import CharNet import cv2, os import num…

搭建maven私服

maven maven简介 什么是maven? Maven这个单词来自于意第绪语(犹太语),意为知识的积累。 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。 Maven 除了以…

20231228在Firefly的AIO-3399J开发板的Android11使用Firefly的DTS配置单前后摄像头ov13850

20231228在Firefly的AIO-3399J开发板的Android11使用Firefly的DTS配置单前后摄像头ov13850 2023/12/28 19:20 缘起,突然发现只能打开前置的ov13850,或者后置的ov13850。 但是不能切换! 【SDK:rk3399-android-11-r20211216.tar.xz】…

[Angular] 笔记 25:指令

组件指令 (chatgpt 回答) 在 Angular 中,组件本身可以被视为指令,这种指令被称为组件指令。组件是 Angular 应用的构建块之一,它封装了一段具有特定功能和特性的用户界面,并且可以在应用中重复使用。 组件指令具有以下特征&…

docker小白第十天

redis集群主从容错切换案例 3主3从的redis集群,某个主机宕机了,需要对应的从机补位。 docker exec -it redis-node-1 /bin/bash # 进入容器1的命令行 redis-cli -p 6381 # 进入节点1的命令行 cluster nodes # 查看集群信息可以看到1号和6号对应是主从关…

【PXIE301-208】基于PXIE总线架构的Serial RapidIO总线通讯协议仿真卡

板卡概述 PXIE301-208是一款基于3U PXIE总线架构的Serial RapidIO总线通讯协议仿真卡。该板卡采用Xilinx的高性能Kintex系列FPGA作为主处理器,实现各个接口之间的数据互联、处理以及实时信号处理。板卡支持4路SFP光纤接口,支持一个PCIe x8主机接口&…

Pearson correlation coefficient (Pearson’s r) 皮尔森相关系数

此图用的是箱状图,的纵轴是“Pearson’s r”,是实际观测值与机器学习模型预测值之间的相关性 Pearsons f得分,它是一个统计量,用来衡量两个变量之间线性相关性的强度。这个得分可能是用来衡量实际观测值与机器学习模型预测值之间的…

App Inventor 2 接入短信服务,实现短信验证码功能

发送短信验证码功能一般都是基于短信平台提供的sdk进行调用,这里是基于阿里云短信平台进行的开发,阿里云短信平台接入步骤请点此参考。 App Inventor 2拓展提供的函数如下: 主要提供2个函数,生成随机位数的数字随机码 和 发送短信…

ctfshow 新手必刷菜狗杯 谜之栅栏题解记录

知识点:图片比较 拿到之后,有两个图片,直观看不出什么,尝试用工具比较。 用010editor打开其中一个,010editor的工具里面就有比较文件选项,比较两个文件,发现有一处不同。题目说栅栏&#xff0c…

《QDebug 2023年12月》

一、Qt Widgets 问题交流 1. 二、Qt Quick 问题交流 1.Q_REVISION 标记的信号槽或者 REVISION 标记的属性,在子类中访问 Q_REVISION 是 Qt 用来做版本控制的一个宏。以 QQuickWindow 为例,继承后去访问 REVISION 标记的 opacity 属性或者 Q_REVISION…

keil5修改默认配色方案

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言1. 找到Keil_5\UV4路径下的两个文件2. 修改global.prop文件中的内容第一种 配色方案第二种 配色方案第三种 配色方案第四种 配色方案 最后 前言 提示&#xff…

GPT3.5 改用 GPT4 价格翻了30倍 如何破局? GPT 对话成本推演

场景介绍 假设你搭建了一个平台,提供 ChatGPT 3.5 的聊天服务。目前已经有一批用户的使用数据,想要测算一下如果更换 GPT 4.0 服务需要多少成本? 方案阐述 如果是全切,最简单粗暴的方案就是根据提供 ChatGPT 3.5 消费的金额乘…

【FileZilla】FileZilla的使用及主动模式与被动模式----图文并茂详细讲解

目录 一 FileZilla的简介 1.1 是什么 1.2 应用场景 二 FileZilla的安装及准备工作 2.1 下载安装 2.2 主机连接VMware 三 FileZilla使用 3.1 内部连接文件管理 3.1.1 添加组 3.1.2 添加用户 3.1.3 添加用户密码 3.1.4 添加用户权限 3.1.5 连接测试 3.2 外部连接文…