Linux 文件系统、动静态库

个人主页仍有未知等待探索-CSDN博客

专题分栏: Linux

目录

一、文件系统

1、了解磁盘的存储结构

1.基本知识

2.磁盘中盘片为什么高速旋转?

3.磁头为什么要左右摇摆?

4.如何找到一个指定位置的扇区?

5.文件在磁盘中怎么存储?

2、磁盘存储的抽象

1.为什么OS不直接用CHS?

2.逻辑抽象

3.管理磁盘文件

Block group里面的属性

查找文件的顺序

关于inode number

关于目录

为什么目录文件中不允许有同名文件?

如何拿到inode number的?

怎么确认inode到底再哪个分区?

怎么删除一个文件?

回收站

分区格式化

目录通常是谁提供的?

Linux内核在被使用的时候,一定存在大量的解析完毕的路径,要不要对访问的路径做管理?

二、动静态库

1、软硬连接

1.软连接

2.硬连接

3.软硬连接的区别

4.软连接有什么用?

5.硬连接有什么用?

6.定位一个文件,只有两种方式?

7.磁盘中文件的引用计数

8.文件系统会不会有环路问题

9.文本文件写入和二进制文件写入

2、动静态库

1.标准库

2.动静态库

3.静态库

什么是静态库:

生成静态库:

为什么要有静态库和动态库呢?

形成可执行程序(浅):

1、第一种方式:

2、第二种方式:

形成可执行程序(深):

第一种方式:

系统里面的标准库为什么编译的时候就不需要再带上标准库了呢?

如何将第三方库设置成标准库?

第二种方式:

 4.动态库

生成动态库

生成可执行程序:

这样直接进行运行是有问题的。

为什么静态库这样写就没有问题呢?

那如何将代码运行的时候查找默认的动态库位置改变呢?

动态库加载 --- 可执行程序和地址空间

理解

当可执行程序编译成功后,没有加载运行,二进制代码中有“地址”吗?

ELF格式的可执行程序

关于编址

程序的加载

动态库的加载


一、文件系统

  • 没有被打开的文件,在磁盘中存放。 --- 磁盘文件
  • 打开一个文件 ---> 需要找到文件 ---> 在磁盘中寻找 ---> 通过文件路径 + 文件名。
  • 计算机只认识二进制。
  • 什么是0,1?计算机规定出来的,在物理上会有不同的表现形式。

1、了解磁盘的存储结构

1.基本知识

  • 磁盘的本质是机械设备,外设,慢,但是性价比高。
  • 盘片:可读可写可擦除,一片两面都可以写,一面一个磁头。
  • 磁盘读写的基本单位是扇区:512字节。
  • 1片磁盘 = n 个磁道,1个磁道 = n 个扇区。

2.磁盘中盘片为什么高速旋转?

定位扇区。

3.磁头为什么要左右摇摆?

定位磁道。

4.如何找到一个指定位置的扇区?

  1. 找到指定磁头。 --- H(Head,磁头)
  2. 找到指定磁道。 --- C(Cylinder,柱面)
  3. 找到指定扇区。 --- S(Sector,扇区)

5.文件在磁盘中怎么存储?

其实就是文件在磁盘中占据几个扇区的问题。

2、磁盘存储的抽象

1.为什么OS不直接用CHS?

  1. 耦合度太高。
  2. 不便于实现内核进行磁盘管理。

2.逻辑抽象

  • 把磁盘想成矩形,每个小格子就是一个扇区。
  • os和磁盘交互的时候,基本单位是4KB == 8 * sector(8个连续的扇区 --- 块大小)。

  • 文件 = 很多的块构成 = 很多个LBA地址。
  • 块号 * 8(8个连续的扇区) = 下标。
  • 所以只要知道一个起始块号,和磁盘的总大小,有多少块,每个块的块号,如果转换到对应的多个CSH地址,就全都知道了。
  • LBA:逻辑区块地址。

所以,对整个的磁盘管理好,只需要把其中一个分区管理好就行。

3.管理磁盘文件

  • 文件 = 内容(数据) + 属性(数据)。
  • 在Linux中,文件的内容和属性单独存放。

分区->写入文件系统(格式化)->挂在到指定的目录下->进入该目录->在指定的分区中进行文件操作。

一个文件在访问前,都是先有目录的!!!

Block group里面的属性

1、Data blocks --- 数据区

存放文件内容。

2、Block Bitmap --- 块位图

记录Data Blocks中哪个数据块已经被占用。

比特位的位置表示块号,比特位的内容表示该块是否被占用。

通常用于创建,删除文件等等。

3、inode Bitmap --- inode位图

记录inode table里面指定位置是否存储了文件。

比特位的位置表示第几个inode(inode number),比特位的内容表示该inode是否被占用。

4、inode Table --- inode表

存放文件的属性,如文件大小,所有者,最近修改时间等。

Linux中文件的属性是一个大小固定的集合体 --- 128字节。

一个文件一个inode

inode内部,不包含文件名!在内核层面。每一个文件,都要有inode number!我们通过inode号标识一个文件。

5、GDT(Group Descriptor Table) --- 块组描述符

描述块组属性信息,如块内剩余内存的大小,块组的inode范围等。

6、Super Block --- 超级块

存放文件系统本身的结构信息。

记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。

Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。但不是只有一个,在整个文件系统中,可能有多个,但是信息要保持一致。

查找文件的顺序
  1. 确定分区:确定分区(根据路径)。
  2. 获取inode number:获得inode编号(根据文件名和inode的映射关系)。
  3. 确定分组:根据分区里面每个组的inode范围,确定具体分组。
  4. 相对inode number:inode编号 - 该组的起始inode编号,得到相对的inode编号。
  5. 判断inode number的合法性:再根据相对的inode编号查找inode Bitmap,查看文件编号是否合法,为1就合法。
  6. 查找数据块:如果合法,查找inode table表,找到inode对应的数据。
  7. 读取数据:使用从inode中获取的数据块信息,文件系统会从磁盘上读取相应的数据块,并将数据返回给请求者。
关于inode number

我们寻找文件的时候,都必须先得到文件的inode号。

  • inode编号是以分区为单位。

  • inode号不能跨分区访问,因为不同区之前,inode号可能重复。

  • super block和GDT记录的都是inode number范围,start_inode, end_inode。区别就是super block记录的是整个分组的inode number范围,GDT记录的是这一个分组的inode number范围。

  • 查找inode number是再目录文件的data blocks里面,找到文件名和inode numer的映射关系。

关于目录
  • 目录也是文件,也有自己的属性和内容。
  • 目录也有inode number。根目录的inode number是系统默认的。
  • 目录文件的内容中:文件名和inode number的映射关系
  • 目录的 r 权限:本质是是否允许我们读取目录的内容。
  • 目录的 w 权限:新建文件的时候,本质上,最后一定要向当前所处目录内容中写入,文件名和inode的映射关系。
为什么目录文件中不允许有同名文件?

因为文件系统要建立文件名和inode编号的映射关系。

如何拿到inode number的?

普通文件:根据文件名和inode的映射关系。

目录文件:根据上级目录文件的内容查找。如果上级目录的inode number也不知道,就继续往上面进行查找,直到到根目录为止。(根目录的inode numer由系统默认的,逆向的路径解析。)

怎么确认inode到底再哪个分区?

1、文件在哪个目录里,就在哪个分区下。

2、就是根据路径可以判断在哪个分区下。

怎么删除一个文件?

先根据文件名得到inode number,然后只需要把对应的位图inode bitmap,由1置0。

回收站

回收站的本质其实是一个目录。

分区格式化

在每一个分区内部分组,然后写入文件系统的管理数据 ---> 在磁盘中写入文件系统!

目录通常是谁提供的?

内核文件系统提前写入并组织好,然后进程提供的。

Linux内核在被使用的时候,一定存在大量的解析完毕的路径,要不要对访问的路径做管理?

要,先描述,再组织。

一个文件一个struct dentry --- 路径解析信息。

二、动静态库

1、软硬连接

1.软连接

ln -s filename1 filename2   (后者连接前者。)

类似于Windows里面的快捷方式。

这是两个单独的文件,因为inode不同。

2.硬连接

 ln filename1 filename2

3.软硬连接的区别

 1、软连接是一个独立的文件,因为有独立的inode number。

软连接的内容:目标文件所对应的路径字符串。(类似于windows中的快捷方式)

2、硬链接不是一个独立的文件 --- 因为inode number一样。

硬链接就是一个文件名和inode的映射关系,建立硬链接,就是在指定目录下,添加一个新的文件名和inode映射关系。

3、属性中有一列硬连接数(第三列)。

磁盘级的引用计数,有多少个文件名字符串通过inode number指向我,引用计数就是几。

目录文件中目录个数 = 引用计数 - 2。

4.软连接有什么用?

就是快捷方式。

5.硬连接有什么用?

1、构建Linux的路径结构,让我们可以使用. ..来进行路径定位(文件系统默认的,用户没有权限构建. ..的路径结构)。

2、一般用硬链接来做文件备份。

6.定位一个文件,只有两种方式?

1、通过路径。

2、直接找到目标文件的inode。

7.磁盘中文件的引用计数

任何一个目录,刚开始新建的时候,引用计数一定是2,任何一个目录,新建一个目录,就会让A目录的引用计数自动+1,一个目录内部有几个目录:A引用计数-2。

Linux系统中,不允许给目录建立硬链接。

8.文件系统会不会有环路问题

不会,因为文件名是固定的。所有的系统指令在设定时候,几乎就能知道. ..是干什么的。

9.文本文件写入和二进制文件写入

文本写入和二进制写入本质上是一样的,文本写入只是语言层转换的。

2、动静态库

1.标准库

C语言标准库:libc.so.6

C++标准库:libstdc++.so.6

2.动静态库

Linux:      .so(动态库) .a(静态库)

Windows:.dll(动态库) .lib(静态库)

头文件是一个手册,提供函数的声明,告诉用户怎么用。

.o提供实现,我们只需要补上一个main,调用头文件提供的方法,然后和.o进行连接,就能形成可执行程序。

只需要math.o和main.c就可以生成可执行程序。

3.静态库

什么是静态库:

本质就是把.o文件打包。

生成静态库:

意思就是将所有的.o为后缀的文件进行打包,生成静态库mylibc.a。

-rc(replace and create):存在了就覆盖,不存在就创建。

生成的库文件的名字是:myc(去掉前缀lib,去掉后缀.a)

为什么要有静态库和动态库呢?

提高开发效率。

形成可执行程序(浅):

1、第一种方式:

2、第二种方式:

        

形成可执行程序(深):
第一种方式:

这种方式不推荐!!!

系统里面的标准库为什么编译的时候就不需要再带上标准库了呢?

因为系统会默认的去特定的位置去寻找标准库。

如何将第三方库设置成标准库?

只需要将第三方库下载到本地的/lib64;将第三方库的头文件下载到本地的/usr/include。

这样就可以正常编译了。

加上-l(小写L)选项,后面跟着第三方库的名称(去掉前缀,后缀剩下的部分)。

例如:静态库(libmyc.a),它的名称就是myc。

// 1、gcc main.c -lmyc
// 2、gcc main.c -l myc
第二种方式:

通过自己指定库的路径的方式,来对库进行查找。

要多加两个选项来进行定位:-L(大写i)+库文件路径;-I+头文件路径。

gcc main.c -I /usr/include -L /lib64 -l myc

 4.动态库

当gcc编译的时候,没有指明-static时,默认生成的就是动态连接,如果没有动态库(有静态库),就生成静态连接。

生成动态库

先生成.o文件。

// -fPIC的作用是,产生位置无关码。

gcc -fPIC -c *.c

然后再将.o文件打包生成动态库。

gcc -shared *.o libmyc.so
生成可执行程序:
这样直接进行运行是有问题的。

--- 因为在运行的时候,操作系统不知道库文件的位置

1、生成动态库。

2、进行编译。(gcc中选项 -I (大写i),指定用户自定义头文件路径,-L 指定用户自定库文件路径,-l(小写L)执行确定的第三方库名称。)

3、运行。

为什么静态库这样写就没有问题呢?

因为动态库要在程序运行的时候,要找到动态库加载并运行。静态库没有这种问题的原因是编译期间,已经将库中的代码拷贝到我们的可执行程序内部了,加载和库就没有什么关系了。

那如何将代码运行的时候查找默认的动态库位置改变呢?

1、直接将第三方动态库拷贝到默认的动态库位置(/lib64)。这种方式简单粗暴的方法,不建议。--- 安装到系统

2、在默认的标准库中建立一个软连接和第三方库连接上。 --- 建立软连接

3、修改环境变量:LD_LIBRARY_PATH --- 动态库的搜索路径。但是环境变量是内存级别的,当关掉xshell之后,环境变量将恢复默认。 --- 命令行导入环境变量

4、直接在.bashrc中修改LD_LIBRARY_PATH的路径,这样每次重启环境变量LD_LIBRARY_PATH则会变成你修改后的值。---修改配置文件.bashrc,让环境变量永久生效。

5、/etc/ld.so.conf.d配置文件,在该路径底下创建一个.conf的配置文件,里面写入第三方动态库的路径。然后再让该配置文件生效:ldconfig指令。--- /etc/ld.so.conf.d新增动态库搜索的配置文件,ldconfig

动态库加载 --- 可执行程序和地址空间
理解
  • 动态库会在磁盘中加载到内存中,然后会在mm_struct中的共享区开辟一段空间,将物理内存和mm_struct根据页表进行映射。
  • 可执行程序也会加载到内存中,和mm_struct中的正文区通过页表进行映射。
  • 当可执行程序调用一个函数的时候,就会去共享区进行寻找其函数定义。
  • 如果有两个可执行程序,动态库不需要加载两份。
当可执行程序编译成功后,没有加载运行,二进制代码中有“地址”吗?

包含了地址。

ELF格式的可执行程序
  • 所谓的二进制是有自己的固定格式的。
  • ELF可执行程序的头部,可执行程序的属性。
  • 可执行程序编译之后,会变成很多行汇编语句,每条汇编语句都有他自己的地址。
  • ELF + 加载器 ---> 会得到各个区域(代码区等等)的起始地址和结束地址,也会得到main函数的起始地址。
关于编址
  • 编址范围:从00000...0000 ~ FFF...FFFFF。
  • 地址的种类:绝对编址 --- 平坦模式;相对编址。
程序的加载

1、进程创建阶段,初始化地址空间,让cpu知道main函数的入口地址。

2、加载-> 每一行代码和数据,就都有了物理地址,自己的虚拟地址也知道,就可以开始构建映射了。

动态库的加载
  • 库被映射到虚拟地址空间的什么位置,不重要。因为映射完了,函数虚拟地址相当于是偏移量。 --- 与地址无关
  • 库函数调用,其实也是在地址空间内来回的跳转。
  • 怎么知道库有没有被加载?系统中有一个描述库的结构体的链表。

谢谢大家!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仍有未知等待探索

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值