新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > stm32函數(shù)放入段section中

stm32函數(shù)放入段section中

作者: 時(shí)間:2016-12-03 來(lái)源:網(wǎng)絡(luò) 收藏
關(guān)鍵字,__attribute__((section)).

對(duì)于這樣一個(gè)需求,不管你寫(xiě)多少個(gè)硬件底層初始化函數(shù),我都能通過(guò)固定的循環(huán)進(jìn)行執(zhí)行,是不動(dòng)的一個(gè)狀態(tài),這種實(shí)現(xiàn)方式,可以通過(guò)以下介紹的方式操作。

本文引用地址:http://butianyuan.cn/article/201612/325186.htm

思路,有兩種辦法,一種是指定一個(gè)段,這個(gè)段需要固定,然后,在這個(gè)段之間的區(qū)域?qū)⒑瘮?shù)寫(xiě)入進(jìn)去。一種是直接將函數(shù)一直寫(xiě)入,編譯器知道寫(xiě)的函數(shù)有多少個(gè),調(diào)用編譯器得到的函數(shù)個(gè)數(shù)來(lái)操作,對(duì)于寫(xiě)的函數(shù)個(gè)數(shù)同樣靈活。

第一種辦法:

指定段的辦法。

操作示例:

先定義一個(gè)函數(shù)類(lèi)型。

typedef int (*MyFun)(void);

#define INIT_FUN(fn,level)

const MyFun __myFun_##fn __attribute__((section(".myFun."level))) = fn

讓其在初始化動(dòng)作的時(shí)候,寫(xiě)入一個(gè)段中,在程序上看起來(lái)是一個(gè)text文本段了。

這里有一個(gè)知識(shí)點(diǎn),如果這樣寫(xiě)的話(huà),后期程序遍歷的時(shí)候,發(fā)現(xiàn)在程序上無(wú)法執(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.

剛開(kāi)始建立了,但是在程序上沒(méi)有使用,就給刪除了段。

那么這個(gè)緣由肯定是由于編譯器動(dòng)了手腳,因此,查看Arm Development Tool可以查到,在RealView Linker User Guide這個(gè)欄目下的Section elimination下的unused section elimination中有相關(guān)的敘述:

Unused section elimination

RealView Compilation Tools for ?Vision Linker User Guide

Version 4.0

Home > Using the Basic Linker Functionality > Section elimination > Unused section elimination

Unused section elimination removes unreachable code and data from the final image. This optimization can be controlled by the--remove,--no_remove,--first,--last, and--keeplinker options and, indirectly, with--entry. Use the--info unusedlinker option to instruct the linker to generate a list of the unused sections that have been eliminated.

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 data together and emit one section for each category. The linker can only eliminate a section if it is entirely unused.

里面談到了map文件最后移除了未用到的段。但是可以通過(guò)加—keep字段進(jìn)行保留,讓其最后不再刪除。

對(duì)于本例程的用法是:

--keep=__myFun*

當(dāng)然了,按照map文件的提示,是將used文件變?yōu)閡nused,進(jìn)而刪除了,那么可以做一個(gè)操作:

#define INIT_FUN(fn,level)

const MyFun __myFun_##fn __attribute__((section(".myFun."level))) __attribute__((used)) = fn

就是加: __attribute__((used))變?yōu)轱@示的使用了這個(gè)段,那它就不會(huì)被刪除了吧,測(cè)試可行??!其實(shí)這個(gè)在linux上可以找到相關(guān)的參考。

內(nèi)核版本linux3.0.1.。

在main.c(init)這個(gè)文件中,

有:

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_one_initcall(*fn);

}

在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)

很簡(jiǎn)單,寫(xiě)的函數(shù)在段.initcall0.init-----initcall7s.init中,那么遍歷的時(shí)候,框頭框尾,中間函數(shù)明顯就能調(diào)用到。

然后在init.h中有

#define __init __section(.init.text)

#define __initdata __section(.init.data)

#define __exitdata __section(.exit.data)

#define __exit_call __used __section(.exitcall.exit)

同樣在段上加了一個(gè)__used修飾。猜測(cè)來(lái)的,所以加上了__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屬于框頭框尾,遍歷時(shí)候,就作為邊界即可

于是,就形成:

const MyFun *vMyFun;

for( vMyFun = &__myFun_init_begin; vMyFun <= &__myFun_init_end; vMyFun ++)

{

(*vMyFun)();

}

從而達(dá)到效果。

第二種辦法:

只有段的概念,不用計(jì)算多少個(gè)函數(shù),由編譯器來(lái)動(dòng)作即可。

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++;

}

就這樣,可以遍歷整個(gè)段中定義好的函數(shù)了。

代碼下載:

http://download.csdn.net/detail/wit_yuan/9010727中關(guān)于section的部分。



關(guān)鍵詞: stm32函數(shù)段sectio

評(píng)論


技術(shù)專(zhuān)區(qū)

關(guān)閉