使用動態加載目標模塊很多好處,比如可以在不破壞原來的環境下增加除錯定位功能,
相當于給系統打“補丁”;不需要編譯原來的代碼(甚至不用原來的代碼)而只需要關注正在
除錯的代碼,這樣能減少編譯時間和減少映象的加載量。
實作目標模塊的動態加載有很多中方法,如在主機環境的界面上通過在目標模塊上單擊
滑鼠右鍵,選擇“Download 檔案名”;也可以通過 wShell 和 GDB 命令列視窗實作。本文通
過 tshell 下使用 ld( )、 loadModule( )、loadModuleAt( )中一個函式來實作,當然在代碼中也可
以自如的呼叫它們。
ld 命令是由用戶介面子程式庫 usrLib 提供的一個加載命令。使用 ld 的前提是在 config.h
中定義 INCLUDE_LOADER。這樣,在 usrRoot()函式中就會自動呼叫加載模塊初始化函式
moduleLibInit ( );同時,根據 CPU 型別,自動決定目標模塊的格式。如果 CPU 是 MIPS,
PPC,ARM,I80X86,COLDFIRE,SIMSPARCSOLARIS,SH 等,加載的目標模塊格式是 elf
型別,就會呼叫 loadElfInit ( );如果 CPU 是 I960,AM29XXX 等,加載的目標模塊的格式則是
coff 型別,就會呼叫 loadCoffInit t ( )函式。
在 ARM 和 PPC 下,Tornado 編譯器生成的.o 或.out 都是 ELF 型別,打開目標檔案都會
看到檔案頭有 ELF(45,4C,46)標記。這時可以通過 ftp 工具把它加載到檔案系統(如使用 copy
命令加載到 RAM 盤)中,再呼叫 ld( )或 loadModule( )函式加載到記憶體中運行。
ld 的函式原型:MOUDLE_ID ld ( int syms,BOOL noAbort, char *name);引數 syms 決定目
標檔案的符號怎么處理,0:添加全域符號到系統符號表中;1:添加全域和區域符號到系統
符號表中;-1:符號不添加到系統符號表中。一般選 1,便于 shell 下使用其中的符號。引數
noAbort 表明是否可以忽略加載期間出現的錯誤,為 TRUE 則忽略。Name 則為加載的檔案名。
含檔案路徑。
loadModule 的函式原型是 MODULE_ID loadModule ( int fd, int symFlag );fd 為檔案描述
符號,需要先打開檔案獲取 fd;引數 symFlag 含義有 LOAD_NO_SYMBOLS(2);
LOAD_LOCAL_SYMBOLS(4);LOAD_GLOBAL_SYMBOLS(8);LOAD_ALL_SYMBOLS
(0xC)。
假如已經將需要加載的檔案 demo.o 放到 RAM 盤中,則加載到記憶體中的方式有以下幾種:
(1)-> ld 1,0,”RamDisk:demo.o”
(2)-> ld (1) <RamDisk:demo.o
(3)->fdT = open (”RamDisk:demo.o”, O_RDONLY);
->loadModule (fdT, 0xC);
->close (fdT);
加載函式回傳的是 MODULE_ID,這是該加載模塊的標記。使用卸載 unldByModuledId 時
可以使用模塊 ID。查看加載模塊的具體資訊的函式是 moduleShow()。
-> moduleShow
MODULE NAME MODULE ID GROUP # TEXT START DATA START BSS START
--------------- ---------- ---------- ---------- ---------- ----------
RamDisk:demo.o 0x3fff9e8 1 0x3fff3e8 0x3fff4e4 0x3fff4e4
對于某些應用,使用 ld 或 loadModule 會出現如下錯誤:
Relocation value does not fit in 24 bits.
ld error: error loading file (errno = 0x3d0001).
這是因為函式在記憶體中的位置超出了跳轉的最大距離(一般跳轉指令是 24bit 地址,32M)。
為了規避這個問題,可以使用長跳轉來完成函式的呼叫。這就要求編譯目標檔案時在編譯選
項中使用“長呼叫”的選項。如 ARM 加 –mlong-calls;PPC 處理器加-mlongcall。
當然也可以使用 loadModuleAt ()解決這個問題,將目標模塊加載到指定地址,使所需
要的函式在跳轉地址以內。其原型是:
MODULE_ID loadModuleAt ( int fd, int symFlag,
char **ppText, char **ppData, char **ppBss);
ppText,ppData,ppBss 是分別是加載后 text 段,data 段,bss 段指向的地址。假如加
載 demo.o 到 1M 空間處(保證這個空間沒有被用):fdT = open (”RamDisk:demo.o”,
O_RDONLY); pText = 0x100000; pData = pBss = 0xffffffff; /* (LD_NO_ADDRESS) */
loadModuleAt(fdT, 8 ,& pText, & pData, & pBss); close (fdT);
加載完成后,在 shell 下就可以執行最新的目標檔案中的函式了。如果函式以前有的,按
最后加載的函式為準。可見,加載的目標模塊都經過重定位,符號決議和添加的程序。
如果目標模塊中使用的全域變數或函式在本模塊和以前的程式中都沒有定義,則加載時會
出現類似 Undefined symbol 的錯誤。
有時候從主機上下載的目標模塊中的函式符號不會出現在目標機 shell 中,反過來也一樣,
目標機 shell 生成的符號對主機 wShell 也不可見。出現這種情況的主要原因是目標機和主機
的符號沒有同步化,需要在編譯映象時定義 INCLUDE_SYM_TBL_SYNC。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/18903.html
標籤:VxWorks開發
上一篇:計算機原理與結構課程的一項作業
