傳統嵌入式開發需將應用與核心靜態連結成單一映像檔,修改需重新編譯燒錄,週期長。動態模組載入技術讓系統運行時載入/更新模組,提升彈性與開發效率。
| 類型 | 時機 | 優點 | 缺點 |
|---|---|---|---|
| 靜態連結 | 建構期 | 獨立執行、速度快 | 映像檔大、無法更新 |
| 載入時連結 | 載入期 | 程式碼較小 | 記憶體佔用不減、載入器複雜 |
| 動態連結 | 執行期 | 按需載入、節省空間、支援熱更新 | 執行期開銷、實作複雜 |
# module.decl
name=NetworkStack
version=1.2
exports=net_init, net_send, net_recv, net_close
建構腳本依宣告產生:調用庫(給呼叫端)與附加庫(連結進模組,含介面表與註冊函數)。
// 模組內部附加庫程式碼
void module_init() {
register_module("NetworkStack", &interface_table); // 向載入器註冊
}
// 呼叫端連結的調用庫 (NetworkStack_stub.c)
static void* module_base = NULL; // 二級重定位表基址
void lib_init() {
module_base = sys_get_module_table("NetworkStack"); // 系統呼叫取得基址
}
void net_send(void* buf, int len) {
typedef void(*func_t)(void*, int);
((func_t)(module_base + 1*4))(buf, len); // 索引 1 對應 net_send
}
地址計算公式:函數實際地址 = 模組重定位表基址 + 函數索引 × 4(32位元系統)。
模組名 → 二級表基址 映射,動態可變。// 一級表結構
struct Level1Entry { char* name; void* level2_base; };
Level1Entry level1_table[MAX_MODULES];
// 二級表結構 (模組內)
void* level2_table[] = {
net_init_addr, // index 0
net_send_addr, // index 1
net_recv_addr, // index 2
net_close_addr // index 3
};
lib_init()。lib_init() 透過系統呼叫請求載入器載入模組(若未載入)。module_init() 註冊二級表。module_base,後續呼叫直接透過索引計算跳轉。| 優點 | 缺點/限制 |
|---|---|
| 開發期熱更新、無需重燒核心 | 函數呼叫多一次間接跳轉(微小開銷) |
| 核心與應用解耦、獨立編譯測試 | 需嚴格管理介面版本相容性 |
| 記憶體按需載入、支援模組化架構 | 無 MMU 系統實作複雜度高 |
| 支援高可靠領域熱備援更新 | 除錯需支援動態載入符號解析 |