要執行一隻程式須將它的 instruction 跟 data load 到 memory。現代 OS 結合 virtual memory 以及 memory management 的 paging 機制來 load process。
virtual memory 將 process 認知的 memory space 跟 physical memory 分離,藉此達到 process 不一定要在它認定的 physical memory address 上執行。如果實際有的記憶體比較少,virtual memory 也可以在記憶體不足的情況下讓 process 以為它有這麼多 memory 可用。
每個 process 有自己的 virtual memory space,virtual memory space 的大小由平台的定址 bit 數決定,例如 32 bit 的平台可定址的 address 就從 0 到 2^32 - 1,總大小為 4 GB。process 在 32 bit 系統中的 virtual memory space 大小是 4GB,但不是 4GB 都可以為 process 使用,process 只能用 OS 分配給它的空間,亂用的話會被強制結束。
paging 簡單來說是將 memory space 分成固定 size 的 page,現在 OS 大多使用 4K size 的 page。virtual memory space 跟 physical memory space 都以 page 切分,MMU(Memory Management Unit)負責 virtual page 與 physical page 的 mapping。virtual page 不存在 physical memory 而該 virtual page 又要被使用時會發生 page fault,此時 OS 負責將 virtual page 從 disk 中讀到 memory 並建立 virtual page 與 physical page 之間的 mapping。
結合 virtual memory 跟 paging 的 load process 步驟:
建立這個 process 的 virtual memory space,實際上是建立 virtual page 對應到 physical page 所需的 data structure。
由 executable file header 的資訊建立 virtual space 與 executable file 的關係,也就是 process 的 virtual memory space 哪一塊對應到 executable file 的哪一塊。
將 PC register 設到執行入口,process 開始執行。
process 執行到的程式或需要的 data 沒有 load 進 physical memory,發生 page fault。OS 依照 virtual space 與 executable file 的對應關係知道要從 disk load 哪個 page 到 physical memory,load 進 physical memory 後建立 virtual apge 與該 physical page 的關係,這段即一般講 load 所指的動作。控制權還給 process 繼續跑。
Symbol table '.symtab' contains 11 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 7: 0000000000000000 0 SECTION LOCAL DEFAULT 5 8: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 sum 9: 0000000000000000 26 FUNC GLOBAL DEFAULT 1 main 10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND foo
Relocation section '.rela.text' at offset 0x2a0 contains 3 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000014 000c00000002 R_X86_64_PC32 0000000000000000 sum - 4 00000000001b 000300000002 R_X86_64_PC32 0000000000000000 .data + 0 00000000001f 000c0000000b R_X86_64_32S 0000000000000000 sum + 0
Relocation section '.rela.data' at offset 0x2e8 contains 1 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000008 000300000001 R_X86_64_64 0000000000000000 .data + 10
Relocation section '.rela.eh_frame' at offset 0x300 contains 1 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
$ readelf -r main.o
Relocation section '.rela.text' at offset 0x238 contains 1 entries: Offset Info Type Sym. Value Sym. Name + Addend 00000000000f 000a00000002 R_X86_64_PC32 0000000000000000 foo - 4
Relocation section '.rela.eh_frame' at offset 0x250 contains 1 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
symbol 的 definition 可分為 strong symbol 跟 weak symbol。C/C++ 的 compiler 預設 function 及有初始化的 global variable 為 strong symbol,未初始化的 global variable 為 weak symbol。strong & weak symbol 跟處理 symbol 重複定義有關:
GCC 中可用 __attribute__((weak)) 來定義一個 strong symbol 為 weak symbol:
weaksym.cpp
1
__attribute__((weak)) int x = 2; // weak symbol
main.cpp
1 2 3 4 5 6 7 8
#include<iostream>
int x = 123; // strong symbol
intmain(){ std::cout << x << endl; // result is 123 return0; }
weak symbol 可以在 link time 置換 function。一開始給個預設 implementation 並設為 weak symbol,使用者可以寫 function 編成 object file 去 link。由於使用者寫的是 strong symbol 會蓋掉原本的 default implementation,達到 link 階段換 implementation。