1 4 3重定位 使用C語言清除BSS段

2021-10-06 23:11:45 字數 1659 閱讀 6515

使用c語言清除bss段,我們肯定要獲取bss段的起始位址和結束位址,那麼,c語言要怎麼實現使用lds檔案中的變數abc?

答:需要以下兩步,這兩步是重點

在函式中宣告該變數為extern型別(型別不重要,因為我們主要是取值,具體原因後面會說);

使用時,要取址,比如, int *p = &abc;//p的值即為lds中abc的值。

比如下圖中,使用extern宣告**段的起始位址和bss段的起始位址,然後取值用指標進行複製操作,這樣lds中的變數也可以像c語言中的普通變數一樣操作。(實際上,它們和c語言中的變數不同。

在c語言中需要宣告,那麼在彙編指令中,為什麼可以直接使用?(如下圖,為重定位和清除bss段的彙編**)

下面開始解答:

在c函式中,如果我們宣告如下變數。這樣,該變數為全域性變數:

int g_i;

//程式中必然有四位元組空間來儲存這個變數

但是,如果我們在lds鏈結檔案中宣告了a1,a2,a3…an個變數,那麼,.bin檔案中是不會儲存這些變數的,這是為啥?

答:這是因為c程式中不儲存lds檔案中的變數(因為一般用不到),而且真正要用到的時候,我們也並不是沒辦法。

我們編譯程式時,有乙個symbol table符號表,萬一要用這些變數,可以通過這個符號表在鏈結的時候使用。

以上面為例,除了g_i,我們再宣告兩個變數:

int g_i, g_j, g_k;
那麼在鏈結的時候,會有乙個符號表如下:

畫質不好,但是還是能看懂的。這裡每個圈表示乙個變數,乙個變數由名字和位址構成。顯然,c語言中的變數,名字即為變數名,位址即為變數的位址。但是,我們前面說過,.bin檔案中不會儲存lds檔案中的變數,所以lds檔案中的變數,位址填的是值,名字則還是變數名。所以,我們在copy2sdram函式中才要使用取址符號來修飾這個lds變數,因為它的位址才是它的值。

另外,我們要明白。

這個符號表只存在於鏈結時,作用是輔助鏈結,不存在與.bin檔案中。lds檔案中,無論變數還是常量,裡面的值都來自於鏈結指令碼,在鏈結時由編譯器決定。

在使用上,他們和c語言中的普通變數是不同的:

對於g_i,它是乙個c語言變數,使用&g_i就可以得到它的位址addr;對於lds中的a1,他們沒有位址,因為.bin檔案裡面不會儲存它們,c語言中使用它們時,使用&a1取它們的值。

綜上所述,使用ld中的變數,就是借助symbol table儲存lds的變數,使用時加上&得到它們的值。

C語言重構 143 重排鍊錶

所有題目源 git位址 題目給定乙個單鏈表 l l0 l1 ln 1 ln 將其重新排列後變為 l0 ln l1 ln 1 l2 ln 2 你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。示例 1 給定鍊錶 1 2 3 4,重新排列為 1 4 2 3.示例 2 給定鍊錶 1 2 3 4...

小白C語言Leetcode 143 重排鍊錶

給定乙個單鏈表 l l0 l1 ln 1 ln 將其重新排列後變為 l0 ln l1 ln 1 l2 ln 2 你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。示例 1 給定鍊錶 1 2 3 4,重新排列為 1 4 2 3.示例 2 給定鍊錶 1 2 3 4 5,重新排列為 1 5 2...

力扣演算法題 143 重排鍊錶 C語言實現

給定乙個單鏈表 l l0 l1 ln 1 ln 將其重新排列後變為 l0 ln l1 ln 1 l2 ln 2 你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。示例 1 給定鍊錶 1 2 3 4,重新排列為 1 4 2 3.示例 2 給定鍊錶 1 2 3 4 5,重新排列為 1 5 2...