???hello,各位讀者大大們你們好呀??
????系列專欄:【Linux初階】
????本篇內(nèi)容:計(jì)算機(jī)空間初識(shí)(子進(jìn)程變量修改實(shí)驗(yàn)),感性理解進(jìn)程虛擬地址空間,進(jìn)程地址空間基礎(chǔ)(概念、區(qū)域劃分與調(diào)整、程序?qū)?nèi)存數(shù)據(jù)的修改、按需分配虛擬地址空間),解答為什么存在虛擬地址空間(防止非法越界、方便解耦、保證進(jìn)程獨(dú)立性、統(tǒng)一編譯方便使用),其中重點(diǎn)講解統(tǒng)一編譯中CPU與可執(zhí)行程序的交互原理
????作者簡(jiǎn)介:本科在讀,計(jì)算機(jī)海洋的新進(jìn)船長(zhǎng)一枚,請(qǐng)多多指教( ????? ) ??-
目錄
一、你真的了解計(jì)算機(jī)數(shù)據(jù)空間分布嗎?
二、感性理解進(jìn)程虛擬地址空間
三、進(jìn)程地址空間基礎(chǔ)
1.相關(guān)的基礎(chǔ)概念
2.區(qū)域劃分與調(diào)整
3.程序是如何更改內(nèi)存中的數(shù)據(jù)的?
4.操作系統(tǒng)會(huì)根據(jù)進(jìn)程的需求分配虛擬地址空間
四、為什么存在地址空間?
1.防止非法越界訪問
2.方便進(jìn)程解耦,保證進(jìn)程獨(dú)立性
3.統(tǒng)一編譯,方便使用
(1)可執(zhí)行文件中有地址嗎?
(2)編譯器的編碼方式
(3)物理地址的來源
(4)CPU與可執(zhí)行程序交互的原理
(5)邏輯地址知識(shí)補(bǔ)充
結(jié)語
一、你真的了解計(jì)算機(jī)數(shù)據(jù)空間分布嗎?
在以前的學(xué)習(xí)中,大家可能很早已經(jīng)見過類似下面這樣的空間分布圖了
可是我們很多同學(xué)對(duì)它并沒有深入理解,很多同學(xué)認(rèn)為這個(gè)空間實(shí)際上就是我們的內(nèi)存,但是真的是這樣嗎?
我們直接通過一段代碼來驗(yàn)證一下
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 0;
}
else if (id == 0) { //child
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
else { //parent
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
輸出
//與環(huán)境相關(guān),觀察現(xiàn)象即可
parent[2995]: 0 : 0x80497d8
child[2996] : 0 : 0x80497d8
我們發(fā)現(xiàn),輸出出來的變量值和地址是一模一樣的,很好理解呀,因?yàn)樽舆M(jìn)程按照父進(jìn)程為模版,父子并沒有對(duì)變量進(jìn)行進(jìn)行任何修改??墒菍⒋a稍加改動(dòng):
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 0;
}
else if (id == 0) { //child,子進(jìn)程肯定先跑完,也就是子進(jìn)程先修改,完成之后,父進(jìn)程再讀取
g_val = 100;
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
else { //parent
sleep(3);
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
輸出結(jié)果:
//與環(huán)境相關(guān),觀察現(xiàn)象即可
child[3046]: 100 : 0x80497e8
parent[3045] : 0 : 0x80497e8
我們發(fā)現(xiàn),父子進(jìn)程,輸出地址是一致的,但是變量?jī)?nèi)容不一樣!能得出如下結(jié)論:
- 變量?jī)?nèi)容不一樣,所以父子進(jìn)程輸出的變量絕對(duì)不是同一個(gè)變量。
- 但地址值是一樣的,說明,該地址絕對(duì)不是物理地址!
- 曾經(jīng)我們學(xué)習(xí)語言的基本地址(指針),并不是對(duì)應(yīng)的物理地址。
- 在Linux地址下,這種地址叫做 虛擬地址。
- 我們?cè)谟肅/C++語言所看到的地址,全部都是虛擬地址!物理地址,用戶一概看不到,由OS統(tǒng)一管理。
注意:OS必須負(fù)責(zé)將 虛擬地址 轉(zhuǎn)化成 物理地址 。
二、感性理解進(jìn)程虛擬地址空間
進(jìn)程會(huì)認(rèn)為自己是獨(dú)占系統(tǒng)資源的(實(shí)際上不是)
這里我舉一個(gè)通俗易懂的例子:
peter是美國一個(gè)擁有十億美元的大富翁,他擁有三個(gè)私生子,且這三個(gè)私生子互不知道其他私生子的存在,三個(gè)兒子分別是工廠老板、證券交易員、學(xué)生。每個(gè)兒子都認(rèn)為自己是peter十億美金的繼承者。
在他們工作的過程中,需要向peter索取金錢(工廠老板為維持家族企業(yè)正常運(yùn)轉(zhuǎn),發(fā)放工人工資,結(jié)清貨款;證券交易員維持正常投資,管理部分家族現(xiàn)金資產(chǎn);學(xué)生為繳納學(xué)費(fèi)等),他們向peter索要的金錢有多有少,但是都不會(huì)提出過分的要求(比如直接索要十億美金),如果他們提出過分要求,會(huì)被peter拒絕。
peter在三個(gè)兒子工作的時(shí)候,會(huì)給兒子們“畫餅”,比如他會(huì)對(duì)第一個(gè)兒子說:你好好干,只要你管理好我們的家族企業(yè),提高我們的工廠效益,以后我的十億美金就都是你的了。
其中大富翁peter就相當(dāng)于我們的操作系統(tǒng),十億美金就相當(dāng)于操作系統(tǒng)管理的內(nèi)存資源。其中兒子就相當(dāng)于我們平時(shí) malloc、new等向系統(tǒng)索要資源的進(jìn)程。兒子們獲取的金錢就相當(dāng)于內(nèi)存或者在語言上稱為對(duì)象空間(內(nèi)存)。peter給三個(gè)兒子畫的“大餅”就相當(dāng)于進(jìn)程地址空間。計(jì)算機(jī)通過軟件,給進(jìn)程“畫餅”。
?———— 我是一條知識(shí)分割線 ————
那實(shí)際上如何“畫餅”呢?在此之前,我們要知道“餅”是什么,畫餅的本質(zhì):在你大腦中的藍(lán)圖 - 數(shù)據(jù)結(jié)構(gòu)對(duì)象(地址空間)。
每個(gè)兒子(進(jìn)程)都可以根據(jù)peter(操作系統(tǒng))為自己畫的“餅”(數(shù)據(jù)結(jié)構(gòu)對(duì)象/地址空間)向peter要錢(內(nèi)存資源)
?
———— 我是一條知識(shí)分割線 ————?
?我們已經(jīng)知道“餅”是什么,那么問題又來了,我們都知道兒子(進(jìn)程)需要被管理,那么peter(操作系統(tǒng))為兒子(進(jìn)程)提供的“餅”(數(shù)據(jù)結(jié)構(gòu)對(duì)象/地址空間)需要被管理嗎?答案是:要的!因?yàn)椴荒軐⒔o大兒子的承諾許錯(cuò)給二兒子或三兒子,所以“餅”也要被管理。
如果進(jìn)程中有500個(gè)進(jìn)程,操作系統(tǒng)需要給每個(gè)進(jìn)程創(chuàng)建地址空間,進(jìn)程會(huì)被PCB管理,地址空間需要怎么管理呢?答案是:先描述,在組織。地址空間的本質(zhì):是內(nèi)核的一種數(shù)據(jù)結(jié)構(gòu)(mm_struct)。簡(jiǎn)單來說,我們的虛擬地址空間會(huì)被一個(gè)名為?struct mm_struct的數(shù)據(jù)結(jié)構(gòu)管理起來。
三、進(jìn)程地址空間基礎(chǔ)
1.相關(guān)的基礎(chǔ)概念
注意:本次講解以32位計(jì)算機(jī)平臺(tái)為基礎(chǔ)
?在正式深入學(xué)習(xí)進(jìn)程地址空間之前,我們需要先了解一些相關(guān)的基礎(chǔ)概念:
- 進(jìn)程/內(nèi)存空間描述的基本空間大小為字節(jié);
- 32位下計(jì)算機(jī)最多可以形成 2^32個(gè)地址;
- 每個(gè)地址標(biāo)識(shí)一個(gè)字節(jié),所以我們能表示的地址空間范圍最大為 4G;
- 每個(gè)進(jìn)程都要有唯一的地址,假設(shè)我們需要表示 2^32個(gè)地址,我們需要保持每個(gè)地址的唯一性;
- 我們可以通過 32位的數(shù)據(jù)(32個(gè)比特位的數(shù)據(jù))來表示一個(gè)地址。
進(jìn)程地址空間圖例如下?
2.區(qū)域劃分與調(diào)整
這里我們舉一個(gè)例子來理解區(qū)域劃分和區(qū)域調(diào)整。
假設(shè)初中有一對(duì)男女同桌,由于男生太貪玩,經(jīng)常打擾到旁邊的女生學(xué)習(xí),所以女生給桌子畫了一條線,將桌子分成了兩個(gè)區(qū)域,假設(shè)桌子有100cm,她將區(qū)域劃分為[1-50, 51-100],這就是區(qū)域劃分。
而后小男孩還是不在意,經(jīng)常越線,因此小女孩調(diào)整了桌子上線的位置,桌子有100厘米,但是女孩只給了小男孩30厘米的活動(dòng)范圍,[1-30, 31-100],這種在劃分后調(diào)整各自區(qū)域的行為稱為區(qū)域調(diào)整。?
通過觀察下圖我們可以發(fā)現(xiàn),只要我們調(diào)整不同對(duì)象的 start、end,就可以實(shí)現(xiàn)區(qū)域調(diào)整(擴(kuò)大 or 縮小)。
我們可以通過搜索不同的地址位置,找到數(shù)據(jù)所在。還是上面的例子來解釋,可能1-10cm中放有小男孩的筆袋,12-16cm放有小男孩的筆記本。
———— 我是一條知識(shí)分割線 ————?
之前文章中提到,我們可以通過 32位的數(shù)據(jù)(32個(gè)比特位的數(shù)據(jù))來表示地址,我們的虛擬地址空間會(huì)被一個(gè)名為?struct mm_struct的數(shù)據(jù)結(jié)構(gòu)管理起來。在32位計(jì)算機(jī)下,通常我們采用 int類型的數(shù)據(jù)來記錄一個(gè)地址,因?yàn)?int在剛好在32位計(jì)算機(jī)下占32個(gè)比特位。在?struct mm_struct的數(shù)據(jù)結(jié)構(gòu)中包含著不同區(qū)域地址信息,其中就包含有堆的區(qū)域起始地址、區(qū)域結(jié)束地址等。
這些在不同的區(qū)域范圍內(nèi)、可以供我們使用的地址稱為虛擬地址。也就是說在地址空間中的 2^32個(gè)地址都是虛擬地址。
所以,進(jìn)程地址空間也叫做進(jìn)程虛擬地址空間,它的本質(zhì)實(shí)際上是一個(gè)存儲(chǔ)虛擬地址及其相關(guān)數(shù)據(jù)的集合。
———— 我是一條知識(shí)分割線 ————
在地址空間中,代碼區(qū)(已初始化、未初始化)的大小是固定的,也就是說代碼區(qū)的起始和結(jié)束地址不可被調(diào)整;但是堆區(qū)和棧區(qū)不同,堆區(qū)可以通過 malloc等手段調(diào)整它的大小,棧區(qū)也可以定義相應(yīng)的局部變量,也就是說,堆區(qū)和棧區(qū)是可以被調(diào)整的!
heap & stack的調(diào)整,本質(zhì)上就是調(diào)整兩個(gè)區(qū)域的 start和end。在我們的編程過程中,定義局部變量,malloc、new對(duì)象實(shí)際上就是擴(kuò)大堆區(qū)或者棧區(qū)。當(dāng)我們 free的時(shí)候,實(shí)際上就是在縮小堆區(qū)或者棧區(qū)。
3.程序是如何更改內(nèi)存中的數(shù)據(jù)的?
在第一節(jié)中我們驗(yàn)證過,父子進(jìn)程,輸出地址是一致的,但是變量?jī)?nèi)容不一樣,這到底是怎么做到的呢?在解答這個(gè)問題之前,我們先要知道,程序是如何更改內(nèi)存中的數(shù)據(jù)的。接下來這一部分的知識(shí)主要就是向大家講解,程序是如何更改內(nèi)存中的數(shù)據(jù)的。
文章第二節(jié)講到,操作系統(tǒng)會(huì)為進(jìn)程畫“大餅”,這里的大餅就是地址空間(mm_struct),因此相應(yīng)的,tack_struct(PCB,進(jìn)程控制塊)會(huì)有相應(yīng)的指針指向進(jìn)程地址空間。
———— 我是一條知識(shí)分割線 ————?
在硬件方面(內(nèi)存和磁盤),假設(shè)有文件 my.exe存在于磁盤之中,當(dāng)文件加載到內(nèi)存中,占用內(nèi)存 1k字節(jié)的空間,每個(gè)字節(jié)我們都可將它視作一個(gè)地址。
內(nèi)存在使用時(shí),它會(huì)和我們對(duì)應(yīng)的磁盤進(jìn)行輸入輸出數(shù)據(jù),這個(gè)工作我們稱為 IO,其中傳輸數(shù)據(jù)的基本單位為 4KB(1KB = 1024字節(jié))。在此基礎(chǔ)上,內(nèi)存可以被我們劃分為一個(gè)個(gè) 4KB大小空間塊,這個(gè)空間塊我們稱之為 page(頁),如果我們將內(nèi)存想象為一個(gè)大數(shù)組,則內(nèi)存大小或者說對(duì)應(yīng)的頁有:struct page men[4GB/4KB]。只要我們知道某一頁的起始地址,再加上對(duì)應(yīng)的偏移量,我們就可以找到內(nèi)存的任意一個(gè)地址。
———— 我是一條知識(shí)分割線 ————?
頁表簡(jiǎn)介:可以用于建立虛擬地址和物理地址之間的映射關(guān)系,實(shí)現(xiàn)虛擬地址和物理地址的轉(zhuǎn)換。頁表內(nèi)部不是簡(jiǎn)單的對(duì)應(yīng)空間結(jié)構(gòu),因?yàn)槿绻@樣設(shè)計(jì)需要占用 4G*8 = 32G。左式中8的含義 - 假設(shè)空間為1-1對(duì)應(yīng)結(jié)構(gòu),左邊和右邊各一個(gè)數(shù)據(jù),一個(gè)數(shù)據(jù)需要4個(gè)字節(jié)表示(int),加起來則需要8個(gè)字節(jié)。因此,頁表內(nèi)部使用的是多級(jí)頁表的結(jié)構(gòu),就是頁目錄為根,對(duì)應(yīng)多個(gè)二級(jí)、三級(jí)索引這樣的結(jié)構(gòu),這里就不展開細(xì)說了。
下圖中以淺藍(lán)色標(biāo)記為例,虛擬地址0x123445678可以通過頁表映射找到對(duì)應(yīng)的物理地址 0x11112222,物理空間中儲(chǔ)存著 val變量的值為10.
———— 我是一條知識(shí)分割線 ————?
?以下述代碼為例講述程序是如何更改內(nèi)存中的數(shù)據(jù)的?
char val = 100;
首先我們要明確,val的地址是虛擬地址(在第一節(jié)中驗(yàn)證過),當(dāng)代碼運(yùn)行起來時(shí),操作系統(tǒng)拿著 val的虛擬地址,去查找頁表,找到對(duì)應(yīng)的物理地址,將物理地址對(duì)應(yīng)內(nèi)存空間中的數(shù)值修改/存儲(chǔ)為100。至此我們已經(jīng)可以充分認(rèn)識(shí)到程序是如何更改內(nèi)存中的數(shù)據(jù)的原理了。
注意:這個(gè)過程都是由操作系統(tǒng)完成的!
4.操作系統(tǒng)會(huì)根據(jù)進(jìn)程的需求分配虛擬地址空間
進(jìn)程無法直接訪問物理內(nèi)存,進(jìn)程只能通過虛擬地址空間來訪問對(duì)應(yīng)的數(shù)據(jù),其中我們可以認(rèn)為操作系統(tǒng)給進(jìn)程畫了一個(gè)“大餅”(紅色正方形框框),每個(gè)進(jìn)程都以為自己能占有 2^32個(gè)地址空間(內(nèi)存大?。?。
而實(shí)際上,我們通過觀察,發(fā)現(xiàn)堆和棧之間還有很大部分的空缺,不難推斷出,操作系統(tǒng)會(huì)根據(jù)進(jìn)程對(duì)應(yīng)的需求給進(jìn)程分配地址空間,而不會(huì)真的將所有空間都給一個(gè)進(jìn)程。相反,如果進(jìn)程的需求不合理,操作系統(tǒng)會(huì)拒絕進(jìn)程的對(duì)應(yīng)訪問。
四、為什么存在地址空間?
1.防止非法越界訪問
如果進(jìn)程直接訪問物理內(nèi)存,會(huì)存在越界非法操作的風(fēng)險(xiǎn)(比如將儲(chǔ)存有別的數(shù)據(jù)的page覆蓋)
地址空間的存在,使程序員在應(yīng)用層只能通過頁表映射來訪問物理地址,期間操作系統(tǒng)可以幫我們甄別相應(yīng)指令,接收正確指令,拒絕錯(cuò)誤訪問。
2.方便進(jìn)程解耦,保證進(jìn)程獨(dú)立性
進(jìn)程地址空間的存在,可以更方便的讓進(jìn)程與進(jìn)程之間的數(shù)據(jù)進(jìn)行解耦,保證進(jìn)程獨(dú)立性
進(jìn)程具有獨(dú)立性,一個(gè)進(jìn)程對(duì)被共享的數(shù)據(jù)進(jìn)行修改,不能影響其他進(jìn)程。
操作系統(tǒng)為了保證進(jìn)程獨(dú)立性,當(dāng)物理內(nèi)存中的一個(gè)共享數(shù)據(jù)需要被修改時(shí),操作系統(tǒng)會(huì)在物理內(nèi)存中開辟一個(gè)新的空間,數(shù)據(jù)拷貝一份放到新的空間中,然后會(huì)將頁表原來對(duì)應(yīng)共享數(shù)據(jù)空間物理地址改為新空間的地址(更改映射)。這樣,在進(jìn)程改變某個(gè)值的時(shí)候,就只和這個(gè)進(jìn)程本身有關(guān),和其他進(jìn)程無關(guān),實(shí)現(xiàn)了進(jìn)程之間的相互獨(dú)立。
任何一方嘗試寫入,OS先進(jìn)行數(shù)據(jù)拷貝,更改頁表映射,然后再讓進(jìn)程進(jìn)行修改,我們把這樣的行為稱為寫時(shí)拷貝。在我們修改數(shù)據(jù)時(shí),操作系統(tǒng)會(huì)幫我們自動(dòng)完成寫時(shí)拷貝。
寫時(shí)拷貝,幫我們實(shí)現(xiàn)了數(shù)據(jù)間的分離。以下圖為例,在數(shù)據(jù)不做修改時(shí),父子進(jìn)程可以共用同一塊物理內(nèi)存空間,當(dāng)子進(jìn)程對(duì)數(shù)據(jù)進(jìn)行修改,操作系統(tǒng)會(huì)通過寫時(shí)拷貝,實(shí)現(xiàn)數(shù)據(jù)分離,即父進(jìn)程的 g_val變量和子進(jìn)程 g_val變量存儲(chǔ)于不同的物理地址空間中。
每個(gè)進(jìn)程都有自己獨(dú)立的內(nèi)核數(shù)據(jù)結(jié)構(gòu),包括獨(dú)立的PCB、獨(dú)立的地址空間、獨(dú)立的頁表。
結(jié)論:進(jìn)程 = 進(jìn)程的內(nèi)核數(shù)據(jù)結(jié)構(gòu) + 進(jìn)程對(duì)應(yīng)的代碼和數(shù)據(jù),當(dāng)進(jìn)程內(nèi)核數(shù)據(jù)結(jié)構(gòu)和對(duì)應(yīng)數(shù)據(jù)都相互獨(dú)立時(shí),這個(gè)進(jìn)程也就和其他進(jìn)程相互獨(dú)立了。也就是說,地址空間的存在,使進(jìn)程可以擁有獨(dú)立的內(nèi)核數(shù)據(jù)結(jié)構(gòu),可以更方便的讓進(jìn)程與進(jìn)程之間的數(shù)據(jù)進(jìn)行解耦,保證進(jìn)程獨(dú)立性。
3.統(tǒng)一編譯,方便使用
讓進(jìn)程可以以統(tǒng)一的視角,來看待代碼和數(shù)據(jù)的各個(gè)區(qū)域,方便使用;方便編譯器也以統(tǒng)一的視角來編譯代碼,編完可以直接用。
(1)可執(zhí)行文件中有地址嗎?
我們的可執(zhí)行文件中,有沒有地址呢?答案是有的,我們的可執(zhí)行文件中早就有地址了!這種在程序內(nèi)部使用的地址,我們稱它們?yōu)?- 邏輯地址。程序可以通過邏輯地址實(shí)現(xiàn)內(nèi)部之間的相互跳轉(zhuǎn),實(shí)現(xiàn)函數(shù)調(diào)用等功能。
(2)編譯器的編碼方式
編譯器在編譯我們的代碼和數(shù)據(jù)時(shí),會(huì)按照虛擬地址空間的方式給我們的代碼和數(shù)據(jù)進(jìn)行編址,也就是它也會(huì)按照32位的方式進(jìn)行編址。
只有??臻g、堆空間對(duì)應(yīng)的數(shù)據(jù)沒有進(jìn)行編址,因?yàn)樗鼈兪切枰趦?nèi)存中動(dòng)態(tài)申請(qǐng)的。其他的代碼都會(huì)完成編址。
(3)物理地址的來源
程序內(nèi)部使用的地址(邏輯地址),在程序加載到內(nèi)存時(shí),會(huì)天然具有物理地址。因?yàn)檫壿嫷刂泛臀锢淼刂返谋硎痉椒ㄏ嗤?,所以邏輯地址就是物理地址,不用改變。只不過我們?yōu)槌绦騼?nèi)部的地址起了一個(gè)名稱 - 邏輯地址,加以辨識(shí)罷了。
注意:通常情況下,邏輯地址、物理地址、虛擬地址的表示方式是一樣的,都采用32位的數(shù)據(jù)進(jìn)行記錄。這也就是為什么編譯器可以以統(tǒng)一的視角來編譯代碼,編完可以直接用的原因所在。
———— 我是一條知識(shí)分割線 ————
(4)CPU與可執(zhí)行程序交互的原理
代碼編譯好加載到內(nèi)存后,會(huì)生成對(duì)應(yīng)的虛擬地址,且在內(nèi)存中的代碼天然具有物理地址。操作系統(tǒng)會(huì)用?main函數(shù)入口和結(jié)束處的虛擬地址等數(shù)據(jù),初始化進(jìn)程虛擬地址空間(主要是代碼區(qū))和進(jìn)程對(duì)應(yīng)的頁表,再將虛擬地址空間初始化好的地址加載到CPU的寄存器中。
CPU通過虛擬地址,經(jīng)過頁表映射,找到對(duì)應(yīng)物理地址中數(shù)據(jù)并進(jìn)行獲取。CPU讀進(jìn)來的都是指令,指令中包含地址,這里的地址是虛擬地址。
CPU處理完數(shù)據(jù)之后,再將數(shù)據(jù)通過虛擬地址,經(jīng)過頁表映射,寫入到對(duì)應(yīng)物理地址的內(nèi)存中。
具體圖示如下,下圖中的地址都是虛擬地址(物理內(nèi)存中的虛擬地址來源于代碼編譯生成的虛擬地址)
所以,在整個(gè)訪問過程中,CPU輸入輸出的都是虛擬地址,CPU壓根兒就沒有見到物理地址,也即是說CPU不會(huì)對(duì)物理地址進(jìn)行直接訪問。
在我們對(duì)代碼進(jìn)行 debug(調(diào)試)時(shí),程序已經(jīng)運(yùn)行起來了,此時(shí)我們通過監(jiān)視窗口看到寄存器相關(guān)的地址都是虛擬地址。
總結(jié):虛擬進(jìn)程地址的使用,讓進(jìn)程可以以統(tǒng)一的視角,來看待代碼和數(shù)據(jù)的各個(gè)區(qū)域,方便使用;
———— 我是一條知識(shí)分割線 ————
(5)邏輯地址知識(shí)補(bǔ)充
注意:Linux下我們編譯可執(zhí)行程序的格式的編碼格式為 ELF
邏輯地址有兩種常見的編址方式,一種是線性編址方式,另一種是區(qū)域編址方式。這兩種生成的都是邏輯地址,但是因?yàn)?span style="color:#4da8ee;">線性編址編出來的地址和物理地址的表示方法相同,因此當(dāng)程序內(nèi)部使用線性編址時(shí),在程序加載到內(nèi)存之后,該程序就天然具有了物理地址。
- 線性編址(常用)
地址從0開始,假設(shè)普通代碼占了100個(gè)字節(jié)(每個(gè)字節(jié)一個(gè)地址),那么其他數(shù)據(jù)代碼從101個(gè)地址開始,繼續(xù)向下呈線性編址
- 區(qū)域編址(不常用 - 了解)
區(qū)域編址,采用的是區(qū)域起始地址加偏移量的方式,當(dāng)代碼加載到內(nèi)存時(shí),每一個(gè)地址都要做修改才能轉(zhuǎn)換成對(duì)應(yīng)的物理地址。因?yàn)檫@種編制方式,使得地址時(shí)一塊塊區(qū)域區(qū)分開來的,我們可以使用物理地址的起始地址+對(duì)應(yīng)的偏移量,找到對(duì)應(yīng)邏輯地址。
地址從0開始,代碼區(qū)的普通代碼編址完成后,數(shù)據(jù)區(qū)的地址重新從0開始編址,呈現(xiàn)了區(qū)域性。
文章來源:http://www.zghlxwxcb.cn/news/detail-453606.html
結(jié)語?
?????Linux進(jìn)程地址空間 的知識(shí)大概就講到這里啦,博主后續(xù)會(huì)繼續(xù)更新更多Linux操作系統(tǒng)的相關(guān)知識(shí),干貨滿滿,如果覺得博主寫的還不錯(cuò)的話,希望各位小伙伴不要吝嗇手中的三連哦!你們的支持是博主堅(jiān)持創(chuàng)作的動(dòng)力!?????文章來源地址http://www.zghlxwxcb.cn/news/detail-453606.html
到了這里,關(guān)于【Linux初階】進(jìn)程地址空間 | CUP與可執(zhí)行程序的交互原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!