C語言運行時數據結構

段(Segment):

對象文件/可執行文件:

SVr4 UNIX上被稱為ELF(起初"Extensible Linker Format", 現在"Executable and Linking Format")文件。BSD UNIX上被稱為a.out。這些格式都具有段的概念

section是存放特定類型二進制文件區域,section是ELF文件的最小組織單元,段通常由多個section組成

段主要有:

  1. BSS段:Block Started by Symbol,放置全局的但是沒有初始化的變量。由于BSS段的變量沒有任何值,所以不會真的在a.out文件中存儲,所以BSS在a.out文件中不占空間(除了需要指明大小需要部分外),而是在運行時申請
  2. text段:代碼段,放置指令
  3. data段:數據段,放置全局的,而且已經初始化的變量。局部變量不會放到a.out中,而是在運行時創建

示例:

只有main函數:
? ?text ? ?data ? ? bss ? ? dec ? ? hex filename
? 14292 ? ?1532 ? ? 112 ? 15936 ? ?3e40 Hello.exe
定義全局未初始化int:
? ?text ? ?data ? ? bss ? ? dec ? ? hex filename
? 14292 ? ?1532 ? ? 116 ? 15940 ? ?3e44 Hello.exe
定義全局初始化int:
? ?text ? ?data ? ? bss ? ? dec ? ? hex filename
? 14292 ? ?1536 ? ? 112 ? 15940 ? ?3e44 Hello.exe
定義局部未初始化int:
? ?text ? ?data ? ? bss ? ? dec ? ? hex filename
? 14292 ? ?1532 ? ? 112 ? 15936 ? ?3e40 Hello.exe
定義局部初始化int:
? ?text ? ?data ? ? bss ? ? dec ? ? hex filename
? 14308 ? ?1532 ? ? 112 ? 15952 ? ?3e50 Hello.exe

結論:

  1. 全局未初始化的變量放到了BSS段
  2. 全局初始化的放到了data段
  3. 局部未初始化變量只意味著在運行時為其分配空間,而不會在生成可執行文件的時候分配空間或者生成相關的語句,所以不涉及BSS\DATA\TEXT段
  4. 局部初始化變量不涉及BSS和DATA段,而是生成語句執行初始化

操作系統如何處理可執行文件:

段會生成運行時鏈接器可以直接加載的對象,加載器直接把每個段對應到內存中的一部分

這些段就成為執行中程序的一塊實際的內存區域

highest memory address
+------------------------+
?| ? ?stack segment? |
?| ? ? ? ? ? ? ? .? ? ? ? ? ? ?|
?| ? ? ? ? ? ? ? .? ? ? ? ? ? ?|
?| ? ? ? ? ? ? ? .? ? ? ? ? ? ?|
+------------------------+
?| ? ? ?BSS segment? |--未初始化的全局變量
+------------------------+
?| ? ? ?data segment ?|--初始化的全局變量
+------------------------+
?| ? ? ?text segment ? |
+------------------------+
?| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
+------------------------+
lowest memory address

text段:

放置程序指令,是加載器直接從文件中復制過來的。一般情況下,text段不會改變,某些操作系統和鏈接器可以給段的不同section設置不同的權限。比如:text是只讀和只執行的,某些data是只讀的。某些data是讀寫但是不可執行的

data段:

包含了初始化的全局變量和靜態變量,并進行了初始化賦值

BSS段:

在data段生成之后,加載器就從可執行文件中獲取BSS段的大小并獲取相應的空間放到data段后面。通常BSS段和data段會合并在一起,由于段在OS內存管理中只是一段連續的虛擬地址空間,所以相連的會被合并。所以數據段通常是最大的段

局部變量、臨時存儲單元、函數調用的參數傳遞等就需要用到分配的棧空間

對于動態分配的空間還需要堆空間,堆空間是在需要的時候創建的,在第一次malloc()函數調用的時候

需要注意的是虛擬地址空間的最低的一部分沒有映射到物理地址空間,所以任何對這部分地址的引用都是非法的。這部分一般是從0開始的幾個字節空間,null指針或含有很小整數值的指針將指向這里

如果考慮到共享庫文件,那么實際的映射將是這樣的:

highest memory address
+--------------------------+
?| ? ? stack segment ? ?|
?| ? ? ? ? ? ? ? ?. ? ? ? ? ? ? ? |
?| ? ? ? ? ? ? ? ?. ? ? ? ? ? ? ? |
?| ? ? ? ? ? ? ? ?. ? ? ? ? ? ? ? |
+--------------------------+
?| ? ? ? ? ? ?linker ? ? ? ? ? ?|
+---------------------------+
?| unmapped segment|
?| ? ? ? ? ? ? ? ?. ? ? ? ? ? ? ? ?|
+---------------------------+
?| ? ? ? data segment ? ?|
+---------------------------+庫文件
?| ? ? ? text segment ? ? ?|
+----------------------------+
?| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
+----------------------------+
?| ? ? ? data segment ? ? ?|
+----------------------------+庫文件
?| ? ? ? text segment ? ? ? |
+----------------------------+
?| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
+----------------------------+
?| ? ? ? data segment ? ? ?|
+-----------------------------+執行代碼
?| ? ? ? text segment ? ? ? |
+-----------------------------+
?|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
+-----------------------------+
lowest memory address

C運行時如何處理可執行文件:

C在運行時會維護很多數據結構,比如棧、活動記錄、數據、堆等等

棧段:

棧段只包含一個數據結構——棧

經典的棧定義是先進后出的隊列,只有push和pop操作。但是這里的棧不僅可以push和pop還可以改變棧中某位置的值

運行時維護一個指針,通常位于寄存器中被稱為sp,指向棧頂

棧段的作用主要有三個,兩個關于函數,一個關于表達式計算:

  1. 棧為函數中的局部變量提供存儲空間,這些變量被成為"自動變量"
  2. 棧保存函數調用時需要的維護信息,被稱為"程序活動記錄"。包含調用結束時的返回地址、不能放到寄存器中的參數和保存調用前的寄存器狀態
  3. 棧也可以作為高速暫存寄存器,當程序需要臨時存儲的時候使用。如長表達式的計算,中間結果會被放到棧中并在使用的時候取出

alloca()函數分配的空間也在棧中,但是這部分空間會被下一次函數調用重寫

如果不是有函數遞歸調用,棧是不被需要的。如果沒有遞歸調用,局部變量、參數需要的空間和返回地址都可以在編譯器知道并且在BSS段分配

程序活動記錄

活動記錄的目的是追蹤調用鏈,每次調用函數都會在棧中生成一個活動記錄,活動記錄支持函數的調用以及記錄調用結束后需要恢復的狀態。具體活動記錄的設計和實現相關,活動記錄內部各區域的順序可能各不相同,也可能有一個區域存儲函數調用之前的寄存器值

大多數現代程序語言都支持函數內部定義函數(和數據一起)。但是C不允許函數嵌套聲明,所有的函數都必須在詞法頂層。這種限制能夠一定程度的簡化C編譯器實現

在允許嵌套函數的語言中,活動記錄會包含一個指向其外部函數的指針,這個指針被稱為靜態鏈接(static link)(和編譯文件時的靜態鏈接區分一下),這個指針允許內部函數獲取外部函數的棧幀

雖然可能一個外部函數同時被多次調用,但是靜態鏈接總能指向正確的棧幀,訪問到正確的局部數據

對外部函數數據的獲取被稱為上層引用(uplevel reference)

之所以被稱為靜態鏈接,是因為對其外部函數的指向是在編譯期確定的,而動態鏈接是運行時被調用時指向其調用者的棧幀

典型的活動記錄如下:
+-------------------------+
?| ? ? ? ? local vars? ? ? ?| -- 存儲如調用結束時需要恢復得寄存器值等
+-------------------------+
?| ? ? ? arguments ? ? ? | -- 參數
+-------------------------+
?| ? ? ? prev frame ? ? ? | -- 調用者的棧幀
+-------------------------+
?| ? ? ? return addr ? ? ?| -- 返回地址
+-------------------------+

每次調用函數都會生成一個這樣的活動記錄。但是編譯器作者會盡量的減少存儲的信息以提高程序的性能,比如:

  1. 用寄存器存儲某些信息而不是在棧中
  2. 對于葉函數(不會調用其他函數的函數)不生成完整的棧幀,調用者不再存儲寄存器的值而是讓被調用者存儲
  3. 使用指向調用者棧幀的指針可以簡化函數返回時彈棧到先前記錄的工作

auto和static

auto的變量是函數調用時在棧中分配空間存儲的,函數調用結束的時候對應的棧空間就會被釋放并且可以被重寫。所以如果函數返回一個指針指向局部變量就會返回一個"懸空指針",指向的值不是有效的。

如果想要返回一個函數中定義的變量,可以將其定義為static。static變量不是存儲在棧中,而是在數據段分配空間存儲。這樣變量就會在程序的生命周期中存在,即便函數調用結束數據也依然存在,下一次函數調用還可以訪問

棧幀不一定在棧中

如果把活動記錄放到寄存器中會有更好的性能。SPARC架構以"寄存器窗口"來提高棧幀的性能。芯片中有一組專門用來存放活動記錄中的參數的寄存器。空的棧幀還會被壓入棧中,如果調用鏈過長導致寄存器窗口被用光,那么就會通過把寄存器中的值填充到對應的空棧幀中來釋放寄存器?

線程控制:

每個線程都會有自己的棧并且用red zone和其他線程的棧結構區分

setjmp和longjmp

它們通過操縱活動記錄實現,這個特性彌補了C在跳轉能力上的不足

工作方式:

  1. setjmp(jmp_buf j)首先被調用,用變量j記錄當前語句所在的位置,調用后返回0
  2. longjmp(jmp_buf j,int i)在setjmp之后調用,返回j記錄的地址,使之看起來像是從函數setjmp()返回,而且返回值是整數i,用以區分這是從longjmp()返回的
  3. j的內容在使用longjmp()之后被銷毀

setjmp()保存了當前程序計數器和當前棧頂指針的內容。然后longjmp()恢復這些內容,高效的將控制流轉移到原來的位置恢復保存的狀態。并且會回退所有保存的棧頂之前的棧空間

和goto的不同:

  1. goto語句無法跳出當前函數,但是longjmp甚至可以調到另一個文件的函數
  2. longjmp只能回到之前控制流到過的某個地方,即設置了setjmp()并且被執行過的地方

setjmp/longjmp最有用的地方是錯誤恢復。只要你沒有從函數返回,如果發現了一個不可恢復的錯誤,你就可以移動控制流到之前的某個節點,然后從那里重新開始。可以用來從多重函數調用中立即返回,也可以用來預防危險的代碼
如:

switch(setjmp(jbuf)) {?case 0: ?apple = *suspicious; ?break; ?case 1: ?printf("suspicious is indeed a bad pointer\n"); ?break; ?default: ?die("unexpected value returned by setjmp"); ?
}

如果在某個地方檢測到了這個指針危險,就可以返回到這里

就像goto語句,setjmp/longjmp也會導致程序難以理解難以調試,所以要盡量避免使用

UNIX下的棧段:
棧隨著程序需要增長,程序員可以認為棧是無限大的

UNIX使用某種虛擬內存模式,當嘗試獲取超過分配的空間的空間的時候就會產生一個頁錯誤,處理方式依賴于引用是否有效。內核處理非法引用的方式通常是向產生錯誤引用的程序發送一個信號。在棧頂之后有一個red zone,對這里的引用不會產生錯誤,操作系統相應的會增加棧空間的大小,虛擬地址空間會相應的增加

MS-DOS的棧段:
DOS中棧的大小是由可執行文件指定的,而且不能再運行時修改,對超過空間的訪問會導致程序失效。如果打開了檢查,就會產生棧溢出錯誤。如果超出了段的限制,也會在編譯器產生這個錯誤。Turbo C如果數據段或代碼段過大,會產生Segment overflowed ? maximum ?size ?<lsegname>,80x86架構限制為64Kbytes

轉載于:https://www.cnblogs.com/biaoJM/p/10186679.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/395866.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395866.shtml
英文地址,請注明出處:http://en.pswp.cn/news/395866.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java掛起線程

2019獨角獸企業重金招聘Python工程師標準>>> 不優雅的suspend import java.util.concurrent.TimeUnit;public class SuspendTest {static Object lock new Object();SuppressWarnings("deprecation")public static void main(String[] args) {Suspend s1…

Hibernate包及相關工具包下載地址

Hibernate包及相關工具包下載地址&#xff1a; http://prdownloads.sourceforge.net/hibernate/ 這里包含所有hibernate各個版本的包下載&#xff0c;且提供了 Middlegen Hibernate及hibernate-extensions包的下載。這兩個包是用于自動生成相就的JAVA和*.hb…

init(coder:)_2018年《 New Coder》調查:31,000人告訴我們他們如何學習編碼并在工作中獲得工作…

init(coder:)More than 31,000 people responded to our 2018 New Coder Survey, granting researchers an unprecedented glimpse into how adults are learning to code.超過31,000人對我們的2018年《新編碼器調查》做出了回應&#xff0c;使研究人員對成年人如何學習編碼有了…

Redis源碼解析:21sentinel(二)定期發送消息、檢測主觀下線

六&#xff1a;定時發送消息 哨兵每隔一段時間&#xff0c;會向其所監控的所有實例發送一些命令&#xff0c;用于獲取這些實例的狀態。這些命令包括&#xff1a;”PING”、”INFO”和”PUBLISH”。 “PING”命令&#xff0c;主要用于哨兵探測實例是否活著。如果對方超過一段時間…

[SDOI2018]原題識別

題解&#xff1a; 。。感覺挺煩得 而且我都沒有注意到樹隨機這件事情。。 就寫個30分的莫隊。。 #include <bits/stdc.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (int ih;i<t;i) #define dep(i,t,h) for (int it;…

django app中擴展users表

app models中編寫新的User1 # _*_ coding:utf-8 _*_2 from __future__ import unicode_literals34 from django.db import models5 from django.contrib.auth.models import AbstractUser # 繼承user67 # Create your models here.8910 class UserProfile(AbstractUser):11 …

[bzoj2301] [HAOI2011]Problem b

Description 對于給出的n個詢問&#xff0c;每次求有多少個數對(x,y)&#xff0c;滿足a≤x≤b&#xff0c;c≤y≤d&#xff0c;且gcd(x,y) k&#xff0c;gcd(x,y)函數為x和y的最大公約數。 Input 第一行一個整數n&#xff0c;接下來n行每行五個整數&#xff0c;分別表示a、b、…

華為p4用鴻蒙系統嗎_華為p40pro是鴻蒙系統嗎

華為的鴻蒙OS是一款“面向未來”的操作系統&#xff0c;一款基于微內核的面向全場景的分布式操作系統&#xff0c;此前mate30系列并沒有搭載鴻蒙系統。那華為p40pro是鴻蒙系統嗎&#xff1f;品牌型號&#xff1a;華為p40pro華為p40pro是鴻蒙系統嗎&#xff1f;華為p40pro沒有搭…

設置MYSQL允許用IP訪問

mysql>use mysql;mysql>update user set host % where user root;mysql>flush privileges;mysql>select host,user from user where userroot;mysql>quit 轉載于:https://www.cnblogs.com/vipstone/p/5541619.html

Web優化 --利用css sprites降低圖片請求

sprites是鬼怪&#xff0c;小妖精&#xff0c;調皮鬼的意思&#xff0c;初聽這個高端洋氣的名字我被震懾住了&#xff0c;一步步掀開其面紗后發覺非常easy的東西。作用卻非常大 什么是CSS Sprites CSS Sprites是指把網頁中非常多小圖片&#xff08;非常多圖標文件&#xff09;做…

[BZOJ3203][SDOI2013]保護出題人(凸包+三分)

https://www.cnblogs.com/Skyminer/p/6435544.html 先不要急于轉化成幾何模型&#xff0c;先把式子化到底再對應到幾何圖形中去。 1 #include<cstdio>2 #include<algorithm>3 #define rep(i,l,r) for (int i(l); i<(r); i)4 typedef long long ll;5 using names…

輕松創建nodejs服務器(1):一個簡單nodejs服務器例子

這篇文章主要介紹了一個簡單nodejs服務器例子,本文實現了一個簡單的hello world例子,并展示如何運行這個服務器,需要的朋友可以參考下我們先來實現一個簡單的例子&#xff0c;hello world。 似乎每種語言教程的第一節都會講這個&#xff0c;我們也不例外。 首先我們先創建一個項…

誰是贏家_人工智能競賽正在進行中。 這是贏家。

誰是贏家by Terren Peterson由Terren Peterson 人工智能競賽正在進行中。 這是贏家。 (The race is on for artificial intelligence. Here’s who is winning.) On Saturday, Louisville, Kentucky hosted the 143rd running of the Kentucky Derby. It was a spectacle wher…

mysql取消mvvc機制_MySQL探秘(六):InnoDB一致性非鎖定讀

一致性非鎖定讀(consistent nonlocking read)是指InnoDB存儲引擎通過多版本控制(MVVC)讀取當前數據庫中行數據的方式。如果讀取的行正在執行DELETE或UPDATE操作&#xff0c;這時讀取操作不會因此去等待行上鎖的釋放。相反地&#xff0c;InnoDB會去讀取行的一個快照。上圖直觀地…

自動化腳本

自動化腳本工具: http://appium.io/slate/cn/master/?python#about-appium 查看app元素工具: uiautomatorviewer http://www.cnblogs.com/ITGirl00/p/4235466.html app 反編譯原理 http://blog.csdn.net/jiangwei0910410003/article/details/47188679轉載于:https://www.cnblo…

springmvc常用注解之@Controller和@RequestMapping

對于各種注解而言&#xff0c;排第一的當然是“Controller”,表明某類是一個controller。 “RequestMapping”請求路徑映射&#xff0c;如果標注在某個controller的類級別上&#xff0c;則表明訪問此類路徑下的方法都要加上其配置的路徑&#xff1b;最常用是標注在方法上&…

最小可行產品是什么_無論如何,“最小可行產品”到底意味著什么?

最小可行產品是什么by Ravi Vadrevu通過拉維瓦德雷武(Ravi Vadrevu) 無論如何&#xff0c;“最小可行產品”實際上是什么意思&#xff1f; (What does “Minimum Viable Product” actually mean, anyway?) 伊隆馬斯克(Elon Musk)提出一個令人困惑的想法 (Elon Musk on makin…

站立會議12-2

編寫團隊博客&#xff0c;進行資料的查看轉載于:https://www.cnblogs.com/qijun1120/p/10247725.html

徹底刪除mysql server 2005_sql2005卸載工具(sql server 2005卸載工具)

如果您要安裝新版的sql就必須先完整的卸載sql2005&#xff0c;如果你按照常規的方法是不能完整的卸載sql2005&#xff0c;從而會引起安裝的時候說sql已經掛起的錯誤&#xff0c;sql2005卸載工具(sql server 2005卸載工具)&#xff0c;是一個幫你完整的清理已經安裝的sql的工具。…

谷歌瀏覽器有時會卡頓_Google不會,不要學:為什么搜索有時會比了解更好

谷歌瀏覽器有時會卡頓by Jeremy Gunter杰里米甘特(Jeremy Gunter) Google不會&#xff0c;不要學&#xff1a;為什么搜索有時會比了解更好 (Google not, learn not: why searching can sometimes be better than knowing) A few months ago, I was reading through some of th…