1. 程式人生 > >Linux 核心中邏輯地址/虛擬地址/線性地址三者的區別

Linux 核心中邏輯地址/虛擬地址/線性地址三者的區別

為了防止歧義,以下術語都用英文。部分術語不做解釋了,不然答案就太長了。

以下講解都是以程式碼段為例

在 Intel 平臺下,邏輯地址(logical address)是 selector:offset 這種形式,selector 是 CS 暫存器的值,offset 是 EIP 暫存器的值。如果用 selector 去 GDT( 全域性描述符表 ) 裡拿到 segment base address(段基址) 然後加上 offset(段內偏移),這就得到了 linear address。我們把這個過程稱作段式記憶體管理

如果再把 linear address 切成四段,用前三段分別作為索引去PGD、PMD、Page Table裡查表,最終就會得到一個頁表項(Page Table Entry),那裡面的值就是一頁實體記憶體的起始地址,把它加上 linear address 切分之後第四段的內容(又叫頁內偏移)就得到了最終的 physical address。我們把這個過程稱作頁式記憶體管理

問題來了,為什麼沒提到 virtual address,這是個什麼東西?其實在 Intel IA-32 手冊裡並沒有提到這個術語,但是在核心的確是用到了這個概念,比如__va和__pa這兩個巨集定義。看似神祕的 virtual address 究其本質就是程式裡面使用的地址比如一個指標值,指標的本質就是 EIP 暫存器裡的值,說直白點,virtual address 就是 EIP 暫存器的值。你會發現我們上面說過,logical address 由 selector 和 offset 兩部分組成,offset 也是 EIP 暫存器的值,所以結論為:logical address 的 offset 正是 virtual address

,它倆是一個東西。

既然搞明白了 logical address 和 virtual address 的關係,那麼我們再來看下,linear address 和 virtual address 是什麼關係。在上面講到的段式記憶體管理中,Linux 核心會將 segment base address(段基址)設成 0,於是就有 linear address = 0+offset,又因為 virtual address 就是 offset,所以算出的 linear address在數值上等於 virtual address,注意,是數值上等於,它們之間是差了段基址的,只不過段基址為 0 罷了。

網上很多資料認為邏輯地址是虛擬地址的別名,其實它們不是一個東西。還有很多資料把線性地址當作虛擬地址的別名,其實它們也不是一個東西,只是Linux在x86下將它們搞得數值相等而已,雖然值相等但是本質不同

---------------------------------我是分割線-------------------------------------------

講到這裡,三者之間的關係就講明白了,最後說下為什麼這三個概念會如此混亂。

按照 Intel 的設計,段式記憶體管理中的段型別分為三種:程式碼段(上面講了)、資料段、系統段(TSS之類的),實在是太麻煩了。我們只靠頁式記憶體管理就已經可以完成Linux核心需要的所有功能,根本不需要段對映,但是段對映這玩意兒又關不掉,那就只能上點手段了。於是,Linux核心將所有型別的段的 segment base address 都設成0,段限長都設成最大(具體數值不展開講了,涉及到段描述符結構,很麻煩,這裡理解成地址匯流排的最大定址限度即可),那麼這樣一來所有段都重合了,也就是不分段了,此外由於段限長是地址匯流排的定址限度,所以這也相當於所有段跟整個線性空間重合了。虛擬地址本來是在段內的偏移量,現在段就是整個線性空間,所以虛擬地址就成了在整個線性空間內的偏移量,這和線性地址的概念一樣,所以核心開發者都已經將虛擬地址和線性地址當作一個東西了。像是 Understand The Linux Kernel 這本書裡面為了避免混淆,除了在開頭和術語表中引用了 virtual address 這個片語之外,其他地方全是用的 linear address。

看完這個答案,你會發現我們繞了一圈回來,雖然邏輯地址的概念很清晰,但是虛擬地址和線性地址依然可以不作區分,因為區分了也沒什麼用,核心裡這倆概念是通用的。不過,知道點區別還是不至於在某些時候把自己搞暈,尤其是有些書和教程裡面這兩個詞不說緣由就混著用,這很蛋疼。好了,最後結論就是,這兩個概念區分開來的確更加清晰,但如果不作區分而直接把虛擬地址看作線性地址的別名,對你理解核心也不會產生任何影響。

相關推薦

Linux 核心邏輯地址/虛擬地址/線性地址三者區別

為了防止歧義,以下術語都用英文。部分術語不做解釋了,不然答案就太長了。 以下講解都是以程式碼段為例 在 Intel 平臺下,邏輯地址(logical address)是 selector:offset 這種形式,selector 是 CS 暫存器的值,offset

Linux 核心獲取時間分析基於do_gettimeofday()

Linux 核心中獲取時間分析基於do_gettimeofday() 核心程式碼能一直獲取一個當前時間的表示,通過檢視jifies的值。通常這個值只代表從最後一次啟動以來的時間,這個事實對驅動來說無關,因為它的生命週期受限於系統的uptime。 驅動可以使用jifie

Linux核心的迴圈緩衝區【轉】

  (轉自:https://blog.csdn.net/heanyu/article/details/6291825) 迴圈緩衝區定義在include/linux/kfifo.h中,如下: struct kfifo { unsigned char *buffer; /

Linux核心連結串列的設計思路

一般實際專案中的連結串列,節點中儲存的資料其實是一個結構體,這個結構體中包含若干的成員,這些成員加起來構成了我們的節點資料區域。 實際上鍊表操作是相同的,而涉及到資料區域的操作就有不同。 鑑於以上2點,能不能有一種辦法把所有連結串列中操作方法裡共同的部分提取出來用一套標準方法實現,然

【轉】對Linux核心程序上下文和中斷上下文的理解

轉自:http://www.embedu.org/Column/Column240.htm 核心空間和使用者空間是作業系統理論的基礎之一,即核心功能模組執行在核心空間,而應用程式執行在使用者空間。現代的CPU都具有不同的操作模式,代表不同的級別,不同的級別具有不同的功能,在較低的級別中將禁止某些

ifconfig---配置和顯示Linux核心網路介面

ifconfig命令被用於配置和顯示Linux核心中網路介面的網路引數。用ifconfig命令配置的網絡卡資訊,在網絡卡重啟後機器重啟後,配置就不存在。要想將上述的配置資訊永遠的存的電腦裡,那就要修改網絡卡的配置檔案了。 語法 ifconfig(引數) 引數 add<地址>:設定網路裝置I

Linux核心發現未修補的DoS漏洞

貢獻者Wanpeng Li在Linux核心中發現的兩個拒絕服務(DoS)漏洞,可能允許本地攻擊者利用空指標引用錯誤來觸發DoS條件。 第一個在Common Vulnerabilities and Exposures資料庫中,編號為CVE-2018-19406,漏洞存在於Linux核心的kvm_pv_se

Linux 核心的 static_key 機制

目錄 GOTO  問題解決: 問題來源:惡意程式檢測 最近,主要由於在研討一些關於LINUX被惡意程式ROOT後,可能會被修改程式碼段中的資料。為了防止程式碼段被修改,採用幾種特殊的機制來保護程式碼段的資料不被篡改,當有惡意程式試圖修改程式

Linux核心的常用巨集container_of

Container_of在Linux核心中是一個常用的巨集,用於從包含在某個結構中的指標獲得結構本身的指標,通俗地講就是通過結構體變數中某個成員的首地址進而獲得整個結構體變數的首地址。     Container_of的定義如下:  #define container_

Linux核心增加新驅動模組

開發環境 開發板:A33-Vstar 開發板系統: Linux/arm 3.4.39 Kernel Ubuntu版本:Ubuntu14.04 ---------------------------------------------------- 新增核心驅動,

amlogic平臺android 系統linux核心新增i2c裝置實現i2c的讀寫

上一篇,我介紹瞭如何在uboot中新增i2c裝置,以及移植i2c的讀寫介面。簡單來說uboot階段使用i2c裝置和平臺關聯性比較大,但不同平臺套路是差不多的。你可以將uboot階段看作是引導androi

Linux核心雙向連結串列的經典實現

1 #ifndef _LIST_HEAD_H 2 #define _LIST_HEAD_H 3 4 // 雙向連結串列節點 5 struct list_head { 6 struct list_head *next, *prev; 7 }; 8

紅黑樹(三)之 Linux核心紅黑樹的經典實現

1 /* 2 Red Black Trees 3 (C) 1999 Andrea Arcangeli <[email protected]> 4 (C) 2002 David Woodhouse <[email protected

linux核心串列埠驅動註冊過程(tty驅動)

原文轉自:http://m.blog.csdn.net/blog/lushengchu2003/9368031 最近閒來無事情做,想到以前專案中遇到串列埠硬體流控制的問題,藍芽串列埠控制返回錯誤,上層讀寫串列埠buffer溢位的問題等,也折騰了一陣子,雖然 最終證明與串列埠驅動無關,但是排查問題

Linux核心的執行緒及多執行緒

一、執行緒的概念、理解及特點     1.執行緒的概念:         至今為止,Linux下還是沒有“真正的執行緒”。談到執行緒就不得不提到程序這概念,程序是系統中程式執行和資源分配的基本單位。每個程序都擁有自己的資料段,程式碼段和堆疊段,這就造成了程序在進行切換

Linux核心的執行緒死鎖

一、死鎖的概念     1.什麼是死鎖:       死鎖 (deadlocks): 是指兩個或兩個以上的程序(執行緒)在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的

arm-linux核心串列埠時鐘頻率及波特率的設定

本人使用的核心版本為linux-2.6.32,採用的ARM處理器為cortex-A8,採用的串列埠為NS16550。串列埠的驅動直接編譯在核心中,當需要修改串列埠的時鐘頻率和波特率的時候, 需要修改以下地方。 1、在板子平臺目錄下平臺相關的標頭檔案路徑下串列埠的標頭檔案中,

linux 核心的概念-模組與裝置檔案

        模組:是在核心空間執行的程式,實際上是一種目標物件檔案,沒有連結,不能獨立執行,但是可以裝載到系統中作為核心的一部分執行,從而可以動態擴充核心的功能。模組最主要的用處就是用來實現裝置驅動程式。Linux下對於一個硬體的驅動,可以有兩種方式:直接載入到核心程式

Linux核心新增自己的驅動程式

就說一下怎麼新增進去吧。首先你要把驅動程式寫好。我已新增 首先在drivers目錄下面建立GPIO資料夾,,資料夾下面建立三個檔案,分別是:gpio.c,Kconfig Makefile,三個檔案。     gpio.c是你的驅動程式,Kconfig是配置選單,也就是它會在

Linux核心的機制學習總結

一、驅動中的poll機制 1.簡介:select()和poll()系統呼叫的本質一樣,前者在 BSD UNIX 中引入的,後者在 System V 中引入的。 應用程式使用 select() 或 poll() 呼叫裝置驅動程式的 file_operations 的 poll() 函式。 2.實現(1).初