专题分栏:Linux
目录
[Block group里面的属性](#Block group里面的属性)
[关于inode number](#关于inode number)
[如何拿到inode number的?](#如何拿到inode number的?)
Linux内核在被使用的时候,一定存在大量的解析完毕的路径,要不要对访问的路径做管理?
[动态库加载 --- 可执行程序和地址空间](#动态库加载 --- 可执行程序和地址空间)
当可执行程序编译成功后,没有加载运行,二进制代码中有"地址"吗?
一、文件系统
- 没有被打开的文件,在磁盘中存放。 --- 磁盘文件
- 打开一个文件 ---> 需要找到文件 ---> 在磁盘中寻找 ---> 通过文件路径 + 文件名。
- 计算机只认识二进制。
- 什么是0,1?计算机规定出来的,在物理上会有不同的表现形式。
1、了解磁盘的存储结构
1.基本知识
- 磁盘的本质是机械设备,外设,慢,但是性价比高。
- 盘片:可读可写可擦除,一片两面都可以写,一面一个磁头。
- 磁盘读写的基本单位是扇区:512字节。
- 1片磁盘 = n 个磁道,1个磁道 = n 个扇区。
2.磁盘中盘片为什么高速旋转?
定位扇区。
3.磁头为什么要左右摇摆?
定位磁道。
4.如何找到一个指定位置的扇区?
- 找到指定磁头。 --- H(Head,磁头)
- 找到指定磁道。 --- C(Cylinder,柱面)
- 找到指定扇区。 --- S(Sector,扇区)
5.文件在磁盘中怎么存储?
其实就是文件在磁盘中占据几个扇区的问题。
2、磁盘存储的抽象
1.为什么OS不直接用CHS?
- 耦合度太高。
- 不便于实现内核进行磁盘管理。
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的信息被破坏,可以说整个文件系统结构就被破坏了。但不是只有一个,在整个文件系统中,可能有多个,但是信息要保持一致。
查找文件的顺序
- **确定分区:**确定分区(根据路径)。
- **获取inode number:**获得inode编号(根据文件名和inode的映射关系)。
- **确定分组:**根据分区里面每个组的inode范围,确定具体分组。
- **相对inode number:**inode编号 - 该组的起始inode编号,得到相对的inode编号。
- **判断inode number的合法性:**再根据相对的inode编号查找inode Bitmap,查看文件编号是否合法,为1就合法。
- **查找数据块:**如果合法,查找inode table表,找到inode对应的数据。
- **读取数据:**使用从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。
cpp// 1、gcc main.c -lmyc // 2、gcc main.c -l myc
第二种方式:
通过自己指定库的路径的方式,来对库进行查找。
要多加两个选项来进行定位:-L(大写i)+库文件路径;-I+头文件路径。
cppgcc main.c -I /usr/include -L /lib64 -l myc
4.动态库
当gcc编译的时候,没有指明-static时,默认生成的就是动态连接,如果没有动态库(有静态库),就生成静态连接。
生成动态库
先生成.o文件。
// -fPIC的作用是,产生位置无关码。
cppgcc -fPIC -c *.c
然后再将.o文件打包生成动态库。
cppgcc -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、加载-> 每一行代码和数据,就都有了物理地址,自己的虚拟地址也知道,就可以开始构建映射了。
动态库的加载
- 库被映射到虚拟地址空间的什么位置,不重要。因为映射完了,函数虚拟地址相当于是偏移量。 --- 与地址无关。
- 库函数调用,其实也是在地址空间内来回的跳转。
- 怎么知道库有没有被加载?系统中有一个描述库的结构体的链表。
谢谢大家!!!