Linux——磁盘文件的理解 + inode详解 + 软硬链接 +动静态库

news2024/11/14 14:51:14

索引

  • 磁盘文件的理解
  • inode
  • 软硬链接
  • 动静态库
    • 理解动态链接与地址无关
    • 生成动静态库
    • 使用静态库
    • 使用动态库
    • 动态链接再次理解!

磁盘文件的理解

之前讲述的都是内存级的文件,但是系统中最多的还是磁盘级的文件,大量的文件自然也需要被管理,那么如何管理呢?
我们先看几张磁盘的实物图才能更好的了解

在这里插入图片描述
如图所示,读写磁盘的时候,磁头找的是某一个面(哪一个磁头)的某一个磁道(距离圆心的半径)的某一个扇区(磁道上的一段,盘面旋转决定的)。
只要我们能找到磁盘上的盘面,柱面(磁道),然后找到扇区也就是找到一个存储单元就能读写磁盘
注:每个扇区的大小都是512字节,无论距离圆形的半径是多少
用同样的方法,我们也就能找到所有的基本单元了。
在这里插入图片描述
由于他们的英文名称,所以在物理上找某个扇区的地址叫做CHS地址
但毕竟磁盘还是物理结构,我们需要将其逻辑抽象一下。
在这里插入图片描述
如图所示,如果我们将这个磁带全部拉出来的话,就变成了一条直线,同理我们也可以把磁盘的一块块扇区拼接起来,变成一条长方形。
在这里插入图片描述
因此,定位一个扇区,只需要找到对应数组的下标就可以了,在内存中这个地址叫做LBA地址(Logic Block Address )逻辑地址
理解:内存中有个数据想向磁盘中写入的话,在内存中他只知道LBA地址,所以首先将LBA地址映射转化成CHS地址,转化成CHS地址之后,然后将内存数据配合CHS地址写入到磁盘中,至此写入就完成了。
但是磁盘的结构是硬件层面的,我们要学习的是如何管理这些磁盘上的文件。
虽然磁盘存储的基本单位扇区的大小是512字节,但是文件系统访问读写磁盘的基本单位是4kb,为什么要这样呢?

  1. 提高IO的效率
  2. 不要软件操作系统的设计和硬件磁盘具有强相关性,使得他们之间接耦合。
    万一以后硬件的一个扇区的大小设置成1024个字节,此时操作系统难道也要跟着变吗?所以操作系统不管硬件的扇区大小是多少,他只需要保持4kb的吞吐量就可以了,接耦合有利于软硬件的发展。

inode

在这里插入图片描述
在这里插入图片描述
如上所示,最左边的就是文件的inode 编号
问题:创建一个文件时,OS做了什么?
当文件在目录被创建时,Linux文件系统会根据文件名为其分配一个唯一的inode编号,然后修改inode Bitmap,在inode Table找到对应的节点然后向他里面写入对应的属性号。找到还未使用的数据块,修改Block Bitmap,将文件名和inode编号的映射关系写入到目录的数据快中!!
删除了一个文件,OS做了什么?
先找到文件名与inode对应的条目,然后找到inode编号,再根据inode编号找到对应的inode Bitmap和blockBitmap由1置0,此时就完成了文件的删除,再在文件的所在目录中将文件名与inode对应的映射关系清除,所以在linux当中文件的数据并没有被真正的删除
我知道了自己所处的目录,就能知道目录的inode吗?
不能,目录的inode在其根目录的内容中,最终得找到根目录

软硬链接

什么是软链接
软连接时第一个独立文件,拥有自己的独立inode和inode编号,主要作为Linux下的快捷方式,因为有的可执行文件或头文件或者是动静态库所在路径十分的深,如果直接运行或者是使用的话路径过深会非常麻烦,所以使用快捷方式非常容易
在这里插入图片描述
什么是硬链接?
硬链接不是一个独立的文件,他和目标文件使用的是同一个inode,就是单纯的在linux指定的目录下,给指定的文件新增文件名和inode编号的映射关系。
可以理解为一个“指针”概念,表示有几个文件名和我的inode建立的关系,有什么用呢?路径间切换
在这里插入图片描述
为什么新建目录的硬链接数是2?但是文件确实1呢?

在这里插入图片描述
可以看到当我们进入test2目录之后,其表示当前路径的.与test2的inode编号是相同的,所以说硬链接数可以用于路径间切换,一般还可以用来估算一下目录中有多少层目录。

动静态库

什么是静态库?
程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库。
优点:

  1. 性能高,程序运行时无需加载额外的库文件
    缺点
  • 占用空间大, 每个程序内部都要保留一份printf(), scanf(), strlen() 等函数还有一些辅助数据结构,所占据的内存十分大。
  • 代码的耦合度太高,如果其中的一个地方错了改动之后需要用户重新下载一遍
  • 代码重复,代码的复用率不高
    所以有了动态库
    程序在运行的时候才去链接动态库的代码,将文件根据功能还分成若干模块,降低了代码的耦合度,并且所有的程序共享使用库的代码。

理解动态链接与地址无关

理解动态链接产生与地址无关码
当进程加载到动态链接时,链接器会将库中所有的符号地址都替换成相对地址,静态链接是将库中所有的符号地址替换成绝对地址,相对地址是相对于库中某个特定基地址的偏移量,然后在运行时,进程会将这个基地址设置为虚拟地址空间中(共享区)的某个地址,从而使得动态链接库的相对地址能够正常的映射到实际的虚拟地址中。动态链接的符号地址都是相对于基地址的偏移量,所以说动态链接与地址无关,基地址是指动态链接在内存中被加载的起始地址然后再将这个基地址映射到进程的虚拟地址空间中。假设动态库的基地址为B,某个符号在动态链接库的地址为A,该符号在进程的虚拟地址空间中的地址是V,那么在运行时,进程会将动态链接库中符号地址A替换成相对地址A-B,然后将基地址B设置为V-A,从而使得动态链接库中的相对地址能够正确映射到实际的虚拟地址空间中。

生成动静态库

.o文件是一种目标文件,它是编译器将源代码编译后生成的中间文件,其中包含了已编译的机器代码,符号表和调试信息
如果我们把多个.o文件给他人,其他人链接能够使用吗?
先记录下下面的源码
mymath.h

#pragma once
#include<stdio.h>
#include<assert.h>
//[from, to] -->累加 -> result ->return
extern int addToVal(int from, int to);

myprintf.h

#pragma  once
#include<stdio.h>
#include<time.h>
extern void Print(const char *msg);

mymath.c

#include"mymath.h"
int addToVal(int from, int  to)
{
  assert(from <= to);
  int sum = 0;
  for(int i = from; i <= to; i++)
  {
    sum += from;
  }
  return sum;
}

myprintf.c

#include"myprintf.h"

 void Print(const char *msg)
{
  printf("%s : %lld\n", msg, (long long)time(NULL));
}

在这里插入图片描述
实验验证,多个.o文件与一个源文件链接在一起,会形成可执行文件,因为链接多个.o文件时,链接器会解析符号表,将不同的.o文件中定义和引用的符号进行匹配,从而形成可执行文件或共享库文件。
但是.o文件太多了,用起来特别不方便,所以我们将.o文件打包形成一个库。

生成静态库:
 10 libmymath.a:mymath_s.o myprintf_s.o
 11     ar -rc libmymath.a mymath_s.o myprintf_s.o
 12 mymath_s.o:mymath.c
 13     gcc -c mymath.c -o mymath_s.o
 14 myprintf_s.o:myprintf.c
 15     gcc -c myprintf.c -o myprintf_s.o
 ar是gnu归档工具,rc表示(replace and create)

生成动态库:
  3 libmymath.so:mymath.o myprintf.o                                                                    
  4     gcc -shared -o libmymath.so mymath.o myprintf.o
  5 mymath.o:mymath.c
  6     gcc -fPIC -c mymath.c -o mymath.o 
  7 myprintf.o:myprintf.c
  8     gcc -fPIC -c myprintf.c -o myprintf.o
  shared:表示生成共享库格式
  FPIC:产生位置无关码
  库名规则:libXXX.so

同时实现动静态库的代码

1 .PHONY:all
  2 all:libmymath.so libmymath.a
  3 libmymath.so:mymath.o myprintf.o
  4     gcc -shared -o libmymath.so mymath.o myprintf.o
  5 mymath.o:mymath.c
  6     gcc -fPIC -c mymath.c -o mymath.o 
  7 myprintf.o:myprintf.c
  8     gcc -fPIC -c myprintf.c -o myprintf.o
  9 
 10 libmymath.a:mymath_s.o myprintf_s.o
 11     ar -rc libmymath.a mymath_s.o myprintf_s.o
 12 mymath_s.o:mymath.c
 13     gcc -c mymath.c -o mymath_s.o
 14 myprintf_s.o:myprintf.c
 15     gcc -c myprintf.c -o myprintf_s.o
 16 
 17 
 18 
 19 .PHONY:lib
 20 lib: 
 21     mkdir -p lib-static/lib 
 22     mkdir -p lib-dyl/lib 
 23     mkdir -p lib-dyl/include
 24     cp *.so lib-dyl/lib 
 25     cp *.h lib-dyl/include
 26     mkdir -p lib-static/include
 27     cp *.a lib-static/lib                                                                           
 28     cp *.h lib-static/include
 29 .PHONY:clean
 30 clean:
 31     rm -rf *.o *.a lib *.so lib*

在这里插入图片描述

使用静态库

在这里插入图片描述
此时如果包含头文件然后编译运行mytest一定是错误的
在这里插入图片描述
因为库文件的搜索路径

  1. 在当前路径下查找文件,此时mytest.c包含的头文件是在lib-static中,所以不行
  2. 由环境变量指定的目录(LIBRARY_PATH)
  3. 系统默认目录
    /usr/lib
    /usr/local/lib

系统的头文件如下所示
在这里插入图片描述
系统库安装位置
在这里插入图片描述
由于我们的头文件和库文件都不在系统路径下,所以此时编译器找不到,所以一定是会报错的。

在这里插入图片描述
如上所示:如果我们此时把头文件和库文件都拷贝进系统目录的话再次编译,此时还是会报错,因为我们从来没有使用过第三方库,一直使用的都是C/C++库,所以如果我们要使用第三方库的话我们必须链接,链接名 需要去掉前缀和后缀,然后就可以了。
但是我们并不推荐安装库,会污染系统的标准库
我们还可以指定路径寻找头文件
在这里插入图片描述

使用动态库

我们一开始直接使用和上述最后一种的方法
在这里插入图片描述
为什么静态库运行的时候没有出现上述找不到库的问题?因为静态链接形成可执行程序之后,已经把需要的代码拷贝进我的代码中!运行时,不需要依赖系统中的库——不需要运行时查找
为什么动态库会有这个问题呢?
因为程序和动态库是分开加载的!
如何解决?
想办法让进程找到动态库即可!

  1. 动态库拷贝到系统路劲下 /lib64 --安装(不推荐!)
  2. 通过环境变量的方式,—程序运行的时候,会在环境变量中查找自己需要的动态库路劲 – LD_LIBRARY_PATH
  3. 系统配置文件来做
    通过导入环境变量的方式

在这里插入图片描述
这样导入环境变量只在当前shell有效,重启之后就无效了,因为shell本身启动的时候就是在配置文件里导入,说明这个指令本身是内存级别的。
通过配置文件
在这里插入图片描述
就是在/etc/ld.so.conf.d/这个路径下写一个文件然后将对应的库路径写入就可以了。因为系统寻找库路径的时候不仅会在默认路径下还会扫描这个路径(试验完记得删除!)
在系统中建立软链接查找动态库
在这里插入图片描述
此时不用指明库的路径和名称直接就可以编译运行

动态链接再次理解!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法】08 耦合 Lorenz 63 模式的参数估计实验

摘要 本实验通过建立基于耦合 Lorenz 63 模式的孪生实验框架&#xff0c;使用集合调整卡尔曼滤波器EAKF实现参数估计&#xff0c;测试参数估计开始的不同阶段、观测误差、同化频率、协方差膨胀等方法细节对于参数估计结果的影响。 耦合 Lorenz 63 模式 Lorenz 63 模式是Lore…

Postman实战:轻松搞定接口自动化测试

随着移动互联网的发展&#xff0c;接口自动化测试已经成为软件测试领域中不可或缺的一部分。而作为最流行的API开发工具之一&#xff0c;Postman凭借其简单易用、功能强大的特点赢得了越来越多开发者和测试人员的青睐。 想要掌握Postman的接口自动化测试技能&#xff0c;只需要…

JDK 下载与安装

首先下载 jdk 最新版本。可以去 http://java.sun.com/j2se/1.4.2/download.html 版本一&#xff1a;适合 win7oracle 版本 java 下载最新的 jdk 版本&#xff0c; 打开界面后。选择 J2SE v 1.4.2_08 SDK 拦目下面的 Download J2SE SDK&#xff0c; 然后选择 Accept License…

6设计指令流水线-3【FPGA模型机课程设计】

6设计指令流水线-3【FPGA模型机课程设计】 前言推荐6设计指令流水线-3安排测试与结果 指令流水线理论MIPS的一种简单实现基本的MIPS流水线 指令流水线实现MIPS五段流水CPU设计 基于单周期CPU的流水线设计乘除流水线的设计原子流水线的设计代码设计EX_Mem 附录0 框架 最后 前言 …

理论+实操|一文掌握 RFM 模型在客户数据洞察平台内的落地实战

确定用户价值是整个用户运营过程中极其重要的一环。传统的工作流程中&#xff0c;业务人员向数据部门提出数据需求&#xff0c;等待返回结果后再进行价值分析是主要的准备工作&#xff0c;但这个过程非常耗时。为了提高工作效率&#xff0c;业务人员经常会基于自己对用户的理解…

链表【+逆序链表】、循环队列、堆栈讲解(链表头和尾插法)

文章目录 一、链表&#xff08;1&#xff09;链表简单介绍&#xff08;2&#xff09;链表的创建&#xff08;3&#xff09;数据的插入【1】头插法【2】尾插法 &#xff08;4&#xff09;链表的删除&#xff08;5&#xff09;源代码实现 二、队列&#xff08;循环队列&#xff0…

热闹炸了,公司居然公然鼓励员工玩游戏

池塘边的榕树上&#xff0c;知了在声声叫着夏天&#xff0c;操场边的秋千上&#xff0c;只有蝴蝶停在上面..........每逢儿童节到来之时&#xff0c;东东总是会回想起儿时的自己&#xff0c;面对那即将到来的节日&#xff0c;兴奋异常。 因为在这一天全校会给我们放上一天假&am…

Android进阶之路 - 字体阴影、文字阴影

最近几个月都挺忙&#xff0c;忙着工作&#xff0c;忙着成长… 一直以来我认为在开发中首当其冲的肯定是需求、功能&#xff0c;然后才是UI细节&#xff1b;所以我自己一般不太会去深究一些看不明显的UI&#xff0c;不过这俩日同事提醒我文字有阴影效果&#xff0c;细看之下果然…

Java000——超好用的工具推荐

下面介绍工具直接安装即可&#xff0c;基本上都是一路next&#xff08;有需要选择安装路径则选择自己的安装目录即可&#xff09; Everything Everything用于搜索电脑本地文件、文件夹&#xff0c;快速高效 下载地址 Snipaste截图工具 下载地址 notepad 轻量级文本编写查看…

C++11 右值引用

文章目录 一. 左值&#xff1f;右值&#xff1f;二. 右值引用的使用三. 万能引用&完美转发四. 移动构造&移动赋值结束语 一. 左值&#xff1f;右值&#xff1f; C中&#xff0c;对于左值&#xff0c;右值&#xff0c;我们可能会理解为 赋值符号左边是左值&#xff0c…

木棒 DFS经典题 剪枝优化 满注释版 java

&#x1f351; 算法题解专栏 &#x1f351; 题目地址 乔治拿来一组等长的木棒&#xff0c;将它们随机地砍断&#xff0c;使得每一节木棍的长度都不超过 50 50 50 个长度单位。 然后他又想把这些木棍恢复到为裁截前的状态&#xff0c;但忘记了初始时有多少木棒以及木棒的初始…

【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;数据结构与算法 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 前言 一、最小生成树的概念 二、最小生成树的求解方法 三、练习题 四、最小生成树在实际应用中的例…

返回类对象时,什么时候调用拷贝构造函数,什么时候会进行返回值优化(RVO)

#include<iostream> using namespace std;class Person { public:Person(){}Person(int age){m_Age age;}Person(const Person& p){cout << "拷贝构造函数" << endl;}Person fun(){cout << "fun this" << " "…

一步步教你如何剪辑出专业水平的视频

1. 视频字幕制作。媒体梦工厂软件提供了强大的字幕制作功能&#xff0c;可以自主设计字幕的颜色、大小、字体等属性&#xff0c;使字幕更加具有视觉冲击力。"媒体梦工厂软件是一款广受欢迎的影视后期制作软件&#xff0c;自从软件发布以来在行业内有着广泛的应用。本文将会…

使用redis模拟手机验证码发送及消费者与生产者案例

规定一个手机号一天只能请求三次验证码&#xff0c;且每次请求的验证码只有一分钟就会过期 package com.doit.demo;import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;import java.util.Random; import java.util.Scanner;public class PhoneNum {publ…

Spark基础入门篇 | MapReduce原理 + Spark原理 + PySpark环境搭建 + 简单实战

&#x1f604; 之前简单了解过Spark&#xff0c;并简单用别人的代码跑过pyspark的数据处理和模型的分布式推理&#xff0c;但没做系统的总结&#xff0c;那这篇博客就对Spark做个基础入门讲解&#xff0c;看完基本就算基础入门了&#xff0c;后面再实操就会轻松一些。 文章目录…

Windows本地提权 · 下篇

Windows本地提权&#xff0c;这种提权适用于有一本地个用户的基础上&#xff0c;有一定的权限&#xff0c;无法从webshell上进行提权 目录 BypassUAC提权 原理 关于UAC MFS绕过提权 UAC等级为低绕过测试 UAC等级为中绕过测试 UAC等级为高绕过测试 注意&#xff1a;bypa…

【综述】视频无监督域自适应(VUDA)的小综述

【综述】视频无监督域自适应&#xff08;VUDA&#xff09;的小综述 一篇小综述&#xff0c;大家看个乐子就好&#xff0c;参考文献来自于一篇综述性论文 链接&#xff1a;https://arxiv.org/abs/2211.10412 这次基于三篇有代表性的文章来讲解 X. Song, S. Zhao, J. Yang, H.…

第十篇、基于Arduino uno,用LCD1602(不带IIC的)显示屏显示字符——结果导向

0、结果 说明&#xff1a;可以在LCD1602屏幕上面显示字符&#xff0c;实时的变量&#xff0c;如果是你想要的&#xff0c;可以接着往下看。 1、外观 说明&#xff1a;注意是不带IIC通讯的LCD屏幕&#xff0c;外形如下。 2、连线 说明&#xff1a;需要连接十几根线。 uno——…

#机器学习--深度学习中的优化

#机器学习--深度学习中的优化 引言1、神经网络优化中的挑战1.1、病态1.2、局部极小值1.3、高原、鞍点和其它平坦区域1.4、悬崖1.5、长期依赖、梯度消失与梯度爆炸1.6、非精确梯度1.7、局部和全局结构间的弱对应1.8、优化的理论限制 2、优化算法2.1、随机梯度下降&#xff08;SG…