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目前装机量也有好几亿了,使用上也非常方便,提供的组件也很丰富,值得学习及深入研究。

 

 

 

你可能感兴趣的:(IOT,rtthread,链接,自动初始化)