关键字,__attribute__((section)).
关于这样一个需求,不论你写多少个硬件底层初始化函数,我都能经过固定的循环进行履行,是不动的一个状况,这种完成方法,能够经过以下介绍的方法操作。
思路,有两种方法,一种是指定一个段,这个段需求固定,然后,在这个段之间的区域将函数写入进去。一种是直接将函数一向写入,编译器知道写的函数有多少个,调用编译器得到的函数个数来操作,关于写的函数个数相同灵敏。
第一种方法:
指定段的方法。
操作示例:
先界说一个函数类型。
typedef int (*MyFun)(void);
#define INIT_FUN(fn,level) \
const MyFun __myFun_##fn __attribute__((section(“.myFun.”level))) = fn
让其在初始化动作的时分,写入一个段中,在程序上看起来是一个text文本段了。
这里有一个知识点,假如这样写的话,后期程序遍历的时分,发现在程序上无法履行初始化的操作,本源是在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中有相关的叙说:
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*
当然了,依照map文件的提示,是将used文件变为unused,然后删去了,那么能够做一个操作:
#define INIT_FUN(fn,level) \
const MyFun __myFun_##fn __attribute__((section(“.myFun.”level))) __attribute__((used)) = fn
便是加: __attribute__((used))变为显现的运用了这个段,那它就不会被删去了吧,测验可行!!其实这个在linux上能够找到相关的参阅。
内核版别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)
很简单,写的函数在段.initcall0.init—–initcall7s.init中,那么遍历的时分,框头框尾,中心函数显着就能调用到。
然后在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—\r\n”);
return 0;
}
INIT_FUN(init_begin,”0″);
static int init_fun1(void)
{
printf(“—-fun init fun1—\r\n”);
return 0;
}
INIT_FUN(init_fun1,”0s”);
static int init_fun2(void)
{
printf(“—-fun init fun2—\r\n”);
return 0;
}
INIT_FUN(init_fun2,”2″);
static int init_end(void)
{
printf(“—-fun init end—\r\n”);
return 0;
}
INIT_FUN(init_end,”7″);
上面一系列函数中:
init_begin函数和init_end归于框头框尾,遍历时分,就作为鸿沟即可
所以,就构成:
const MyFun *vMyFun;
for( vMyFun = &__myFun_init_begin; vMyFun <= &__myFun_init_end; vMyFun ++)
{
(*vMyFun)();
}
然后到达作用。
第二种方法:
只要段的概念,不必核算多少个函数,由编译器来动作即可。
typedef int (*FunInit)(void);
#define INIT_FUNCTION(func) \
FunInit __Fun_##func __attribute__((section(“mySection”))) = func
void InitFun1(void)
{
printf(“InitFun1 init\r\n”);
}
INIT_FUNCTION(InitFun1);
void InitFun2(void)
{
printf(“InitFun2 init \r\n”);
}
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++;
}
就这样,能够遍历整个段中界说好的函数了。
代码下载:
http://download.csdn.net/detail/wit_yuan/9010727中关于section的部分。