KEIL段重定位

2021-07-23 11:58:05 字數 2879 閱讀 4037

對於乙個大的檔案,為了便於管理,乙個好的辦法時把乙個大檔案分為若干個小檔案,每個小檔案包含一部分相關的功

能,這樣功能將顯得很整潔,而且移植到其它工程的時候也很方便,把檔案copy過去即可。

對於彙編,我們也許知道,可以使用org***x來指定函式的位址(org是乙個段內指定偏移的偽指令),但是當指定這個位址時,是否與其它函式衝突呢?有可能其它函式過長已經占用了這個位址。難道要數手指計算函式的長度嗎?另乙個問題是主函式怎樣呼叫被調函式呢?

在回答這些問題之前,先來看看使用的開發工具是怎 樣工作的。首先a51彙編器彙編檔案後會生成.obj檔案,這並不是最終需要的檔案。通常還要使用乙個叫鏈結器(如bl51)的工具,把多個obj檔案組合起 來,生成最終的二進位制**檔案(或其它格式的檔案)。雖然傳遞給鏈結器的引數是乙個或多個obj檔案,但是鏈結器在鏈結時卻是按段來計算的。每

個obj檔案裡包含的都是一些絕對位址段或/和可重定位段。鏈結器必須為可重定位段重新計算及分配位址。並計算絕對位址段是否重疊。

因 此:可得定位段可以保證多目標檔案鏈結時不發生目標位址重疊,故絕對位址段只適用用某些特殊場合,如固定i/o口或中斷向量的入口位址

絕對位址段就是這個段的位址在傳入鏈結器的時候已 經固定,鏈結器不能改變這個段的位址。

可重定位段就是這個段的位址需要鏈結器分配,如是 **段的段內的跳轉等指令的偏移也需要重新進算。

段的另一種分法可分為**段,資料段。資料段又分為以初始化資料段和未初始化資料段。這裡不細說。

通過上面可知,如果乙個函式是乙個段,而這個段是可重定位的,那麼就可以不用考慮**的位址問題了,把這個問題留給了鏈結器。

剩下來的問題就是怎樣把乙個函式變為乙個段的問題,(當然乙個段可包括很多函式,在彙編中,函式只是乙個說法而已)。大部分 的彙編器都會提供偽指令來定義絕對段及可重定位段(寫法上有可能有區別而已)。

在a51中,定義段的偽指令是

cseg -- 絕對**段

bseg -- 絕 對位段

dseg -- 絕對內部直接定址(data)資料段

iseg -- 絕 對內部間接定址(idata)資料段

xseg -- 絕對外部(xdata)資料段

segment -- 定義乙個可重定位段

rseg -- 選擇乙個可重定位段

使用說明:

name 模組名   //用來指明當前程式模組

重定位段名 segment 段型別 [重定位型別]     //[重定位型別為可選,段型別為可用的段型別有code,data,         xdata,idata ,bit    重定位型別為page,inpage,inblock,bitaddressable,unit,overlayable    段名等價於段符號,在表示式中用段名表示復合段中的基位址。

每個函式都包含在乙個段內。org 0 改為了 cseg at 0, org 50h則被刪除,這樣鏈結程式會自動的為每個重定位段分配位址,也就相當於為函式分配的位址這 樣函式與函式之間就沒有了gas(^_^,這是keil的術語,也就相當於空隙),當有gas時,程式是沒有使用的,白白浪費了。對於51這樣的系統可重定位段的另乙個好處就是空間覆蓋處 理,這將在下一節細說。

也許讀者會有這樣的疑問,之前的示例並沒有定義任 何的段,它們工作得也很好啊,那彙編器及鏈結器是怎麼工作的呢?鏈 接器的工作仍然是不變的,只是彙編器在掃瞄檔案時 發現檔案沒有定義段,會為每個空間分配乙個絕對段,位址從0開始。以code空間為例,如果沒有定義段,則預設段從0開始,這時檔案中的第一條指令的位址就是0開始,而org偽指令是指定段內偏移的,這裡的org 0 有沒有也就無所謂了。不信讀者可以把這條語句去掉再

彙編一次。

而當工程裡有多個檔案的時候,每乙個都不定義段,那麼每個檔案的預設段位址都從位址0開始,這時鏈結 器就會提示位址空間重疊。 因此可重定位段的用處就在 於此:它不會造成位址空間重疊。

下面將介紹的幾個偽指令對於多文件工作就特別的有 用了。

extrn  -- 指 示符號是外部的,並告訴模組是什麼型別

extern -- 跟extrn差不多,相當於extrn的一種特例

public -- 指示符號可在其它模組使用

使用方法如下:

extrn class (symbol [ , symbol ... ])

extrn class:type (symbol [ , symbol ... ])

extern class:type (symbol [ , symbol ... ])

public symbol [ , symbol ... ]

中括號內是可選部分。

c51編譯器採用了乙個擴充套件關鍵字 reentrant作為定義函式時的選項,需要將乙個函式定義為可重入函式時,只要在函式後面加上關鍵字reentrant即可。

與非可重入函式的引數傳遞和區域性變數的儲存分配方法不同,c51編譯器為可重入函式生成乙個模擬棧(相對於系統堆疊或是硬體堆疊來說),通過這個模擬棧來 完成引數傳遞和存放區域性變數。模擬棧以全域性變數?c_ibp、?c_pbp和?c_xbp作為棧指標(系統 堆疊棧頂指標為sp),這些變數定義在data位址空間,並且可在檔案startup.a51中進行初始化。根據編譯時採用的儲存器模式, 模擬棧區可位於內部(idata)或外部(pdata或xdata)儲存器中。如表1所示:

儲存模式

棧指標棧區域

small

?c_ibp(1  位元組)

間接訪問的內部資料儲存器(idata),棧區最大為256位元組

compact

?c_pbp(1位元組)

分頁定址的外部資料儲存器(pdata),棧區最大為256位元組

large

?c_xbp(2位元組)

外部資料儲存器(xdata),棧區最大為64k

表1注意:51系列微控制器的系統堆疊(也叫硬體堆疊或常規棧)總是位於內部資料儲存器中 (sp為 8位暫存器,只能指向內部),而且是「向上生長」型的(從低位址向高位址),而模 擬棧是「向下生長」型的

1 4 1 段的概念 重定位的引入

2440外接有sdram,nor flash,nand flash 通過nand flash控制,cpu可以直接控制sram,sdram,nor flash,但不能直接控制nand 同時內部還有4k的sram nor啟動時,起始位置為0x4000,0000 nand啟動時,起始位置為0 使用nand...

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

使用c語言清除bss段,我們肯定要獲取bss段的起始位址和結束位址,那麼,c語言要怎麼實現使用lds檔案中的變數abc?答 需要以下兩步,這兩步是重點。在函式中宣告該變數為extern型別 型別不重要,因為我們主要是取值,具體原因後面會說 使用時,要取址,比如,int p abc p的值即為lds中...

keil中函式變數定位方法

函式絕對定位方法 將鏈結方式從lx51改回bl51,然後再bl51 locate中的code框中寫入 pr?delay?delay 0x8000 其中,前面那個 delay是指函式名叫做delay,前面為什麼要加 還不清楚,而且原來無論是什麼這裡都是大寫 後面那個delay是指檔名叫做delay,也...