rt-thread 自動初始化機制分析-關於編譯鏈接及段信息

本來我的工作主要集中於嵌入式Linux這一塊,關於RTOS,雖然之前也有用UcosII做過一兩個項目並量產,但並不是主要發力點,感覺相對與Linux來說,RTOS太過“easy”,能研究的東西並不多。

最新閒來看到Rtthread發展挺不錯,文檔更新也比較多,也出了專用的IDE,加之“中美大戰”,“國產”、“愛國”等情懷也被炒至高點,因此動了心思來研究研究。

因爲之前用過ucos,所以研究路線即定爲:改用rtthread實現之前ucos項目的所有功能。

經過一週的時間,項目基本移植完成並正常使用,此過程,收益還挺多,也總結了一些觀點

1. rtthread兼容性還是不錯的,支持範圍也挺廣,Cortex M,A,R都有,還有RISC-V,尤其是R系列支持,讓人感覺非常好

2. 編碼風格及設計思想,與Linux相近,尤其是設備驅動的思想,熟悉linux的話來學習rtthread應該會很似曾相識

3. 實現了很多POSIX API,比如Socket,pthread等,甚至有與Linux相近的設備驅動,個人感覺有點不倫不類,既是一個RTOS,就應該做RTOS專業的事情(微小,實時,精妙),搞得太過複雜不一定是好事。當然它的目的肯定是爲了應用層統一和跨平臺。

4. 至於內核的實現,比如中斷處理,任務調度,通訊機制等等,基本是常用實現手段

5. shell控制檯有點意思,比較方便查看相關信息

回到正題,在研究過程中,自動初始化這一機制比較有特色,當然還有動態庫以及模塊的加載。

網上有很多關於自動初始化機制的使用以及一些實現原理的分析,在此不多描述,其核心思想是把函數加入特定段,配合特定標示符號,在系統加載過程中,捕獲特定標示,進而實現函數調用。

此文主要分析編譯過程:

首先看編譯結果的段信息

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x80100000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          817480 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         22
  Section header string table index: 21

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        80100000 010000 02ff3c 00  AX  0   0 32
  [ 2] .init             PROGBITS        8012ff3c 03ff3c 000004 00  AX  0   0  4
  [ 3] .fini             PROGBITS        8012ff40 03ff40 000004 00  AX  0   0  4
  [ 4] .rodata           PROGBITS        8012ff48 03ff48 003f35 00   A  0   0  8
  [ 5] .ARM.exidx        ARM_EXIDX       80133e80 043e80 000008 00  AL  1   0  4
  [ 6] .l1_page_table    NOBITS          80134000 043e88 004000 00  WA  0   0  1
  [ 7] .data             PROGBITS        80138000 048000 001398 00  WA  0   0  8
  [ 8] .bss              NOBITS          8013c000 049398 008cd8 00  WA  0   0 16384
  [ 9] .comment          PROGBITS        00000000 049398 00006e 01  MS  0   0  1
  [10] .ARM.attributes   ARM_ATTRIBUTES  00000000 049406 00002d 00      0   0  1
  [11] .debug_info       PROGBITS        00000000 049433 0425e0 00      0   0  1
  [12] .debug_abbrev     PROGBITS        00000000 08ba13 0087ae 00      0   0  1
  [13] .debug_loc        PROGBITS        00000000 0941c1 009650 00      0   0  1
  [14] .debug_aranges    PROGBITS        00000000 09d818 000750 00      0   0  8
  [15] .debug_line       PROGBITS        00000000 09df68 00e3dd 00      0   0  1
  [16] .debug_str        PROGBITS        00000000 0ac345 007eb6 01  MS  0   0  1
  [17] .debug_frame      PROGBITS        00000000 0b41fc 006ad8 00      0   0  4
  [18] .debug_ranges     PROGBITS        00000000 0bacd8 000148 00      0   0  8
  [19] .symtab           SYMTAB          00000000 0bae20 007840 10     20 1038  4
  [20] .strtab           STRTAB          00000000 0c2660 00520f 00      0   0  1
  [21] .shstrtab         STRTAB          00000000 0c786f 0000d9 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

沒有什麼特別,都是常用的一些段

再查看鏈接腳本imx6.lds,以imx6ul爲例

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)

SECTIONS
{
    . = 0x80100000;

    __text_start = .;
    .text :
    {
        *(.vectors)
        *(.text)
        *(.text.*)

        /* section information for finsh shell */
        . = ALIGN(4);
        __fsymtab_start = .;
        KEEP(*(FSymTab))
        __fsymtab_end = .;
        . = ALIGN(4);
        __vsymtab_start = .;
        KEEP(*(VSymTab))
        __vsymtab_end = .;
        . = ALIGN(4);

        /* section information for modules */
        . = ALIGN(4);
        __rtmsymtab_start = .;
        KEEP(*(RTMSymTab))
        __rtmsymtab_end = .;

        /* section information for initialization */
        . = ALIGN(4);
        __rt_init_start = .;
        KEEP(*(SORT(.rti_fn*)))
        __rt_init_end = .;
    } =0
    __text_end = .;

    __rodata_start = .;
    .rodata   : { *(.rodata) *(.rodata.*) }
    __rodata_end = .;

    . = ALIGN(4);

。。。。。。

    . = ALIGN(8);
    __bss_start = .;
    .bss       :
    {
    *(.bss)
    *(.bss.*)
    *(COMMON)
    . = ALIGN(4);
    }
    . = ALIGN(4);
    __bss_end = .;

    /* Stabs debugging sections.  */
    .stab 0 : { *(.stab) }
    .stabstr 0 : { *(.stabstr) }
    .stab.excl 0 : { *(.stab.excl) }
    .stab.exclstr 0 : { *(.stab.exclstr) }
    .stab.index 0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment 0 : { *(.comment) }

    _end = .;
}

註釋已經非常明確: /* section information for initialization */,及各組件的初始化,位於text段,由此可見模塊以及shell也位於此段。

以board.c的rt_hw_timer_init函數爲例,確認一下過程:

首先使用:
INIT_BOARD_EXPORT(rt_hw_timer_init);

其實現爲:

/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn)           INIT_EXPORT(fn, "1")


#define INIT_EXPORT(fn, level)                                                       \
            RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn

針對GCC:
#define SECTION(x)                  __attribute__((section(x)))

很明確rt_hw_timer_init 在.rti_fn段,包含在text段

下面,確認text段信息:

objdump -t -j .text rtthread-imx6.elf

gwind@gwind-P5820T:/media/gwind/gcode/opensource/rt-thread/bsp/imx6ul$ objdump -t -j .text rtthread-imx6.elf | grep rt_hw
801001cc l     F .text  0000002c rt_hw_timer_isr
80100334 l     F .text  00000034 rt_hw_uart_isr
8012a108 l       .text  00000000 rt_hw_context_switch_interrupt_do
80112028 g     F .text  00000038 rt_hw_trap_swi
80111cb4 g     F .text  0000022c rt_hw_stack_init
80111648 g     F .text  00000020 rt_hw_interrupt_get_irq
80111bcc g     F .text  00000034 rt_hw_set_domain_register
801103bc g     F .text  00000058 rt_hw_cpu_shutdown
80112304 g       .text  00000000 rt_hw_cpu_dcache_disable
80112098 g     F .text  00000038 rt_hw_trap_dabt
8012ff20 g     O .text  00000004 __rt_init_rt_hw_timer_init
80112244 g       .text  00000000 rt_hw_cpu_icache_enable
8011220c g       .text  00000000 rt_hw_context_switch_to
801118d0 g     F .text  00000244 rt_hw_cpu_dump_page_table
80111ee0 g     F .text  00000110 rt_hw_show_register
80122468 g     F .text  00000114 rt_hw_serial_register
8012a07c g       .text  00000000 rt_hw_context_switch_interrupt
80111724 g     F .text  000001ac rt_hw_cpu_dump_page_table_2nd
80112190 g     F .text  00000068 rt_hw_trap_fiq
80100648 g     F .text  0000007c rt_hw_uart_init
8010030c g     F .text  00000028 rt_hw_board_init
801120d0 g     F .text  00000038 rt_hw_trap_resv
80111c00 g     F .text  0000006c rt_hw_init_mmu_table
80112108 g     F .text  00000088 rt_hw_trap_irq
80111590 g     F .text  00000068 rt_hw_interrupt_init
80111690 g     F .text  00000094 rt_hw_interrupt_install
8012ff24 g     O .text  00000004 __rt_init_rt_hw_uart_init
80112320 g       .text  00000000 rt_hw_cpu_icache_disable
80111ff0 g     F .text  00000038 rt_hw_trap_undef
80111668 g     F .text  00000028 rt_hw_interrupt_ack
80111c6c g     F .text  00000048 rt_hw_mmu_init
8010bcb8  w    F .text  00000020 rt_hw_console_output
801121f8 g       .text  00000000 rt_hw_interrupt_disable
801115f8 g     F .text  00000028 rt_hw_interrupt_mask
8012a0a8 g       .text  00000000 rt_hw_context_switch_exit
801001f8 g     F .text  00000114 rt_hw_timer_init
80111b14 g     F .text  000000b8 rt_hw_mmu_setmtt
80112204 g       .text  00000000 rt_hw_interrupt_enable
80111620 g     F .text  00000028 rt_hw_interrupt_umask
80112234 g       .text  00000000 rt_hw_cpu_dcache_enable
80111570 g     F .text  00000020 rt_hw_vector_init
8012257c g     F .text  00000420 rt_hw_serial_isr
8012a058 g       .text  00000000 rt_hw_context_switch
80112060 g     F .text  00000038 rt_hw_trap_pabt

可見結果: 801001f8 g     F .text  00000114 rt_hw_timer_init

對比編譯的MAP信息:

 .text          0x00000000801001cc      0x168 build/drivers/board.o
                0x00000000801001f8                rt_hw_timer_init

最後,初始化調用,標識爲__rti_init_rti_board_end

volatile const init_fn_t *fn_ptr;

    for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
    {
        (*fn_ptr)();
    }


static int rti_board_start(void)
{
    return 0;
}
INIT_EXPORT(rti_board_start, "0.end");

static int rti_board_end(void)
{
    return 0;
}
INIT_EXPORT(rti_board_end, "1.end");

其段信息:

gwind@gwind-P5820T:/media/gwind/gcode/opensource/rt-thread/bsp/imx6ul$ objdump -t -j .text rtthread-imx6.elf | grep __rt_init_
8012ff2c g     O .text  00000004 __rt_init_dfs_init
8012ff18 g       .text  00000000 __rt_init_start
8012ff20 g     O .text  00000004 __rt_init_rt_hw_timer_init
8012ff3c g       .text  00000000 __rt_init_end
8012ff38 g     O .text  00000004 __rt_init_rti_end
8012ff18 g     O .text  00000004 __rt_init_rti_start
8012ff24 g     O .text  00000004 __rt_init_rt_hw_uart_init
8012ff28 g     O .text  00000004 __rt_init_rti_board_end
8012ff30 g     O .text  00000004 __rt_init_libc_system_init
8012ff34 g     O .text  00000004 __rt_init_finsh_system_init
8012ff1c g     O .text  00000004 __rt_init_rti_board_start

總結:

rt-thread目前裝機量也有好幾億了,使用上也非常方便,提供的組件也很豐富,值得學習及深入研究。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章