对于这样一个需求,不管你写多少个硬件底层初始化函数,我都能通过固定的循环进行执行,是不动的一个状态,这种实现方式,可以通过以下介绍的方式操作。
思路,有两种办法,一种是指定一个段,这个段需要固定,然后,在这个段之间的区域将函数写入进去。一种是直接将函数一直写入,编译器知道写的函数有多少个,调用编译器得到的函数个数来操作,对于写的函数个数同样灵活。
第一种办法:
指定段的办法。
操作示例:
先定义一个函数类型。
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 --first or --last option (or a scatter-loading equivalent)
- if it is marked as unremovable by the --keep option.
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的部分。
上一篇:stm32的DMA空闲中断数据配置
下一篇:stm32接收中文字符,解析中文字符的方法与调试
推荐阅读最新更新时间:2024-03-16 15:13