catalog
- 程式
程式
我們寫的程式,需要經過(編譯,鏈接)得到 最終的exe/elf(產生到 磁盤上),
如果我們要運行他,必須要把他加載到 記憶體里! 因為cpu訪問記憶體的速度 要比訪問磁盤,速度快千萬倍
cpu的位數,是指: 他一次性能夠進行運算的 整數的寬度,因為cpu是在ALU里運算資料
所以, cpu的位數 其實是 ALU的寬度(即,資料總線的 條數)
但是, cpu的位數 不一定等于 地址總線的 條數,他等于的是 資料總線的條數
比如虛擬地址是4GB,(物理記憶體不一定是4GB!!),他的布局格式是:
-
[0 - 3GB]這個地址區域,稱為 用戶空間-
[0 - 128MB]是forbidden禁止的! 他是禁止訪問的,連訪問都不能,更不能寫!! -
[128MB - 3GB],這是我們程式可以使用的 虛擬地址區域
第一個區域,他劃分為有:[.text] [.data] [.bss]
我們知道,一個程式無非是:(指令) + (資料)
指令是在:.text段, 資料是在:.data段 和 .bss段緊接著 第二個區域: heap 堆空間
第三個區域:用來放到dll共享庫的!
比如,你用了很多scanf這種函式,他在頭檔案里 只有宣告,并沒有定義, 但是,等到鏈接時,程式會自動的 鏈接一些系統的庫,第四個區域:
[.stack]段
因為,我們程式的運行 就是從入口函式開始遞回,這個段就是供我們函式運行的;比如,你的區域變數 就會在這個.stack段里,第五個區域: 放命令列引數、環境變數,
main函式的引數 argv這些
-
-
[3 - 4GB]這個地址區域,稱為 內核空間,即OS運行的空間
第一個區域是:ZONE_DMADMA: direct memory access,加速 磁盤和記憶體 交換資料用的
在沒有DMA技術前,磁盤和記憶體交換資料時: 磁盤資料 必須經過總線,流經 cpu的暫存器,最終才能到達記憶體
這是對cpu的 極大浪費,
有了DMA,比如加載一個檔案 從磁盤 通過總線 到記憶體中時,不需要使用cpu的暫存器!!!
cpu遇到這種情況,他就會空閑下來,來調度其他的行程!!第二區域: `ZONE_NORMAL` 第三區域: `ZONE_HIGHMEM`
int a = 1;
int b = 0;
int c;
static int d = 1;
static int e = 0;
static int f;
int main(){
int g = 1;
int h = 0;
int i;
static int j = 1;
static int k = 0;
static int l;
return 0;
}
這個程式中,屬于 指令的是: int main(){ int g = 1; int h = 0; int i; return 0; },即他們是在 .text段,
因為這些,要么是函式,要么是區域變數,可以多次呼叫 是屬于指令, 即注意,區域變數 屬于的是 指令!
而對于: 全域變數 + 區域static,這些都是 資料(即這些,在程式的運行,自始至終 都是占著記憶體的)
其中,已經初始化的 且不為0 的變數 a,d,j 是在 .data段,即.data段的大小 是12,
常量(比如"hello"),他是在 .rodata段
沒有初始的 或 初始為0的,是在.bss段,
關于.bss段,有幾個資訊:
-
在.obj檔案里,
[elf header] [.text] [.data] [.bss] [.comment] [section table]
但其實你會發現,.comment段 和 .bss段在檔案里的地址,其實是一樣的!!
而這兩個段 大小都不是0,為什么是一樣的呢?
其實,.bss段 他在obj檔案里 其實是不占空間的!!! 其實就沒有這個段,.data后面就是.comment
.bss段 只會占的是: 虛擬空間里的記憶體!! 而不占.obj檔案里的空間而,這個
.bss段 在.obj檔案 是不存在的,那他怎么知道 這個段里的那些全域/static變數呢?
通過讀section table段表,他里面會記錄 每個段的詳細資訊,bss的資訊 可以通過他來獲取.bss段,沒必要在檔案中存盤,這是因為: .data段里存的 都是初始值,即程式一運行 這些值就必須初始化為(用戶指定的值)
但是,.bss段里的 他的值 都是0,就不用在檔案里存盤他了,這樣減少檔案的大小 -
按理說,該有6個變數 是在.bss段, 但是,為什么
1不是在.bss段呢?main.c short x = 10; short y = 10; extern void func(); int main(){ func(); } test.c int x; void func(){ x = 20; }這個專案,在c++里 肯定是錯誤的,因為有2個x,c++里 所有的符號
變數/函式,都不能重名,
而在c里,他存在強符號(初始化了的) 和 弱符號(未初始化的)的區別,這里:short x是強符號,int x是弱符號
(強符號:只能有1個,即初始化的 只能有1個)(弱符號:可以有多個,即未初始的 可以有多個,不管是什么型別)
(在鏈接后,優先使用強符號; 沒有強符號,則優先使用記憶體最大的弱符號)即,在專案進行鏈接完后,func()函式里 所使用的x,其實是:short x這個
func函式里他的匯編是: 往x 寫4個位元組的記憶體,這是在單獨編譯test.c 就確定下來的匯編指令,
而最終鏈接后,這個匯編指令 肯定是不變的,但這個x 并不是int,而是short
所以,20的4位元組是: 14 00 00 00,前面的14 00 給short x,后面的00 00 給short y,所以,最終:x = 20, y = 0 {x是指的short這個}int c;這個全域變數,他是不在.bss段的,
因為:int b = 0;初始了,他是強符號雖然c++沒有強弱符號,但這個程式 也可能是c的!!
int c;未初始,弱符號, 他會在另外一個COM段,不是在bss段,因為他可能被其他obj里的強符號所頂替
其他的,都是static,static,是本檔案可見!!!他是強制性的!!即,即使是一個static的弱符號,在本檔案里 也不會被其他強符號替代!
static還有個名字,是local,即本地的 本檔案的,其他檔案,也看不到這個檔案里的static變數,
os會 運行很多的行程,這些行程 所使用的虛擬空間,其中他們的內核區域[3 - 4GB]區域 都是共享的,因為只有1個作業系統
但用戶空間,他是 獨立的,每個行程的 用戶空間,肯定都是不同的,
當程式要運行時,即變成行程,要進行下面幾個步驟:
- 從虛擬地址 到 物理記憶體 的 映射,創建 頁目錄 和 頁表
- 加載 .text段 和 .data段
- 把該exe的入口地址,寫到 pc暫存器里,
ELF header里,有個entry point address,到時候這個行程運行時,這個地址 就會放到cpu的 pc暫存器里,即為該程式的入口地址
== 2:00 https://www.bilibili.com/video/BV1xf4y127AJ ==
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302981.html
標籤:其他
下一篇:一個奔四程式員的焦慮
