新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > stm32函數放入段section中

        stm32函數放入段section中

        作者: 時間:2016-12-03 來源:網絡 收藏
        關鍵字,__attribute__((section)).

        對于這樣一個需求,不管你寫多少個硬件底層初始化函數,我都能通過固定的循環進行執行,是不動的一個狀態,這種實現方式,可以通過以下介紹的方式操作。

        本文引用地址:http://www.104case.com/article/201612/325186.htm

        思路,有兩種辦法,一種是指定一個段,這個段需要固定,然后,在這個段之間的區域將函數寫入進去。一種是直接將函數一直寫入,編譯器知道寫的函數有多少個,調用編譯器得到的函數個數來操作,對于寫的函數個數同樣靈活。

        第一種辦法:

        指定段的辦法。

        操作示例:

        先定義一個函數類型。

        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

        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文件最后移除了未用到的段。但是可以通過加—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_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)

        很簡單,寫的函數在段.initcall0.init-----initcall7s.init中,那么遍歷的時候,框頭框尾,中間函數明顯就能調用到。

        然后在init.h中有

        #define __init __section(.init.text)

        #define __initdata __section(.init.data)

        #define __exitdata __section(.exit.data)

        #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");

        上面一系列函數中:

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

        }

        就這樣,可以遍歷整個段中定義好的函數了。

        代碼下載:

        http://download.csdn.net/detail/wit_yuan/9010727中關于section的部分。



        關鍵詞: stm32函數段sectio

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 海安县| 新建县| 莱阳市| 吉水县| 郯城县| 昌吉市| 丁青县| 敦化市| 册亨县| 和政县| 商南县| 克东县| 锡林浩特市| 辛集市| 交口县| 武平县| 垦利县| 铜陵市| 壶关县| 宣武区| 巧家县| 内江市| 公主岭市| 墨竹工卡县| 伽师县| 柳州市| 乡宁县| 盐津县| 黄浦区| 疏勒县| 五台县| 宜都市| 治多县| 朔州市| 河南省| 潍坊市| 从化市| 余庆县| 昂仁县| 灵武市| 游戏|