色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

鏈接器安排的【虛擬地址】是如何計算出來的?

li5236 ? 來源:道哥分享 ? 作者:道哥分享 ? 2022-03-29 14:36 ? 次閱讀

問題描述

昨天下午,旁邊的同事在學習Linux系統中的虛擬地址映射(經典書籍《程序員的自我修養-鏈接、裝載與庫》),在看到6.4章節的時候,對于一個可執行的ELF文件中,虛擬地址的值百思不得其解!

例如下面這段C代碼:

poYBAGJCqPOABRdMAAG9iZYG0g4084.jpg

首先編譯出32位的可執行程序(為了避開一些與主題無關的干擾因素,采用了靜態鏈接):

gcc -m32 -static test.c -o test

編譯得到ELF格式的可執行文件:test。

pYYBAGJCqPOAYsyLAAIPXflPCH8725.jpg

這個時候,使用readelf工具來查看這個可執行文件中的段信息(segment):

poYBAGJCqPSAcBW_AAWFTSSCtcA102.jpg

上圖中的紅色矩形框中,第二個段的地址為什么是 0x080e_9f5c?

這篇文章主要根據書中的解釋,來具體的分析這個值的來龍去脈。

ELF 文件格式

在Linux系統中,有4種類型的文件都是ELF格式,包括:目標文件,可執行文件,動態鏈接庫文件、核心轉儲文件。

如果想系統掌握Linux系統中的底層知識,研究ELF的格式是避免不了的事情。

很久之前總結過這篇文章:《Linux系統中編譯、鏈接的基石-ELF文件:扒開它的層層外衣,從字節碼的粒度來探索》,里面詳細總結了ELF文件的內部結構。

這里就不再贅述了,只要記住2點:

1.從編譯器的角度看,ELF 文件是由很多的節(Section)組成的;

2.從程序加載器的角度看,ELF 文件是又很多的段(Segment)組成的;

其實它倆沒有本質區別,只不過是鏈接器在鏈接階段,把不同目標文件中相同的section組織在一起,形成一個 segment。

對于剛才編譯出的test可執行文件,其加載視圖如下:

pYYBAGJCqPSAanuEAAWm4WhSWq4394.jpg

可以看到該文件一共有5個段(segment),前2個需要LOAD到內存的段,它們屬性分別是:讀、執行(R E) 和 讀、寫(RW),它們分別是代碼段和數據段。

綠色的箭頭反映出:代碼段中包含了很多的 section;黃色的箭頭反映出數據段也包含了很多的 section。

地址轉換和內存映射

從地址轉換的角度來看:

Linux 系統中CPU中使用的都是虛擬地址,該虛擬地址在尋址的時候,需要經過MMU地址轉換,得到實際的物理地址,然后才能在物理內存中讀取指令,或者讀取、寫入數據。

在現代操作系統中,MMU地址轉換單元基本上都是通過頁表來進行地址轉換的:

poYBAGJCqPWAUW85AAGOfont-XQ386.jpg

當然了,有些系統是兩級轉換(頁目錄、頁表),有些系統是三級或者四級頁表。

從內存映射的角度來看:

操作系統在把一個可執行程序加載到系統中時,把ELF文件中每個段的內容讀取到物理內存中,然后把這個物理內存映射到該段對應的虛擬地址上(VirtAddr)。

假設一個可執行程序中的代碼段長度是1.2K字節, 數據段長度是1.3K字節。

操作系統在把它倆讀取到內存中時,需要 2 個物理內存頁來分別存儲它們(每 1 個物理頁的長度是4K):

pYYBAGJCqPWADIVyAAFK6tP5sC0814.jpg

雖然每一個物理內存頁的大小是 4K,但是代碼段和數據段實際上只使用了每個頁面剛開始的一段空間。

當CPU中需要讀取物理內存上代碼段中的指令時,使用的虛擬地址是 0x0000_1000 ~ 0x0000_1000 + 1.2K這個區間的地址,MMU單元經過頁表轉換之后,就會得到這個存放著代碼段的物理頁的物理地址。

數據段的尋址方式也是如此:當CPU中需要讀寫物理內存上數據段中的數據時,使用的虛擬地址是 0x0000_2000 ~ 0x0000_2000 + 1.3K這個區間的地址。

MMU單元經過頁表轉換之后,就會得到存放著數據段的物理頁的物理地址。

可以看出在這樣的安排下,每一個段的虛擬地址,都是按照4K(0x1000)對齊的。

如果操作系統都是這樣簡單映射的話,那么事情就簡單多了。

如果按照這樣的安排,來分析一下文章開頭的 test 可執行程序中的虛擬地址安排:

1.代碼段安排的開始虛擬地址是 0x0804_8000,這是 4K 對齊的;

2.代碼段的結束虛擬地址就應該是 0x0804_8000 + 0xa0725 = 0x080e_8725;

3.那么數據段的開始地址就可以安排在 0x080e_8725 之后的下一個 4K 對齊的邊界地址,即:0x080e_9000。

但是這樣的地址安排,嚴重浪費了物理內存空間!

1.2K 字節的代碼段加上1.3K字節的數據段,本來只需要1個物理頁就夠了(4KB),但是這里卻消耗掉2個物理頁(8KB)。

為了減少物理內存的浪費,Linux操作系統就采用了一些巧妙的辦法來減少物理內存的浪費,那就是: 把文件中接壤部分的代碼段和數據段,讀取到同一個物理內存頁中,然后在虛擬地址空間中映射兩次,詳述如下。

Linux 中的內存重復映射

先來看一下test文件的結構:

poYBAGJCqPWAN0wmAAAsafA3Ujc854.jpg

代碼段在文件中的開始位置是:0x00000,長度是 0xa0725。

數據段的開始位置是:0xa0f5c,長度是0x1024。

可以看到它倆之間有一個空白區間,長度是: 0xa0f5c - 0xa0725 = 0x837(十進制:2103字節)。

由于操作系統在把test文件讀取到物理內存的時候,從文件開始代碼段的0x00000地址開始讀取,按照4KB為一個單位存放到一個物理頁中。

1.文件中代碼段的 0x00000 ~ 0x00FFF 讀取到一個物理頁中;

2.文件中代碼段的 0x01000 ~ 0x01FFF 讀取到物理頁中;

3.下面的內容都是如此分割、復制;

也就是說:相當于把test文件從開始位置,按照4KB為一個單位進行"切割",然后復制到不同的物理內存頁中,如下所示:

pYYBAGJCqPWASPGQAABtQ1QJflY467.jpg

注意:這些物理頁的地址很可能是不連續的。

這里有意思的是:代碼段與數據段接壤的這個4KB的空間,它的開始地址是0xA0000,結束地址是0xA0FFF,被復制到物理內存中最上面的橙色物理頁中。

再來看一下代碼段的虛擬地址:在執行gcc指令的的時候,鏈接器把代碼段的虛擬地址安排在0x0804_8000處:

poYBAGJCqPWAVw1yAAC1XFf5kFU636.jpg

也就是說:當CPU中(或者說程序代碼中),使用0x0804_8000 ~ 0x0804_7FFF 這個區間的地址時,經過地址映射,就會找到物理內存中淺綠色的物理頁,而這個物理頁也對應著test可執行文件開始的第一個4KB的空間。

而且,從虛擬地址的角度看,它的地址都是連續的,對應著test文件中連續的內容,這也是虛擬地址映射的本質。

把代碼段的開始位置安排在 0x0804_8000 地址,這是 Linux 操作系統確定的。

那么考慮一下:代碼段的最后一部分指令相應的4K頁面,其對應的開始虛擬地址是多少呢?

上圖中已經標記出來了,就是虛擬地址中橙色部分:0x080e_8000,計算如下:

通過代碼段的開始地址0x0804_8000,再加上代碼段在內存中的長度0xa0725,結果就是 0x080e_8725。

按照4K (0x1000)對齊之后,最后一個虛擬頁就應該是0x080e_8000。

也就是說:虛擬地址中0x080e_8000 ~ 0x080e_8724 這個區間就對應著test文件中代碼段的最后一部分指令(0x725個字節)。

此外,上圖中最右側:test文件結構中的2個紅色地址:0xA0000, 0xA1000,是如何計算得到的?

代碼段的長度是 0xA0725,按照4K為一個單位來進行分割,也就是把0xA0725對0x1000進行整除,就得到這個4KB的開始地址0xA0000。

同理,下一個4KB的開始地址就是0xA1000。

把文件中這部分4K的數據(包括:一部分代碼段內容 + 0x837 字節空洞 + 一部分數據段內容),復制到上圖中物理內存中最上面的橙色物理頁中。

又因為虛擬地址空間中,0x080E_8000開始的這個4KB空間映射到這個物理頁中,所以:在這個虛擬地址空間中,也有一個0x837字節的空洞,如下所示:

pYYBAGJCqPaAUBlkAAB2jLkJ8go953.jpg

空洞的下方,是代碼段的指令;空洞的上方,是數據段的數據。

現在,這個物理頁中即存放了代碼,又存放了數據。

那么CPU中在查找部分的代碼和數據的時候,必須都能夠找得到才行!

對于代碼段比較好理解:從這個物理頁開始的前0x725個字節是有效的,從虛擬地址的角度看,就是從0x080e_8000開始的前0x725個字節是有效的。

因此,對于這部分代碼的尋址,使用的虛擬地址處于0x080e_8000 ~ 0x080e_8724這個區間中。

那么數據段呢?

重點來了:Linux系統把虛擬地址空間 0x080e_9000 ~ 0x080e_9FFF 也映射到圖中物理內存中最上面的橙色物理頁上!

如下所示:

poYBAGJCqPaAVdcEAADEQ8znZnA069.jpg

因為物理頁中,是從0x837個字節空洞的上面開始,才是真正的數據段內容,那么相應的: 虛擬地址0x080e_9000 ~ 0x080e_9FFF空間中,0x837字節上面的內容才是數據段內容。

那么在虛擬地址空間中,這個數據段的開始地址應該是多少呢?

只要計算出0x837字節空洞的上方,距離這個4K頁面開始地址的偏移量就可以了,然后再加上這個4K頁面的起始地址 0x080E_9000,就得到了數據段的開始地址(虛擬地址)。

因為虛擬地址、物理地址、test文件中,都是按照4K的單位進行劃分的,因此這個偏移量就等于:test文件中數據段的開始地址(0xA0F5C) 距離 這個頁面的開始地址(0xA0000) 的偏移量。

0xA0F5C - 0xA0000 = 0xF5C 。

pYYBAGJCqPaAFjcDAAA-1y0EUrk624.jpg

即:從這個4K頁面的開始地址,偏移量為0xF5C的地方,才是數據段內容的開始。

因此對于虛擬地址來說,從0x080e_9000地址開始,偏移量為0xF5C之后的內容才是數據段的內容,這個地址值就是:0x080e_9000 + 0xF5C = 0x080e_9F5C,如下所示:

poYBAGJCqPaASJEZAACQYSwrSLA759.jpg

這個地址正是readelf工具讀所顯示的:數據段加載到虛擬地址空間中的開始地址,如下所示:

pYYBAGJCqPeAU7rvAAFV78G8sjU166.jpg

至此,就解釋了文章開頭提出的問題!

再來看一下整個數據段的內容:在內存中數據段占據的空間是 0x01e48(readelf 工具讀取到的 MemSiz),那么數據段的結束地址就是(虛擬地址):

0x080e_9F5C + 0x01e48 = 0x080e_bda4

如下所示:

poYBAGJCqPeASZohAACqNeG56yo245.jpg

小結

Linux系統中的這個操作:對屬于不同段的內容進行重復映射,有點類似于共享內存的味道了。

只不過這里重復映射之后,每個段的虛擬地址還是需要修正為該段的合法地址。

經過這樣的操作之后,在虛擬地址中每一個段的界限是涇渭分明的,但是映射到的物理內存頁,則有可能是同一個。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據
    +關注

    關注

    8

    文章

    7067

    瀏覽量

    89110
  • Linux
    +關注

    關注

    87

    文章

    11312

    瀏覽量

    209702
  • 虛擬
    +關注

    關注

    0

    文章

    187

    瀏覽量

    23665
收藏 人收藏

    評論

    相關推薦

    使用430驅動TMP006紅外傳感計算出來的Tobj一直是358~360之間波動,為什么?

    使用430驅動TMP006紅外傳感,各寄存讀取數據正常,經過方程式計算后Tdie正常在26.5度左右,Vobj數值8.18312447E-3 計算出來的Tobj一直是358~36
    發表于 01-02 07:13

    用INA233來監控主芯片的幾個PORT的供電情況,這顆芯片I2C直接輸出電流值是怎么算出來的?

    沒看到相關的寄存設置,唯一能找到一處地方是校準的地方會有一個計算公式和檢流電阻有關,但是依舊不明白電流值是怎么算出來的 求各位大神幫忙看看
    發表于 12-03 06:00

    ads1115在采集距離傳感輸入的0.9v時誤差較大,怎么解決?

    ads1115在采集距離傳感輸入的0.9v時誤差較大,為0.03v,在0.6和1.2左右都是0.01v的誤差,請問這是為什么;在誤差為0.03v時候,計算出來的電流和距離傳感的標準電流差了0.04ma,對應實際距離差了十幾
    發表于 11-29 14:51

    ADS1299器件手冊里的這個衰減怎么計算出來的?

    我的計算過程:33uV x 10.3/(952+10.3) = 0.35uV ?而不是要求的3.5uV,請指教
    發表于 11-18 06:41

    TPA2013D1功率是如何計算出來的,和哪些因素有關?

    有關,如何計算? 和輸入有關么,比如IN+ 接輸入P,IN-接地 和IN+接輸入P, IN-接輸入N輸出功率應該相差4倍吧?? 請答疑,謝謝! 主要想知道功率是如何計算出來的。和哪些因素有關
    發表于 11-07 07:52

    使用TAS5756做一款低音炮,需要隨時調節低通濾波寬帶,請問這些數據是怎么算出來的?

    你好,使用TAS5756做一款低音炮。需要隨時調節低通濾波寬帶,現在用purepath Console可以調節(low pass,butterworth模式),但是不知道BO,B1,B2,A1,A2的值怎么計算出來的,可否提供計算公式。謝謝
    發表于 10-28 06:09

    PCM1808從模擬信號輸入到I2S信號輸出的延遲時間是多少?怎樣計算出來

    PCM1808從模擬信號輸入到I2S信號輸出的延遲時間是多少,或者怎樣計算出來?我想選一個低延遲的音頻ADC是否還有別的更好推薦,謝謝。
    發表于 10-14 06:25

    TAS5805內部的硬件CRC8對應標準的哪種? CRC校驗的數據是offset和value值嗎?

    TAS5805 內部的硬件 CRC8 對應標準的哪種? CRC 校驗的數據是 offset 和 value 值嗎?用 PPC 加載文件計算出來的值和在線CRC計算工具計算的值不一樣。 測試校驗的數據: 58 18 00 80
    發表于 10-12 06:19

    LPV521 Vout是怎么計算得出的呢?

    麻煩分析一下如下電路圖的工作原理:Vout是怎么計算得出的呢? 圖中測量電流的范圍能達多少呢?怎么計算出來的呢? 圖中三極管工作在什么狀態?怎么進行選型呢? 謝謝!
    發表于 09-05 07:37

    LTSR 25-NP計算出來的電流誤差特別大,為什么?

    大家好,我現在使用的電流傳感是lem的LTSR 25-NP,其中電流和輸出電壓關系是:v=2.5+0.025*I,現在的AD采樣輸入范圍是0-3V,中間有一個放大倍數,但是即使這樣,電壓稍微波動一些,計算出來的電流誤差就特別大,請大家支招,謝謝!
    發表于 09-03 08:18

    st2.0的電機庫,hall電角度是怎么計算出來

    小弟最近在看電機庫,是利用定時3捕獲hall信號,但是看代碼不是很明白,為什么計算電角度跟hall值1,2,4無關呢,只是判斷3,5,6這幾個hall值 bPrevHallState
    發表于 07-23 08:30

    dd馬達偏差量怎么計算出來

    反映了電機的實際位置與期望位置之間的差異。 計算DD馬達偏差量的基本步驟如下: 確定期望位置:期望位置是系統希望電機達到的目標位置。這可以是用戶輸入的值,也可以是系統根據某種算法計算出來的值。 獲取實際位置:實際位置是電機當前的實際位置。這可
    的頭像 發表于 07-11 15:05 ?666次閱讀

    MCSDK5.4.8中STEVAL-ESC001V1過流保護里邊的current threshold是怎么計算出來的?

    MCSDK5.4.8中,STEVAL-ESC001V1過流保護里邊的 current threshold是怎么計算出來的? 在voltage threshold 0.6V時33.636Apk 0.3V時0.707Apk 這是什么公式算出來的? STEVAL-ESC001V
    發表于 05-21 07:26

    隔離開關的額定電流怎么計算出來

    隔離開關的額定電流是指設備或元件所能承受的最大連續工作電流。它是由許多因素決定的,包括電流容量、電壓容量、環境溫度和使用條件等。 隔離開關是一種常見的電氣設備,用于控制和切斷電路中的電流。它主要由可分離的觸點組成,可將電路從電源分離以實現安全控制。在選擇隔離開關時,需要考慮電流容量以確保設備的安全運行。 首先,我們需要了解什么是電流容量。電流容量是指設備或元件所能連續承受的電流大小。它是設備設計和制造
    的頭像 發表于 02-05 15:29 ?2062次閱讀

    ADUCM360 demo里面這個3.75Hz怎么算出來的?

    demo里面這個3.75Hz怎么算出來的我按照公式為什么算出來是3.67.。125000/((SF+1)*16*(3+AF)+3) (pADI_ADC1,124,14,FLT_NORMAL
    發表于 01-11 07:34
    主站蜘蛛池模板: 久久最新地址获取| 全免费a级毛片免费看| 国产午夜久久影院| 国产精品乱码一区二区三| 国产亚洲精品久久久999蜜臀| 和搜子的日子 在线观看| 极品少妇高潮XXXXX| 久久性色AV亚洲电影无码| 麻豆精品传媒一二三区| 欧美精品成人久久网站| 色爱区综合小说| 小小水蜜桃免费影院| 亚洲中文无码永久免费| 97超在线视频| 国产成人免费视频| 红尘影院手机在线观看| 免费人成视频X8X8国产更快乐| 欧洲美女高清一级毛片| 色噜噜狠狠色综合中文字幕| 亚洲精品AV一二三区无码| 18日本人XXXXXX18| 成人免费精品视频| 国内精品一级毛片免费看| 美女脱衣服搞鸡| 色呦呦人人视频| 一个人的免费高清影院| av天堂影音先锋在线| 国产精品一区二区欧美视频| 久久久无码精品亚洲欧美| 全部老头和老太XXXXX| 亚洲第一免费播放区| 91热久久免费频精品99欧美| 国产 日韩 欧美 综合 激情| 久见久热 这里只有精品| 欧美性喷潮xxxx| 亚洲乱色视频在线观看| 99视频网站| 国语自产视频在线不卡| 欧美精品XXXXBBBB| 亚洲国产高清在线观看视频| 99精品国产高清自在线看超|