国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

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

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

問題描述

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

例如下面這段C代碼:

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

gcc -m32 -static test.c -o test

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

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

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

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

ELF 文件格式

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

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

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

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

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

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

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

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

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

地址轉換和內存映射

從地址轉換的角度來看:

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

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

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

從內存映射的角度來看:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Linux 中的內存重復映射

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

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

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

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

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

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

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

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

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

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

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

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

也就是說:當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字節的空洞,如下所示:

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

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

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

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

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

那么數據段呢?

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

如下所示:

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

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

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

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

0xA0F5C - 0xA0000 = 0xF5C 。

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

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

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

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

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

0x080e_9F5C + 0x01e48 = 0x080e_bda4

如下所示:

小結

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

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

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


責任編輯:武曉燕 來源: IOT物聯網小鎮
相關推薦

2021-08-11 07:55:10

Go內置函數

2024-04-15 00:00:00

首屏優化元素

2015-06-25 10:57:15

推薦系統老婆算出來

2022-07-14 08:22:48

Computedvue3

2017-07-25 18:36:00

機器學習WOT票房

2009-11-06 13:54:09

Visual Stud

2009-09-10 16:22:48

LINQ建立數據報表

2020-10-10 06:22:58

虛擬地址物理

2021-03-01 10:38:13

深度學習編程人工智能

2023-11-08 08:09:36

幾何算法解析幾何

2024-12-26 11:49:14

2023-05-08 00:01:29

數據分析指標標簽

2018-12-12 11:11:20

系統可靠性可用性

2022-05-18 13:46:37

進程TLB虛擬地址

2010-02-26 13:43:36

Linux gcc

2020-03-16 10:42:23

大數據IT工具

2016-11-18 09:37:07

EC2,云計算故障賠償

2025-07-01 01:55:00

Redis集群模式

2012-04-25 22:58:36

2019-07-10 12:40:29

Linux虛擬地址空間物理地址空間
點贊
收藏

51CTO技術棧公眾號

一本岛在线视频| 在线观看视频你懂的| 欧美精品系列| 中国日韩欧美久久久久久久久 | 亚洲一区二区伦理| 2018日韩中文字幕| 精品久久国产一区| 一区二区在线视频播放| av老司机在线观看| 日韩亚洲欧美在线观看| 日本中文在线| 欧美伦理视频网站| 日韩子在线观看| 在线国产电影不卡| 国产人成在线视频| 色视频成人在线观看免| 欧洲亚洲精品视频| 欧美午夜片欧美片在线观看| 在线观看免费视频一区二区三区| 亚洲一区二区三区中文字幕 | 另类小说一区二区三区| 欧美一区二区三区在线播放| 中文精品视频| 久久精品国产美女| 日日夜夜精品免费视频| 天堂资源在线亚洲资源| 麻豆国产精品官网| 国产欧美日韩网站| 国产蜜臀97一区二区三区| 亚洲娇小娇小娇小| 天堂资源在线亚洲资源| 亚洲在线日韩| 欧美大陆一区二区| 国产一区二区三区在线观看精品| 国产美女主播在线| 国产精品视频看| 理论片鲁丝二区爱情网| 天天综合色天天| 日本www在线观看视频| 亚洲第一精品自拍| 日韩在线观看不卡| 日本精品久久久| 最新精品国产| 在线综合视频网站| 91亚洲男人天堂| 国产国语**毛片高清视频| 亚洲一区二区三区精品在线| 午夜激情视频在线| 亚洲欧美在线第一页| 精品视频自拍| 精品欧美国产| aaa亚洲精品一二三区| 国产超碰在线| 日韩精品中文在线观看| 国产精品zjzjzj在线观看| 一本到三区不卡视频| 日本中文字幕在线2020| 亚洲视频在线观看视频| 麻豆精品少妇| 久久伊人资源站| 国产成人av一区| 国产极品粉嫩福利姬萌白酱| 久久精品在线观看| 久久精品亚洲国产奇米99| 国产宾馆自拍| 337p亚洲精品色噜噜| 亚洲人免费短视频| 国产精品成人av性教育| 亚洲精选久久| 成人精品小视频| 精品91福利视频| 欧美一级免费视频| 亚洲欧美大片| 成人av小说网| 欧美变态凌虐bdsm| 亚洲小说图片视频| 五月天综合婷婷| 精品福利在线观看| 91国内外精品自在线播放| 国产成人av在线| 国产精品1区2区| 蜜桃视频在线观看视频| 美女久久久久久久久久久| 亚洲精品乱码| 国产va在线| 国产亚洲aⅴaaaaaa毛片| 午夜欧美在线| 成年人网站大全| 精品sm捆绑视频| 66视频精品| www.com黄色片| 亚洲国内精品在线| 婷婷综合社区| 日本激情视频在线播放| 亚洲激情在线视频| 欧美日韩日本国产亚洲在线| 成人免费xxxxx在线视频| 亚洲国内精品视频| 99热这里只有成人精品国产| 最新av中文字幕| 国产日产亚洲精品系列| 性欧美高清come| 国产精品亚洲精品| 国产精品国产三级国产| 亚洲日本在线观看视频| 亚洲图片欧洲图片日韩av| 欧美天堂一区二区三区| 欧美日韩有码| 三级黄色的网站| 欧美黑人国产人伦爽爽爽| 国产精品正在播放| 老色鬼在线视频| 日韩av影视| 日韩免费性生活视频播放| 99国产一区| 免费在线你懂的| 国产精品视频一二| 国产91在线播放精品| 尤物一区二区三区| 欧美肥胖老妇做爰| 狠久久av成人天堂| 国产免费永久在线观看| 成人精品网站在线观看| 亚洲福利视频三区| 欧美艳星介绍134位艳星| 国产字幕中文| 国产成人拍精品视频午夜网站| 亚洲视频免费观看| 国产一区二区精品久| 男女午夜视频在线观看| 日韩av免费在线播放| 亚洲欧美一区二区三区极速播放| 欧美亚洲国产日韩| 黄色大秀av大片| 全球成人中文在线| 亚洲在线成人精品| 日韩在线中文| 高清中文字幕一区二区三区| 狠狠色综合欧美激情| 日韩欧美精品三级| 久久精品久久99精品久久| 免费的黄网站在线观看| 日本一区二区三不卡| 亚洲成人av片| 国产v日产∨综合v精品视频| 亚洲18在线| 好男人看片在线观看免费观看国语 | 717成人午夜免费福利电影| 国产一区二区高清| 色女人在线视频| 国产黄色激情视频| 欧美精品18videos性欧| 一区二区国产盗摄色噜噜| 99久久久久国产精品| 免费高清完整在线观看| 熟妇熟女乱妇乱女网站| www.亚洲一区| 日本久久精品| 国产最新视频在线| 日本一区二区三区视频在线观看| 亚洲精品短视频| 日本一区二区三区免费乱视频| jizzjizz欧美69巨大| 成人免费看片| 日韩av片在线看| 国产91精品不卡视频| 精品露脸国产偷人在视频| 亚洲美女啪啪| 福利精品在线| 国产香蕉尹人视频在线| 日本高清久久一区二区三区| 在线视频日韩精品| 天天综合色天天综合色h| 日本视频免费一区| 欧美变态网站| a黄色在线观看| 国产资源在线视频| 欧美视频13p| 九九久久精品视频| 日韩精品丝袜美腿| 污视频在线免费观看网站| 欧美视频第一区| 动漫美女被爆操久久久| 在线看福利67194| 亚洲午夜私人影院| 国产精品羞羞答答xxdd | 欧美另类在线播放| 91黄视频在线| 久久噜噜亚洲综合| 在线播放精品| 成人拍拍拍在线观看| 国产精品视频500部| 中文字幕在线日韩 | 丝袜老师办公室里做好紧好爽| 亚洲综合最新在线| www.日韩不卡电影av| 欧美三级三级三级爽爽爽| 国产视频一区在线观看| 三级亚洲高清视频| 日韩电影二区|