鏈結指令碼之軟體初始化解耦

2021-09-26 13:21:21 字數 2973 閱讀 9067

看過linux核心原始碼的人都知道核心中到處充斥著類似: arch_initcall(),fs_initcall(), module_init()等等, 也都知道它們的作用主要

是將各個不同模組的初始化函式的位址放到指定的段,然後方便核心在同乙個地方集中初始化,同時解決了呼叫者和被調函式

__***_section_start = .; // 表示段的起始位址

*(.***)

__***_section_end = .; // 表示段的結束位址

#define __ro_section_declare(name, order, index_1, index_2, sym) \

__section(".rodata1.symbol." #name "." #order "." #index_1 "." #index_2 "." #sym) \

__used __aligned(4)

struct sysinit_item

#define _sysinit_index_item(sname, handler, nsec, index_1, index_2) \

__ro_section_declare(sname, nsec, index_1, index_2, handler) \

static const struct sysinit_item __##sname##_item_##nsec =

#define sys_init(handler, module, order) \

enum ; \

_sysinit_index_item(sysinit, handler, 1, module, order)

#define sysinit_boundary(_name) \

_sysinit_index_item(_name, null, 0, 0, 0); \

_sysinit_index_item(_name, null, 2, 0, 0)

#define foreach_item(_var, _name) \

for (_var = &__##_name##_item_##0, ++_var; \

_var < &__##_name##_item_##2; \

_var++)

呼叫指定段的所有函式:

sysinit_boundary(sysinit);

void sys_init(void)

使用例程:

#define sysinit_device 0x10

#define device_order 0x03

static void ***_device_setup(void)

sys_init(***_device_setup, sysinit_device, device_order);

上面的實現**中有兩個關鍵巨集:

#define sys_init(handler, module, order) \

enum ; \

_sysinit_index_item(sysinit, handler, 1, module, order)

這裡的列舉型別 enum ; 的主要作用並不是定義乙個型別,而是為了強制觸發編譯器的預處理程式的替換操

作,即:如果module和order是巨集則將他們替換成數字。

#define sysinit_boundary(_name) \

_sysinit_index_item(_name, null, 0, 0, 0); \

_sysinit_index_item(_name, null, 2, 0, 0)

__section(".rodata1.symbol." sysinit "."0 "." 0 "." 0 "." "null") __used __aligned(4)\

static const struct sysinit_item __sysinit_item_0 = ; \

__section(".rodata1.symbol." #name "."2 "." 0 "." 0 "." "null") __used __aligned(4) \

static const struct sysinit_item __sysinit_item_2 =

那這又代表什麼意思呢? 聰明的你們可能早已看破了一切, 但我還是囉嗦一遍,sysinit_boundary(sysinit)的含義如下:

定義並將變數__sysinit_item_0(初始值為null)放在段 .rodata1.symbol.sysinit .0 .0 .0 .null

定義並將變數__sysinit_item_2(初始值為null) 放在段 .rodata1.symbol.sysinit .2 .0 .0 .null

同理: sys_init(***_device_setup, sysinit_device, device_order);表示:

定義並將變數__sysinit_item_1(初始值為***_device_setup)放在段 .rodata1.symbol.sysinit .1 .0x10 .0x03.***_device_setup

0******x0: .rodata1.symbol.sysinit .0 .0 .0 .null

0******x4: .rodata1.symbol.sysinit .1 .0x10 .0x03.***_device_setup

0******x8: .rodata1.symbol.sysinit .2 .0 .0 .null

再看sys_init()的實現, 主要就是遍歷段(&__sysinit_item_0, &__sysinit_item_2), 不包含__sysinit_item_0和__sysinit_item_2,因為這兩個變數為

空且主要作用是標識段的邊界。 另外之所以選擇選擇段.rodata1*主要是為了利用c/c++的基本段.rodata*, 如果鏈結器預設對段rodata進行排序,

則我們完全不用更改鏈結指令碼,反之則需要在指令碼中加入排序指令。

指標的定義 初始化 解引用

1.指標的定義和初始化 1 a 取位址符 單目運算子 a b 按位與 雙目運算子 的三種用法 1 乘法 3 4 12 2 int p a 定義指標變數 3 p 100 解引用 2 int p a 定義整型指標變數 p 儲存整型位址值 p 100 間接訪問符 解引用 通過p間接訪問變數a的值並把a的值...

c 的成員列表初始化解析

首先來看一段 這是某個類的定義 簡單定義 class queue 接著初始化類建構函式 queue queue int qs 上述 無法正常執行,原因在於qszie這一點,他是常量,只能初始化而不能賦值,原因如下 正常的呼叫建構函式的內部順序是 呼叫建構函式 建立物件 首先給類的成員變數分配記憶體,...

初始化 MyBatis初始化之載入初始化

在mybatis初始化過程中,大致會有以下幾個步驟 1.建立configuration全域性配置物件,會往typealiasregistry別名註冊中心新增mybatis需要用到的相關類,並設定預設的語言驅動類為xmllanguagedriver 3.構建defaultsqlsessionfacto...