程式源**被編譯後生成的機器指令被放在**段(.text);全域性變數和區域性靜態變數被放在資料段( .data );
除此之外還有程式裡邊的唯讀變數(如const修飾的變數)和字串常量被分配在唯讀資料段( .rodata ),
注釋資訊段( .comment ),堆疊提示段(.nute.gnu-stack)。
未初始化的全域性變數和靜態區域性變數的預設值都是0,為他們在資料段分配空間是不必要的,所以將它們放在.bss 的段中。 在.bss這個空間中,只是為未初始化的全域性變數和靜態區域性變數預留位置而已,並不做其他工作,沒有內容,不佔記憶體空間。等到最終鏈結成可執行檔案的時候再在 .bss 段分配空間。
程式源**被編譯後主要被分成兩部分:程式指令和程式資料。**段(.text)屬於程式指令,資料段( .data )和 .bss屬於程式資料。
將程式指令和程式資料分開的優勢有三:
(1)兩者許可權不同,可以防止被改寫。資料區域對程序來說是可讀可寫的,而指令區域唯讀,放在不同的區域也就是說放在兩個不同的續存區域,可以防止程式的指令被改寫。
(2)chcha(快取)中資料快取和指令快取相分離。程式的指令和資料分開對提高cpu的快取命中率有很大的好處。
(3)在子程序中,程式段是可以共享的,但是資料段是私有的。系統中執行著多個程式的副本的時候,指令都是一樣的,只需要儲存乙份指令即可 。
段表:段表是儲存段的基本屬性的結構,描述了每個段的資訊,包括每個段的段名,短的長度,在檔案中的偏移,讀寫許可權以及其他的屬性。可以說,段結構是由段表決定的,編譯器,聯結器和裝載器都是依靠段表來定位和訪問各個段的屬性的。段表的結構比較簡單,是乙個以結構體為元素的陣列。陣列元素的個數等於段的個數。段表由n個結構體陣列組成。陣列元素的個數與它的個數相同,其中第乙個是無效描述符為null,所以一共有的段表數量為陣列元素減去一。
sh_name:段名
sh_type:段的型別
sh_flags:段的標誌位
sh_addr:段虛擬位址
sh_offset:段偏移
sh_size:段的長度
sh_addralign:短位址對齊
段的型別:
段的名字只是在編譯和鏈結的過程中有意義,並不能真正的表示段的型別。對於編譯器和鏈結器來說,主要決定段的屬性的是段的型別和段的標誌位。
在連線中,函式和變數統稱為符號,函式名或變數名就是符號名。整個鏈結過程就是以內符號才能完成。符號表用來管理,記錄目標檔案中用到的所有符號,每乙個定義的符號都有乙個對應的值,叫做符號值。對於變數和函式來說,符號值就是它們的位址。
符號表:符號表與段表結構類似,均為結構體陣列。
成員包括:
st_ name:符號表。包含該符號名在字串表中的下標
st_value:符號相對應的值,可能是乙個絕對值,也可能是乙個位址。不同的符號所對應的值的含義不同。
st_size:符號大小。對於包含資料的符號,這個值是該資料型別的大小。比如乙個double型別的符號佔8個位元組,如果這個值為4,表示這個符號佔4個大小的位元組。
st_info:符號型別和繫結資訊。
st_shndx:符號所在的段。
由於不同的編譯器採用不同的名字修飾方法,必然會導致由不同的編譯器編譯產生的目標檔案無法正常相互鏈結,這是導致不同的編譯器之間不能互相操作的主要原因。
目標檔案裡有什麼
1.text段是 段,比如main程式就存放在這裡 data段存放已初始化的資料而且初始化不為0 bss段存放未初始化或初始化為0的資料 英文含義 以符號開始的塊 在這裡我們引發出幾個問題 1 我們都知道.bss段不佔空間,它到底不佔 的空間?虛擬位址空間還是檔案空間?答案是檔案空間,因為對於.bs...
目標檔案裡有什麼?
目標檔案從結構上講,它是已編譯後的可執行檔案格式 windows的.obj或linux的.o 只是還沒有經過鏈結的過程。它跟可執行檔案的內容和結構很類似,所以一般跟可執行檔案格式一起採用一種格式儲存。無論是linux下的elf executable linkable format 或windows下...
知識積累 目標檔案裡有什麼(1)
程式源 被編譯後主要分成兩種段 程式指令和程式資料,屬於程式指令,而資料段和.bss屬於程式資料。為什麼程式指令和資料不混在在一起而是分開放?1.因為程式被裝載後,資料和指令分別被對映到兩個虛存區域。由於資料區域對於程序來說是可讀寫的。而指令區域對於程序來說是可讀的。所以這兩個虛存區域的許可權可以分...