- 前言
- Intel四級頁表
- 實操尋址
- 獲取cr3
- 獲取PGD
- 獲取PUD
- 獲取PMD
- 獲取PTE
- 獲取內容
- 最後
Linux四級頁表的做用主要就是地址映射, 將邏輯地址映射到物理地址. 不少時候, 有些地方想不明白就能夠查看實際物理地址進行分析.bash
其實不少設計的根源或者說緣由都來自於CPU的設計, OS不少時候都是輔助CPU. Linux的四級頁表就是依據CPU的四級頁表來設計的. 這裏主要說的就是Intel x64頁面大小爲4KB的狀況, 如圖所示:工具
固然, 你能夠用指令確認下:ui
getconf PAGE_SIZE
複製代碼
首先這裏先貼出幾個工具, fileview, dram, registers. 這些都是能夠幫助快速獲取地址的, 上一篇文章說的kgdb工具也是能夠的, 就是麻煩一點, 你懂的. 具體內容就不貼了, 這裏僅展現用戶態的代碼:google
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#define BUFSIZE 4096
int main()
{
int fd, ret;
char buf[BUFSIZE];
unsigned long int a = 0x1234567890abcdef;
printf( "a=0x%016lX addr: %p \n", a, &a );
if ( (fd = open( "/proc/registers", O_RDONLY ) ) < 0 )
{
fprintf( stderr, "Open /proc/registers file failed! \n" );
exit( EXIT_FAILURE );
}
lseek( fd, 0L, SEEK_SET );
if ( (ret = read( fd, buf, sizeof buf - 1 ) ) < 0 )
{
perror( "/proc/registers" );
exit( EXIT_FAILURE );
}
buf[ret] = 0;
close( fd );
puts( buf );
while ( 1 );
return(0);
}
複製代碼
使用make指令編譯工具, 插入dram.ko和registers.ko驅動模塊. 編譯運行用戶態程序, 如圖所示:spa
這之中最關鍵的是cr3地址以及局部變量地址, 這裏看到, 變量地址是0x7ffdcbffaba8, 變量值是0x1234567890ABCDEF. cr3寄存器中地址是0x40c78000. 固然了, 按照CPU的圖示, cr3確定是指向PML4E. 在Linux當中, 第一級頁表稱爲PGD, 固然是有歷史緣由的, 能夠自行google. 因此Linux的四級頁表分別是PGD -> PUD -> PMD -> PTE.設計
想要獲取PGD中的內容須要經過計算. 這裏先來處理一下局部變量地址. 首先寫成二進制.3d
0x7ffdcbffaba8
0111 1111 1111 1101 1100 1011 1111 1111 1010 1011 1010 1000
複製代碼
而後按照Intel的設計, 從新整合.code
011111111 111110111 001011111 111111010 101110101000
複製代碼
從新寫成16進制:cdn
ff 1f7 5f 1fa ba8
複製代碼
這就是隻要用的offset. 由於每一個單元是64-bits所以須要在序號基礎上乘以8得到地址. 因此PGD地址爲:blog
0x40c78000(cr3) + ff * 8 = 0x40c787f8
複製代碼
而後使用啓動以前編譯的小工具:
./fileview /dev/dram
複製代碼
輸入以前計算出來的地址0x40c787f8, 就能夠獲得之中的內容, 也就是PUD, 從CPU圖來講就是PDPTE:
這裏獲取到的是67 50 75 76 00 00 00 80, 可是注意, Intel是和顯示順序反過來的. 也就是76755067, 而後後面的12-bits是頁面屬性. 因此, 具體地址就是:
76755000 + 1f7 * 8 = 76755fb8
複製代碼
一樣輸入地址到工具, 獲得67 80 E8 2C 00 00 00 00.
直接計算了:
2ce88000 + 5f * 8 = 2ce882f8
複製代碼
獲得67 00 DD 48 00 00 00 00.
直接計算了:
48dd0000 + 1fa * 8 = 48dd0fd0
複製代碼
獲得67 58 59 20 00 00 00 80.
最後就能夠獲取到內容了:
20595000 + ba8 = 20595ba8
複製代碼
固然了, 此次是在用戶態下進行從線性地址到物理地址轉換的, 若是是內核態有些地方會發生變化. 暫時寫到這裏, 內核態等後續的更新了. 喜歡記得點贊, 有意見或者建議評論區見~