2013-04-15 56 views
6

我想了解.rdata部分與.text部分的含義。我想一個簡單的程序如下什麼時候放置在`.rdata`部分而不是`.text`部分?

int main() 
{ 
    const int a = 10; 
    printf("%d\n", a); 
    return 0; 
} 

當我建立並通過gcc -o a.out sample.c -Wl,Map,test.map轉儲map文件,然後搜索sample.o,我發現下面的分配現在

.text   0x0040138c  0x34 sample.o 
.data   0x00402000  0x0 sample.o 
.rdata   0x00403064  0x8 sample.o 
.eh_frame  0x00404060  0x38 sample.o 
.bss   0x00405020  0x0 sample.o 

,如果我稍微修改我的計劃使a一個全局變量作爲

const int a = 10; 
int main() 
{ 
    printf("%d\n", a); 
    return 0; 
} 

通過重複與上述相同的步驟,我觀察噸帽子的分配情況如下

.text   0x0040138c  0x2c sample.o 
.data   0x00402000  0x0 sample.o 
.rdata   0x00403064  0xc sample.o 
.eh_frame  0x00404060  0x38 sample.o 
.bss   0x00405020  0x0 sample.o 

其中它清楚地表明a被分配到.rdata部分作爲

.rdata   0x00403064  0xc sample.o 
       0x00403064   a 

從這些實驗,我明白globalconst被alocated爲.rdata部分,而.text節規模已經下降。因此,我假設a被分配到第一個例子中的.text部分。

我的問題是:當確定.rdata.text它的位置

  1. 被認爲是const變量的範圍是什麼?

  2. 從我的實驗中,我發現變量在分配到.text部分時需要8個字節,而在.rdata部分中則需要4個字節。這種差異的原因是什麼?

  3. 如果當地const變量太多,則相應的.text部分的大小將顯着增加。在這種情況下推薦的編程習慣是什麼?

非常感謝提前。

回答

5

在第一種情況中,變量聲明爲局部變量。它具有「自動」存儲時間,這意味着它在封閉範圍的末端消失。由於存儲時間長短,無法永久佔用任何內存(無論const如何,都是如此)。因此,它通常存儲在堆棧或寄存器中。

在第二種情況下,變量聲明爲全局變量。它具有靜態存儲持續時間,所以它在程序的整個生命週期內都會持續存在。這可以存儲在許多地方,如.data,.bss,.text.rdata(或.rodata)。

.data通常用於具有一些預定義(非零)內容的可寫靜態數據,例如,全球int foo = 42;.bss用於初始化爲零(或未初始化)的可寫靜態數據。 rdata用於恆定的靜態數據,如字符串和const變量。當然,這些用途都是「一般」,並且可能因編譯器而異。

那麼爲什麼.text在第一種情況下變大?這是因爲編譯器必須生成一些額外的指令才能在堆棧或寄存器中加載10

2

此行爲將有所不同,從目標到目標。在第一個示例中,您認爲a.text部分結尾,它是10(可能)在文本部分中結束,並加載到堆棧中的a。有些例如pc相對尋址的體系結構會將這些常量放在代碼之間的某處。其他體系結構會將10編碼爲立即尋址模式,這也會導致代碼大小稍大。

在第二個示例中,a是一個全局變量,它將位於.data部分,這也是您觀察的部分。

因此,讓我們回想一下上述問題。

  1. 用C const並不意味着它是一個常數(嗚??),則意味着程序員承諾不寫。編譯器將警告如果你這樣做,或者如果你有這樣做的危險,但仍然會編譯。因此,您的案例之間的差異實際上是a是第一個示例中的局部變量,第二個示例中是全局變量。嗯,我只是試圖公然寫作const int,它確實給出了一個錯誤,而不僅僅是一個警告。然而,通過引用可以改變它的函數來傳遞這樣的const是可能的。編譯器甚至可能不會檢測到交叉單元的東西。

  2. 如果它位於.data部分,則它是對象的大小,在您的情況下是4個字節。如果10位於代碼中,無論是在常量表中還是作爲立即尋址模式,那麼它確實取決於體系結構有多大,以及對周圍代碼的影響。

  3. 如果你的代碼中有很多常量,而且這個架構支持與pc相關的尋址(比如ARM),那麼它可能會將所有那些常量定位在它們使用的代碼附近,但所有常量都是這樣跳過就可以跳過它,或者如果有一個常數表可以隱藏的自然分支,則跳過它。因此,常數需要的空間大小和數量不多(多)。如果它們全都被實現爲立即尋址,那麼如果有更有效的方式來獲得常量,編譯器可能仍然決定從中創建一個表。

+0

感謝您提供非常豐富的回覆。我確實有幾點要澄清。其一,在我的問題中,與'.data'部分相比,變量位於'.rdata'部分。問題的主要目標是理解只讀部分的處理,即「.rdata」和「.text」。至於第1點,我相信'const',儘管我們可能通過類型轉換欺騙編譯器,但運行時會拋出異常。例如:http://cfiddle.net/zsPfEg。 – Ganesh

+0

對不起另一個問題:你提到了PC相對尋址。在嵌入式系統中,我可能會靈活地將特定的代碼段加載到更快的存儲器(用於支持此功能的TI DSP-BIOS)。在這種情況下,如何處理偏移計算,因爲當前PC可能位於SDRAM中,而實際數據位於SRAM中? – Ganesh

+0

關於SDRAM vs SRAM的問題超出了我的想象。其他人應該幫助你。我會假設常量表也將被移動到SDRAM。 –