国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Linux > 正文

在 linux x86-32 模式下分析內存映射流程

2024-06-28 13:22:10
字體:
來源:轉載
供稿:網友
在 linux x86-32 模式下分析內存映射流程前言

虛擬內存機制已經成為了現代操作系統所不可缺少的一部分, 不僅可以為每個程序提供獨立的地址空間保證安全性,更可以通過和磁盤的內存交換來提高內存的使用效率。虛擬內存管理作為linux 上的重要組成部分代碼非常龐大。這次并不是探明 linux 源碼級的內存映射,而是通過實例來驗證 x86-32 下的虛擬內存轉換流程。

映射流程簡述

x86-32 模式下的內存映射分為2部分, 分段和分頁。之所以使用 2 步映射更多的是歷史兼容原因。

編譯出的匯編代碼里使用的是邏輯地址,表示形式為 [段標識符:段內偏移量], 在默認情形下可以省略段標識符,直接給出段內偏移即可。段標識符共有 6 個,分別是(CS, DS, SS, ES, FS, GS), 每個都有自己的含義。

邏輯地址經過 "分段" 會轉換為 線性地址,從我之前的文章可以看出,分段機制現在已經不實際使用了,在linux 中使用的分段模式為 “扁平模式”, 即邏輯地址和線性地址是一樣的。

從線性地址轉換為實際物理地址的過程稱為 "分頁"。分頁才是實際的虛擬地址轉換。分頁過程中使用了可迭代的頁表機制,操作系統為每個程序維護獨立的一組頁表來保證程序之間的互不干涉。

因為本文是反向驗證的流程,所以并不會仔細介紹整個映射流程,需要對虛擬內存機制有一定的了解。

驗證方案

本文整個流程參考了網上的另一篇文章,我會在文章末尾列出鏈接。

因為每個程序的相關資源都是獨立的,必須要保證程序的運行不能終止,且要在程序中輸出自己的相關寄存器狀態。大部分寄存器的訪問特權只支持在內核獲取,不能在用戶程序中獲取,我們要編寫相關模塊運行于內核,通過linux 的 /PRoc 文件系統將參數傳遞到用戶程序。

同時也要驗證我們通過手動映射流程獲得的物理地址是否就是程序內地址,要有工具能夠直接查看指定物理地址的數據。我們編寫一個字符設備來處理應用程序的請求,通過 kmap 函數將指定物理地址頁臨時映射獲取其數據。

最終需要程序為 4 個,如下所示。

程序功能
sys_reg.ko加載到內核,讀取相關寄存器, 建立 /proc/sys_reg 文件
running-prog測試程序,需要一直運行,讀取 /proc/sys_reg 來打印本程序相關寄存器值
phy_mem.ko加載到內核,讀取指定物理地址數據,建立 /dev/phy_mem 文件
read-phy-mem通過 /dev/phy_mem 來獲取指定物理地址數據并打印
驗證過程編譯加載

編譯文件,加載 sys_reg.ko, phy_mem.ko 模塊

運行 running-prog

運行后可以得到以下輸出:

可以看到變量 a, 這就是我們要尋找物理地址的變量,其數據和地址都以及輸出了。

分段機制

通過 CR0.PG ,可以看出系統已經打開了分頁機制。 變量 a 定在了數據段, 通過 ds 段寄存器的值可以看出使用的是 GDT ,entry 是 15. GDTR 的基址是 0xF7386000, 注意這里是線性地址, linux 內核的地址映射偏移量是 0xC0000000, 然后獲得 使用的 GDT entry地址如下。

0xF7386000 - 0xC0000000 + 15 * 8 = 0x37386078

通過獲得的 GDT entry值和 gdt entry 格式,可以知道該分段的參數:

name
base0x00000000
limit0xfffff
G1

可以看出段基址是 0x00000000, G和limit決定了該段是 4G 大小。所以從邏輯地址獲得變量 a 的線性地址如下:

0x0804A044 + 0x00000000 = 0x0804A044;

分頁機制

因為 CR4.PAE = 1,說明系統開啟了 PAE(物理地址擴展). PAE 模式下的分頁有如下 2 種。

寄存器及 entry 格式如下:

此時 CR3 中的基址就是 PDPTE 的基址 0x1EF49000, 變量 a 線性地址的bit 31-30 代表了 PDPTE 的序號。 我們可以算出 使用的 PDPTE 地址:

0x1EF49000 + 0 * 8 = 0x1EF49000

可以看到 page directory 的基址為 0x1ec9f000, 使用線性地址中的 bits 29~ 21 來確定偏移為 0x40, 所以使用的 PDE 地址為

0x1EC9F000 + 0x40 * 8 = 0x1EC9F200

PDE 為 0x0000000020A36067, bit7 = 0,說明指向的是 page table, page table 地址為0x20A36000, 使用線性地址的 bits 20~12 作為偏移為 0x4A, 使用的 PTE 地址為

0x20A36000 + 0x4A * 8 = 0x20A36250

PTE 為 0x000000000B628067, 得到了最終的 4K page frame 基址為 0x0B628000, 使用線性地址的 bits 11~0 作為偏移為 0x44, 我們計算出的 變量 a 的物理地址為

0x0B628000 + 0x44 = 0x0B628044

我們看到了數據 0x013579BB, 說明我們正確找到了 a 的物理地址,反向驗證了 linux 在 x86-32 模式下開啟了 PAE 后的線性地址映射。

結束

感謝 Linux內存地址映射 一文,我的整個流程參考了原作者的文檔和代碼, 謝謝原作者的分享。

下面是源代碼鏈接.study-linux-vm-32bit


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 东安县| 江西省| 伊吾县| 长沙市| 红原县| 周宁县| 嘉定区| 黑龙江省| 綦江县| 霍州市| 罗平县| 锡林浩特市| 唐海县| 冀州市| 莎车县| 共和县| 天全县| 威海市| 原平市| 宝坻区| 汝城县| 台湾省| 杭州市| 商水县| 龙胜| 衡阳县| 邻水| 报价| 池州市| 万源市| 台山市| 黄石市| 台山市| 上虞市| 全南县| 马鞍山市| 仁寿县| 长葛市| 玛曲县| 大安市| 兴业县|