1、section的作用
section主要作用是將函數(shù)或者變量放在指定段中,這樣就可在指定的位置取出。
//section demo with gcc #include"stdio.h" int__attribute__((section("my_fun")))test1(inta,intb) { return(a+b); } inttest(intb) { return2*b; } int__attribute__((section("my_fun")))test0(inta,intb) { return(a*b); } int__attribute__((section("my_val")))chengi; int__attribute__((section("my_val")))chengj; intmain(void) { intsum,c,j; chengi=1,chengj=2; sum=test1(chengi,chengj); c=test(100); j=test0(chengi,chengj); printf("sum=%d,c=%d,j=%d ",sum,c,j); return0; }
編譯生成map文件:
gcc-o main.exe main.c-Wl,-Map,my_test.map
my_test.map 文件片段如下:
.text0x004014600xa0C:\Users\think\ccmGLaeH.o 0x00401460test 0x0040146amain .text0x004015000x0c:/mingw/bin/../libmingw32.a(CRTglob.o) ...... my_fun0x004040000x200 [!provide]PROVIDE(___start_my_fun,.) my_fun0x004040000x1cC:\Users\think\ccmGLaeH.o 0x00404000test1 0x0040400dtest0 [!provide]PROVIDE(___stop_my_fun,.) .data0x004050000x200 0x00405000\__data_start_\_=. ...... *(.data_cygwin_nocopy) my_val0x004060000x200 [!provide]PROVIDE(___start_my_val,.) my_val0x004060000x8C:\Users\think\ccdMcTrl.o 0x00406000chengi 0x00406004chengj [!provide]PROVIDE(___stop_my_val,.) .rdata0x004070000x400
分析可見,使用section修飾的函數(shù)和變量在自定義的片段,而且是連續(xù)存放在___start_xx到___stop_xx之間,這樣可根據(jù)變量的地址得出與其同段變量的地址,為后續(xù)自動初始化等功能提供了基礎(chǔ)。
2、 自動初始化
基于前面section的作用,可以將同類函數(shù)指針全部使用同一個段名修飾,然后開機(jī)后系統(tǒng)自動檢索段內(nèi)函數(shù)指針,逐個執(zhí)行,對上層應(yīng)用就是無需主動調(diào)用,系統(tǒng)自動初始化。
考慮到硬件初始化與應(yīng)用功能初始化的先后順序,可以對段名進(jìn)行分配,map文件按段名排序。自動初始化主體是OS_INIT_EXPORT宏。
范例代碼出自中國移動的oneos開源版本,使用gcc,方案和國產(chǎn)RT-Thread類似。
typedefos_err_t(*os_init_fn_t)(void); #defineOS_INIT_EXPORT(fn,level) const os_init_fn_t __os_call_##fn OS_SECTION(".init_call."level)=fn #defineOS_BOARD_INIT(fn)OS_INIT_EXPORT(fn,"1") #defineOS_PREV_INIT(fn)OS_INIT_EXPORT(fn,"2") #defineOS_DEVICE_INIT(fn)OS_INIT_EXPORT(fn,"3") #defineOS_CMPOENT_INIT(fn)OS_INIT_EXPORT(fn,"4") #defineOS_ENV_INIT(fn)OS_INIT_EXPORT(fn,"5") #defineOS_APP_INIT(fn)OS_INIT_EXPORT(fn,"6")
例如shell初始化函數(shù),定義如下:
OS_APP_INIT(sh_system_init);
將宏定義展開:
/*含義是函數(shù)指針__os_call_sh_system_init *其指向sh_system_init函數(shù),且該指針編譯后放在".init_call.6"段 */ constos_init_fn_t__os_call_sh_system_init __attribute__((section((".init_call.6"))))=sh_system_init
系統(tǒng)自身也有自定義函數(shù),用來標(biāo)記起止點(diǎn)函數(shù)。
OS_INIT_EXPORT(os_init_start,"0");//段起點(diǎn)__start OS_INIT_EXPORT(os_board_init_start,"0.end"); OS_INIT_EXPORT(os_board_init_end,"1.end"); OS_INIT_EXPORT(os_init_end,"6.end");//段終點(diǎn)__stop
最終生成的map文件,如下圖所示:
//系統(tǒng)底層在合適的時機(jī)調(diào)用如下兩函數(shù),將指定段區(qū)間內(nèi)的所有函數(shù)自動執(zhí)行 voidos_board_auto_init(void) { constos_init_fn_t*fn_ptr_board_init_start; constos_init_fn_t*fn_ptr_board_init_end; constos_init_fn_t*fn_ptr; fn_ptr_board_init_start=&__os_call_os_board_init_start+1; fn_ptr_board_init_end=&__os_call_os_board_init_end-1; //將段首尾區(qū)間內(nèi)的函數(shù)全部遍歷執(zhí)行 for(fn_ptr=fn_ptr_board_init_start;fn_ptr<=?fn_ptr_board_init_end;?fn_ptr++) ????{ ????????(void)(*fn_ptr)(); ????} ????return; } static?void?os_other_auto_init(void) { ????const?os_init_fn_t?*fn_ptr_other_init_start; ????const?os_init_fn_t?*fn_ptr_other_init_end; ????const?os_init_fn_t?*fn_ptr; ????fn_ptr_other_init_start?=?&__os_call_os_board_init_end?+?1; ????fn_ptr_other_init_end???=?&__os_call_os_init_end?-?1; ????for?(fn_ptr?=?fn_ptr_other_init_start;?fn_ptr?<=?fn_ptr_other_init_end;?fn_ptr++) ????{ ????????(void)(*fn_ptr)(); ????} ????return; }
系統(tǒng)執(zhí)行os_other_auto_init時實(shí)現(xiàn)了sh_system_init的自動執(zhí)行,即使應(yīng)用層沒有顯示的去調(diào)用它。使用符號段的方式實(shí)現(xiàn)初始化函數(shù)自動執(zhí)行,應(yīng)用層修改軟件,增加功能啟動或者裁剪,對底層代碼無需任何改動。
注意:段中函數(shù)類型都是一樣的,范例是同一類函數(shù)指針,也可以是結(jié)構(gòu)體,需要確保每個成員占用空間大小相同,這樣才能逐個遍歷。
3、總結(jié)
不同編譯器對section屬性的定義略有差異,但效果相同。
/*Compiler Related Definitions*/ #ifdefined(__CC_ARM)||defined(__CLANG_ARM) /*ARM Compiler*/ #defineSECTION(x)__attribute__((section(x))) #elifdefined(__IAR_SYSTEMS_ICC__)/*for IAR Compiler*/ #defineSECTION(x)@x #elifdefined(__GNUC__)/*GNU GCC Compiler*/ #defineSECTION(x)__attribute__((section(x))) #elifdefined(__ADSPBLACKFIN__)/*for VisualDSP++Compiler*/ #defineSECTION(x)__attribute__((section(x))) #elifdefined(_MSC_VER) #defineSECTION(x) #elifdefined(__TI_COMPILER_VERSION__) /* *The way that TI compiler set section is different from other(at least *GCC and MDK)compilers.See ARM Optimizing C/C++Compiler 5.9.3 for more *details. */ #defineSECTION(x) #else #errornot supported tool chain #endif
上面的#error也是個應(yīng)用技巧,配搭#if / #else / #endif在編譯階段即可發(fā)現(xiàn)代碼問題,一般用于判斷宏定義的配置是否在預(yù)期之外,編譯報錯必須修改。
配合C關(guān)鍵字,對代碼的安全校驗(yàn)、擴(kuò)展移植都會有很好的效果。對小型項(xiàng)目、個人獨(dú)立開發(fā)看不出效果,但對復(fù)雜的多人合作的項(xiàng)目,合適的關(guān)鍵字對代碼的穩(wěn)定性和架構(gòu)是錦上添花。
審核編輯:劉清
-
C語言
+關(guān)注
關(guān)注
180文章
7604瀏覽量
136694 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1285瀏覽量
40088 -
gcc編譯器
+關(guān)注
關(guān)注
0文章
78瀏覽量
3380
原文標(biāo)題:C語言中section關(guān)鍵字的實(shí)際作用
文章出處:【微信號:玩點(diǎn)嵌入式,微信公眾號:玩點(diǎn)嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論