1.磁盤結構
Linux中的文件加載到內存上之前是放到哪的?
放在磁盤上的文件——>訪問文件,打開它——>找到這個文件——>路徑
但文件是怎樣存儲在磁盤上的
1.1物理結構
磁盤可以理解為上百億個小磁鐵(如N為1,S為0)
清除磁盤數據:消磁——軟件、物理、化學
1.1.1磁盤的存儲結構
扇區:是磁盤存儲的基本單位,512字節,塊設備
磁頭在擺動的本質:定位磁道(柱面)
磁盤盤片旋轉的本質:定位扇區
磁盤容量 = 磁頭數* 磁道數 * 扇區數 * 每扇區字節數
如何定位一個扇區?
1.先定位磁頭(Header)
2.確定磁頭要訪問哪一個柱面(磁道)(Cylinder)
3.定位一個扇區(Sector)
4.這就是CHS地址定位法
1.2邏輯結構
1.2.1邏輯抽象
?個細節:傳動臂上的磁頭是共進退的
柱?是?個邏輯上的概念,其實就是每??上,相同半徑的磁道邏輯上構成柱?。
所以,磁盤物理上分了很多?,但是在我們看來,邏輯上,磁盤整體是由“柱?”卷起來的。
磁道:
某?盤?的某?個磁道展開
柱?:
整個磁盤所有盤?的同?個磁道,即柱?展開:即二維數組
整盤:
整個磁盤不就是多張?維的扇區數組表(三維數組?)
每?個扇區都有?個下標,我們叫做LBA(Logical Block Address)地址,其實就是線性地址。
1.2.2CHS轉LBA
LBA,1000,CHS 必須要! LBA地址轉成CHS地址,CHS如何轉換成為LBA地址?
由硬盤自己來做!固件(硬件電路,伺服系統)
CHS轉成LBA:
? 磁頭數每磁道扇區數 = 單個柱?的扇區總數
? LBA = 柱面號C * 單個柱面的扇區總數 + 磁頭號H * 每磁道扇區數 + 扇區號S - 1
LBA轉成CHS:
? 柱?號C = LBA // (磁頭數每磁道扇區數)【就是單個柱面的扇區總數】
? 磁頭號H = (LBA % (磁頭數*每磁道扇區數)) // 每磁道扇區數
? 扇區號S = (LBA % 每磁道扇區數) + 1
? “//”: 表示除取整
2.抽象理解分區,格式化
OS和磁盤進行IO的時候,以扇區為基本單位,512字節作為單次數據量,有些少。
以1KB、2KB、4KB、8KB為單位,一般以4KB數據塊——8個扇區
即一個數據庫——8個LBA地址,這樣就將磁盤轉化成了 以塊為單位的一維數組
通過將磁盤分區、分組,使用分治實現管理整個磁盤
3.Ext系列的文件系統,inode號和inode
知識點:
1.文件 = 內容+屬性
2.屬性也是數據,以結構體方式構建出來的inode
3.一個文件一個inode,inode是屬性數據的集合
在Linux中可以使用ls -l -i
命令來查看文件inode編號,找到inode就能映射到對應儲存位置Data
- Block Group:ext2 文件系統會根據分區的大小劃分為數個 Block Group。而每個 Block Group都有著相同的結構組成。
- 超級塊(Super Block):存放文件系統本身的結構信息,管理整個分區,不是每個組的super bloc都起作用。記錄的信息主要有:bolck 和inode 的總量,未使用的 block 和 inode 的數量,一個 block 和 inode的大小,最近一次掛載的時間,最近一次寫入數據的時間,最近一次檢驗磁盤的時間等其他文件系統的相關信息。
- GDT,Group Descriptor Table:塊組描述符,描述塊組屬性信息
- 塊位圖(Block Bitmap):Block Bitmap 中記錄著 Data Block中哪個數據塊已經被占用,哪個數據塊沒有被占用
- inode 位圖(inode Bitmap):每個 bit 表示一個 inode 是否空閑可用
- 節點表(inode table):存放文件屬性 如文件大小,所有者,最近修改時間等 ,如下圖inode邏輯結構
- 數據區(data blocks):存放文件內容
刪除的本質是設置inode bitmap、block bitmap,設置對應inode 、block無效
格式化:對inod bitmap、block bitmap 、GDT 、super block操作
4.理解什么叫文件,什么叫目錄,準確理解文件系統
格式化即寫入空的文件系統
GDT中存有start_inode、start_block他們是這個組包含的inode、block的起始編號。
inode號的個數、block的個數都是固定的!(先分配inode、再分配block,故不存在inode沒用完、data block用完的情況)
關于inode
1.inode以分區為單位,一套inode
2.inode分配時,只需確定起始inode即可
關于block
1.塊號也是以分區為單位統一編號的
那么如何分配一個inode、block?
inode、block都是全局的(整個分區通用的),先根據GDT中的起始編號確定組,再根據bitmap確定是否有效,再通過inode table找到inode屬性集
4.1文件的增刪查改流程
已知inode號
1.如何查找一個文件?
- 通過GDT找到分組,使用inode號 - start_inode,找到組內的位置,通過bitmap判斷該位置是否有效,再通過inode table找到inode屬性集。
2.如何刪除
- 找到文件后設置bitmap
3.如何新增
4.如何修改
- 找到文件后對inode、data block進行修改
4.2子問題1:inode和block怎么映射的
將組的設計和文件內容的設計解耦了,文件的內容可以是其他組的塊
4.3子問題2:
4.3.1.我們使用中使用的都是文件名,OS怎么拿到inode的
文件名不再inode中保存。存在哪?——文件名分為:普通文件、目錄文件——存在自己所處目錄的數據塊中
4.3.2.如何理解目錄文件
目錄 = inode + data block = 屬性 + 內容
內容:對應數據塊存儲了 文件名:inode的映射關系。因為同一個目錄中不能有同名文件,所以inode和文件名互為映射。
為什么要這樣設計?
因為文件名可長可短,inode是數字定長,OS管理時效率高。
命令
ls -ln
-ln可以將能顯示成數字的內容顯示為數字
查找文件的邏輯:
找到文件名——>打開當前目錄——>當前目錄也是文件,找到inode編號——>逆向路徑解析——>從根目錄找回去
為什么任何一個文件,都要有路徑?? 進程提供的路徑
每個進程都要有一個CWD,故 任何目標文件都有路徑
那每次打開文件都要對路徑進行逆向解析嗎?
Linux可以對路徑結構進行緩存
Linux以多叉樹的結構對操作路徑進行緩存
4.3.3.文件描述符和進程的關系
通過struct file 可以找到:
1.操作表
2.緩沖區
3.
path---dentry---inode| |
通過文件名訪問磁盤上文件的流程:
通過task_struct
找到打開的文件,通過file
中的path
找到dentry
解析文件路徑,通過自己所在目錄的data block
找到此文件的inode
,再通過inode
將磁盤中的內容映射到文件內核緩沖區
5.分區模擬掛載
怎么確認自己在哪一個分區中?(通過路徑前綴)
多個分區——>一個分區包含若干個普通目錄
|
只有分區該分區無法直接使用
分區必須經過“掛載”到目錄上,分區才可以通過路徑的方式進行訪問
df -h
可以查看磁盤信息
#復制數據
dd if=/dev/zero of=./disk.iso bs=1M count=5
#創建虛擬磁盤分區
mkfs.ext4 disk.iso
#掛載分區
mount -t ext4 ./disk.iso /mnt/myvda# #卸載分區
#umount
任何一個分區,天然有基本路徑(經過掛載,路徑+掛載點+新建目錄)
6.軟硬鏈接
ln -s file.txt file-soft.link #軟鏈接
ln file.txt file-hard.ling #硬鏈接
6.1如何理解軟硬鏈接
軟鏈接本質是一個獨立的文件,硬鏈接本質不是一個獨立的文件
a.軟鏈接沒有獨立的inode,軟鏈接內容上,保存的是文件的路徑,類似Windows的快捷方式
b.硬鏈接本質就是一組文件名和已經存在的文件的映射
6.2為什么要用軟硬鏈接?各種應用場景
軟鏈接:快捷方式(幫助快速找到指令和庫)
硬鏈接:
- 1.可以使用硬鏈接對文件進行備份
- 2.硬鏈接文件后,因為inode相同,OS會存儲inode的引用計數,目錄也有引用計數,可通過硬鏈接分析一個目錄內含幾個目錄(結合3.)
- 3.Linux不允許對目錄進行新建硬鏈接(… 和 . 被特殊處理了)(因為會形成環狀路徑,軟鏈接也會形成環狀路徑,但軟鏈接的文件類型標識為l)
7.動態庫和靜態庫
7.1靜態庫
制作靜態庫
# lib為固定前綴,.a為固定后綴 -rc:r意為replace,c意為create
ar -rc libmylib.a file1.o file2.o file3.o
使用靜態庫
方法一:安裝到系統中 一般為目錄 /lib64
# 使用-l選項:指定名稱的外部庫,庫名稱去前綴、后綴
gcc main.c -lmystdio
方法二:和源文件在同一目錄下
# -L選項告訴編譯器,編譯的時候查找庫時,除了系統路徑,也要在指明路徑下找
gcc main.c -L. -lmystdio
gcc在查找靜態(動態)庫時,不會在當前路徑下找
方法三:使用帶路徑的庫
# -I指定路徑頭文件 -L指定鏈接的目錄 -l指定鏈接哪個庫的目錄
gcc main.c -Istdc/include -Lstdc/lib -lmystdio
7.2動態庫
動態庫制作:
# -shared :不要形成可執行程序,形成.so庫
gcc -shared# -fPIC:意為 flag position ignore code
# 此指令為在.c文件編譯為.o文件時形成與位置無關碼
gcc -fPIC
動態庫的使用
方法一:安裝到系統 /lib64庫中,鏈接方式與靜態庫相同
# 此命令可以查看依賴庫
ldd a.out
方法二:和源文件在同一目錄下(與靜態庫相同,gcc查找動態庫時不會在當前路徑下查)
方法三:使用帶路徑的庫(與靜態庫相同)
7.3知識點
鏈接動態庫的程序執行程序時會顯示找不到.so庫
編譯時找動態庫是告訴編譯器庫在哪
運行時呢?OS要加載程序,系統找不到庫——靜態庫需要找嗎?不需要
如何給系統指定路徑,查找自己的動態庫
1*.拷貝到系統默認路徑下,如/lib64
2.在系統路徑,建立軟鏈接 ln
3*.Linux系統中,OS查找動態庫,修改環境變量:LD_LIBRARY_PATH(將庫路徑加入環境變量)
4.idconfig(更改系統配置文件)配置如 /etc/ld.so.confd/
若同時提供動 、靜態庫,gcc、g++默認使用動態庫,-static指明靜態鏈接
如果強制靜態鏈接,必須提供對應靜態庫
如果只提供靜態庫,但鏈接方式是動態鏈接的,gcc、g++沒得選只能針對你的.a局部性采用靜態鏈接
7.4動態庫的理解,動態庫的加載,進程地址空間
a.原理上理解動態庫(共享庫)
將動態庫映射到進程的虛擬地址空間(共享區)
進程執行庫方法時,是在自己的地址空間中跳轉執行的
8.EIF文件
8.1可執行程序格式
-可重定位?件(Relocatable File) :.o ?件。
-可執行文件(Executable File) :即可執行程序。
-共享目標文件(Shared Object File) :即 xxx.so文件
上面三種文件都屬于EIF文件,EIF文件的結構如下:
section中就是一段一段文件的內容,如:代碼區(.text)、數據區(.data)
鏈接:就是將EIF文件一段一段相同屬性的section進行合并。
對于任何文件,文件的內容就是一個巨大的一維數組
標識文件任何一個區域,可以使用 偏移量+大小
的方式
readelf
指令可以查看某個EIF文件結構
8.2地址空間——可執行程序的加載
操作系統是要認識可執行程序的,那操作系統如何管理可執行程序的的代碼的。
提出以下兩個問題
1.mm_struct中的屬性由誰初始化的?
2.可執行程序有沒有地址的存在?
8.2.1可執行程序的地址
readelf -S 或 --section -headers #顯示EIF文家節頭信息
查看EIF文件節頭信息,發現每一段匯編代碼、函數頭都有一個地址。
當代OS的可執行程序編址模式:
平坦模式:
邏輯地址 = 起始地址 + 偏移量[000···,FFF···]
故可以看出,EIF在沒有加載到內存時,已經按照[000···,FFF···]進行編址了(虛擬地址)
故編譯器編譯時,就已經形成虛擬地址了。
邏輯地址(磁盤EIF) == 虛擬地址(加載到內存中時) //故邏輯地址和虛擬地址只是兩種不同情景下的表達
執行程序時使用的是虛擬地址,執行時將Entry Point address放入PC指針,由MMU硬件(Memory Management Unit,查表邏輯在硬件電路中實現)查頁表將虛擬地址轉換為物理地址
- 故CPU出來的都是物理地址
- CR3寄存器,指向頁表的起始地址
所以,虛擬地址是操作系統、CPU、編譯器共同協作下的產物!!!
為什么要有虛擬地址和虛擬地址空間?
將編譯器與OS解耦,編譯器編址就可以以平坦模式編址了
8.2.2mm_struct中的屬性填充
mm_struct存在一條屬性mmap為分區鏈表
srtuct vm_area_struct即為虛擬地址的分區屬性,其中包含vm_start和vm_end記錄了開始和結束的地址。
鏈接動態庫到共享區,即新建vm_area_struct結構體鏈入鏈表
8.3動態庫加載的理解
我們的程序運行之前,先把所有庫加載并映射,所有庫的起始虛擬地址都應該提前知道
然后對我們加載到內存中的程序的庫函數調用進行地址修改,在內存中二次完成地址設置
(加載地址重定位)
然而,代碼區(.text)不是編譯完成后就不能修改了嗎,每次執行時動態庫的虛擬地址 = 基地址 + 偏移量,不是要修改嗎?
所以:動態鏈接采用的做法是在.data
(可執行程序或者庫自己)中專門預留一片區域用來存放函數
的跳轉地址,它也被叫做全局偏移表.GOT(Global Offset Table)
,表中每一項都是本運行模塊要引用的一個全局變量或函數的地址。代碼區調用的動態庫函數會指向此表。
所以:GOT + 庫方法偏移量,這兩種解決方案實現了與地址無關