stm32函數(shù)放入段section中
對于這樣一個需求,不管你寫多少個硬件底層初始化函數(shù),我都能通過固定的循環(huán)進行執(zhí)行,是不動的一個狀態(tài),這種實現(xiàn)方式,可以通過以下介紹的方式操作。
本文引用地址:http://m.butianyuan.cn/article/201612/325186.htm思路,有兩種辦法,一種是指定一個段,這個段需要固定,然后,在這個段之間的區(qū)域?qū)⒑瘮?shù)寫入進去。一種是直接將函數(shù)一直寫入,編譯器知道寫的函數(shù)有多少個,調(diào)用編譯器得到的函數(shù)個數(shù)來操作,對于寫的函數(shù)個數(shù)同樣靈活。
第一種辦法:
指定段的辦法。
操作示例:
先定義一個函數(shù)類型。
typedef int (*MyFun)(void);
#define INIT_FUN(fn,level)
const MyFun __myFun_##fn __attribute__((section(".myFun."level))) = fn
讓其在初始化動作的時候,寫入一個段中,在程序上看起來是一個text文本段了。
這里有一個知識點,如果這樣寫的話,后期程序遍歷的時候,發(fā)現(xiàn)在程序上無法執(zhí)行初始化的操作,根源是在map文件中:
Section Cross References
startup_stm32f10x_hd.o(RESET) refers to startup_stm32f10x_hd.o(STACK) for __initial_sp
startup_stm32f10x_hd.o(RESET) refers to startup_stm32f10x_hd.o(.text) for Reset_Handler
startup_stm32f10x_hd.o(RESET) refers to stm32f10x_it.o(.text) for NMI_Handler
startup_stm32f10x_hd.o(.text) refers to system_stm32f10x.o(.text) for SystemInit
startup_stm32f10x_hd.o(.text) refers to entry.o(.ARM.Collect$$$$00000000) for __main
main.o(.text) refers to printf1.o(i.__0printf$1) for __2printf
main.o(.text) refers to usart1.o(.text) for USART1_Config
main.o(.text) refers to main.o(.myFun.0) for __myFun_init_begin
main.o(.text) refers to main.o(.myFun.7) for __myFun_init_end
main.o(.myFun.0) refers to main.o(.text) for init_begin
main.o(.myFun.0s) refers to main.o(.text) for init_fun1
main.o(.myFun.2) refers to main.o(.text) for init_fun2
main.o(.myFun.7) refers to main.o(.text) for init_end
Removing Unused input sections from the image.
Removing startup_stm32f10x_hd.o(HEAP), (512 bytes).
Removing main.o(.myFun.0s), (4 bytes).
Removing main.o(.myFun.2), (4 bytes).
Removing core_cm3.o(.emb_text), (32 bytes).
Removing dadd.o(.text), (330 bytes).
Removing dmul.o(.text), (226 bytes).
Removing ddiv.o(.text), (222 bytes).
Removing dfixul.o(.text), (48 bytes).
Removing cdrcmple.o(.text), (40 bytes).
Removing depilogue.o(.text), (194 bytes).
10 unused section(s) (total 1612 bytes) removed from the image.
剛開始建立了,但是在程序上沒有使用,就給刪除了段。
那么這個緣由肯定是由于編譯器動了手腳,因此,查看Arm Development Tool可以查到,在RealView Linker User Guide這個欄目下的Section elimination下的unused section elimination中有相關(guān)的敘述:
Unused section elimination
| ||
Home > Using the Basic Linker Functionality > Section elimination > Unused section elimination |
Unused section elimination removes unreachable co
Unused section elimination is suppressed in those cases that might result in the removal of all sections.
An input section is retained in the final image under the following conditions:
- if it contains an entry point
- if it is referred to, directly or indirectly, by a non-weak reference from an input section containing an entry point
- if it is specified as the first or last input section by the--firstor--lastoption (or a scatter-loading equivalent)
- if it is marked as unremovable by the--keepoption.
Note
Compilers will normally collect functions and da
里面談到了map文件最后移除了未用到的段。但是可以通過加—keep字段進行保留,讓其最后不再刪除。
對于本例程的用法是:
--keep=__myFun*
當(dāng)然了,按照map文件的提示,是將used文件變?yōu)閡nused,進而刪除了,那么可以做一個操作:
#define INIT_FUN(fn,level)
const MyFun __myFun_##fn __attribute__((section(".myFun."level))) __attribute__((used)) = fn
就是加: __attribute__((used))變?yōu)轱@示的使用了這個段,那它就不會被刪除了吧,測試可行??!其實這個在linux上可以找到相關(guān)的參考。
內(nèi)核版本linux3.0.1.。
在main.c(init)這個文件中,
有:
extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
static void __init do_initcalls(void)
{
initcall_t *fn;
for (fn = __early_initcall_end; fn < __initcall_end; fn++)
do_on
}
在init.h中有:
typedef int (*initcall_t)(void);
在vmlinux.lds.h中有:
#define INIT_CALLS
VMLINUX_SYMBOL(__initcall_start) = .;
INITCALLS
VMLINUX_SYMBOL(__initcall_end) = .;
#define INITCALLS
*(.initcallearly.init)
VMLINUX_SYMBOL(__early_initcall_end) = .;
*(.initcall0.init)
*(.initcall0s.init)
*(.initcall1.init)
*(.initcall1s.init)
*(.initcall2.init)
*(.initcall2s.init)
*(.initcall3.init)
*(.initcall3s.init)
*(.initcall4.init)
*(.initcall4s.init)
*(.initcall5.init)
*(.initcall5s.init)
*(.initcallrootfs.init)
*(.initcall6.init)
*(.initcall6s.init)
*(.initcall7.init)
*(.initcall7s.init)
很簡單,寫的函數(shù)在段.initcall0.init-----initcall7s.init中,那么遍歷的時候,框頭框尾,中間函數(shù)明顯就能調(diào)用到。
然后在init.h中有
#define __init __section(.init.text)
#define __initdata __section(.init.da
#define __exitdata __section(.exit.da
#define __exit_call __used __section(.exitcall.exit)
同樣在段上加了一個__used修飾。猜測來的,所以加上了__attribute__((used))
上代碼:
static int init_begin(void)
{
printf("----fun init start---rn");
return 0;
}
INIT_FUN(init_begin,"0");
static int init_fun1(void)
{
printf("----fun init fun1---rn");
return 0;
}
INIT_FUN(init_fun1,"0s");
static int init_fun2(void)
{
printf("----fun init fun2---rn");
return 0;
}
INIT_FUN(init_fun2,"2");
static int init_end(void)
{
printf("----fun init end---rn");
return 0;
}
INIT_FUN(init_end,"7");
上面一系列函數(shù)中:
init_begin函數(shù)和init_end屬于框頭框尾,遍歷時候,就作為邊界即可
于是,就形成:
const MyFun *vMyFun;
for( vMyFun = &__myFun_init_begin; vMyFun <= &__myFun_init_end; vMyFun ++)
{
(*vMyFun)();
}
從而達到效果。
第二種辦法:
只有段的概念,不用計算多少個函數(shù),由編譯器來動作即可。
typedef int (*FunInit)(void);
#define INIT_FUNCTION(func)
FunInit __Fun_##func __attribute__((section("mySection"))) = func
void InitFun1(void)
{
printf("InitFun1 initrn");
}
INIT_FUNCTION(InitFun1);
void InitFun2(void)
{
printf("InitFun2 init rn");
}
INIT_FUNCTION(InitFun2);
extern int mySection$$Base;
extern int mySection$$Length;
FunInit *initFunc = (FunInit *)&mySection$$Base;
int count = (int)(&mySection$$Length)/sizeof(FunInit);
while(count--) {
(*initFunc)();
initFunc++;
}
就這樣,可以遍歷整個段中定義好的函數(shù)了。
代碼下載:
http://download.csdn.net/detail/wit_yuan/9010727中關(guān)于section的部分。
評論