rtems系统默认的初始化的section名字不是init,而是rtemsroset,在开启过程中,通过遍历rtemsroset下的函数指针,调用此函数指针从而对系统进行初始化动作,这里根据代码解析rtems的初始化流程
这个section是rtems的初始化section,不同于常规的elf的.init,我们可以通过如下获得section信息
# rtems-exeinfo -S build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe RTEMS Executable Info 6.ca7bcc490ee8-modified rtems-exeinfo -S build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe exe: build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe Compilation: Producers: 2 | GNU AS 2.43: 13 objects | GNU C17 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd): 282 objects Common flags: 7 | -ftls-model=local-exec -mno-outline-atomics -mcpu=cortex-a53 -mfix-cortex-a53-835769 -mfix-cortex-a53-843419 -mlittle-endian -mabi=lp64 Sections: 38 -------------- addr: 0x00000000 0x00000000 size: 0 align: 0 relocs: 0 .bss WA------------ addr: 0x00100780 0x00103618 size: 11928 align: 64 relocs: 0 .comment ---MS--------- addr: 0x00000000 0x0000006c size: 108 align: 1 relocs: 0 .data WA------------ addr: 0x00100000 0x00100768 size: 1896 align: 16 relocs: 0 .debug_abbrev -------------- addr: 0x00000000 0x000290ae size: 168110 align: 1 relocs: 0 .debug_aranges -------------- addr: 0x00000000 0x00004e00 size: 19968 align: 16 relocs: 0 .debug_frame -------------- addr: 0x00000000 0x00007e10 size: 32272 align: 8 relocs: 0 .debug_gdb_scripts ---MS--------- addr: 0x00000000 0x00000087 size: 135 align: 1 relocs: 0 .debug_info -------------- addr: 0x00000000 0x0014e550 size: 1369424 align: 1 relocs: 0 .debug_line -------------- addr: 0x00000000 0x00039263 size: 234083 align: 1 relocs: 0 .debug_line_str ---MS--------- addr: 0x00000000 0x00004a60 size: 19040 align: 1 relocs: 0 .debug_loclists -------------- addr: 0x00000000 0x0004b84b size: 309323 align: 1 relocs: 0 .debug_rnglists -------------- addr: 0x00000000 0x0000aa8b size: 43659 align: 1 relocs: 0 .debug_str ---MS--------- addr: 0x00000000 0x00012110 size: 74000 align: 1 relocs: 0 .eh_frame -A------------ addr: 0x00032a28 0x00032ae0 size: 184 align: 8 relocs: 0 .fini -AE----------- addr: 0x00030064 0x00030098 size: 52 align: 4 relocs: 0 .fini_array WA------------ addr: 0x00032b00 0x00032b08 size: 8 align: 8 relocs: 0 .got WA------------ addr: 0x00032b08 0x00032b68 size: 96 align: 8 relocs: 0 .init -AE----------- addr: 0x00030030 0x00030064 size: 52 align: 4 relocs: 0 .init_array WA------------ addr: 0x00032af8 0x00032b00 size: 8 align: 8 relocs: 0 .nocachenoload WA------------ addr: 0x3fec0000 0x3ffc0000 size: 1048576 align: 1 relocs: 0 .noinit WA------------ addr: 0x00105640 0x00106360 size: 3360 align: 8 relocs: 0 .robarrier W------------- addr: 0x00030098 0x00030098 size: 0 align: 1 relocs: 0 .rodata -A------------ addr: 0x000300a0 0x00032a21 size: 10625 align: 16 relocs: 0 .rtemsroset -A------------ addr: 0x00032b68 0x00032c18 size: 176 align: 8 relocs: 0 .rtemsstack WA------------ addr: 0x00103640 0x00105640 size: 8192 align: 64 relocs: 0 .rwbarrier WA------------ addr: 0x00032c18 0x00100000 size: 840680 align: 1 relocs: 0 .shstrtab -------------- addr: 0x00000000 0x00000178 size: 376 align: 1 relocs: 0 .stack W------------- addr: 0x3fec0000 0x3fec0000 size: 0 align: 1 relocs: 0 .start -AE----------- addr: 0x00018000 0x00018868 size: 2152 align: 16 relocs: 0 .strtab -------------- addr: 0x00000000 0x00005a5f size: 23135 align: 1 relocs: 0 .symtab -------------- addr: 0x00000000 0x0000b6a0 size: 46752 align: 8 relocs: 0 .tbss WA-------T---- addr: 0x00032af8 0x00032b28 size: 48 align: 8 relocs: 0 .tdata WA-------T---- addr: 0x00032ae0 0x00032af8 size: 24 align: 8 relocs: 0 .text -AE----------- addr: 0x00019000 0x00030030 size: 94256 align: 2048 relocs: 0 .vector W------------- addr: 0x00100000 0x00100000 size: 0 align: 1 relocs: 0 .work WA------------ addr: 0x00106360 0x3fec0000 size: 1071357088 align: 1 relocs: 0 .xbarrier W------------- addr: 0x00018868 0x00018868 size: 0 align: 1 relocs: 0
上面我们看到了.rtemsroset。我们接下来解析如下:
# rtems-exeinfo -I build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe RTEMS Executable Info 6.ca7bcc490ee8-modified rtems-exeinfo -I build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe exe: build/aarch64/zynqmp_qemu/testsuites/samples/hello.exe Compilation: Producers: 2 | GNU AS 2.43: 13 objects | GNU C17 13.3.0 20240521 (RTEMS 6, RSB b1aec32059aa0e86385ff75ec01daf93713fa382-modified, Newlib 1b3dcfd): 282 objects Common flags: 7 | -ftls-model=local-exec -mno-outline-atomics -mcpu=cortex-a53 -mfix-cortex-a53-835769 -mfix-cortex-a53-843419 -mlittle-endian -mabi=lp64 Init sections: 2 .init 0xa9bf7bfd no symbol (maybe static to a module) 0xa9bf73fb no symbol (maybe static to a module) 0xa9bf6bf9 no symbol (maybe static to a module) 0xa9bf63f7 no symbol (maybe static to a module) 0xa9bf5bf5 no symbol (maybe static to a module) 0xa9bf53f3 no symbol (maybe static to a module) .rtemsroset 0x00025910 _Workspace_Handler_initialization 0x0001f900 _Malloc_Initialize 0x00025a60 bsp_start 0x00025670 zynq_uart_kernel_init 0x0001e440 _User_extensions_Handler_initialization 0x000206c0 rtems_initialize_data_structures 0x0001ed30 _Scheduler_Ensure_exactly_one_processor 0x000240e0 _RTEMS_tasks_Manager_initialization 0x00021a30 _Thread_Create_idle 0x00024e10 bsp_r1_heap_extend 0x0001f6f0 rtems_libio_init
可以发现.rtemsroset有多个函数指针如下
0x00025910 _Workspace_Handler_initialization 0x0001f900 _Malloc_Initialize 0x00025a60 bsp_start 0x00025670 zynq_uart_kernel_init 0x0001e440 _User_extensions_Handler_initialization 0x000206c0 rtems_initialize_data_structures 0x0001ed30 _Scheduler_Ensure_exactly_one_processor 0x000240e0 _RTEMS_tasks_Manager_initialization 0x00021a30 _Thread_Create_idle 0x00024e10 bsp_r1_heap_extend 0x0001f6f0 rtems_libio_init
这里我们通过rtems-exeinfo来读取rtemsroset的section的信息,但是这个工具读取初始化流程的函数并不完整,完整的初始化流程如下。
0x00025910 _Workspace_Handler_initialization 0x0001f900 _Malloc_Initialize 0x00025a60 bsp_start 0x00025670 zynq_uart_kernel_init 0x0001e440 _User_extensions_Handler_initialization 0x000206c0 rtems_initialize_data_structures 0x0001ed30 _Scheduler_Ensure_exactly_one_processor 0x000240e0 _RTEMS_tasks_Manager_initialization 0x00021a30 _Thread_Create_idle 0x00024e10 bsp_r1_heap_extend 0x0001f6f0 rtems_libio_init 0x00019150 rtems_filesystem_initialize 0x00019200 _Console_simple_Initialize 0x0001c290 _RTEMS_tasks_Initialize_user_task 0x00019790 rtems_libio_post_driver
值得注意的是,rtems-exeinfo程序解析的不对,少了如下
0x00019150 rtems_filesystem_initialize 0x00019200 _Console_simple_Initialize 0x0001c290 _RTEMS_tasks_Initialize_user_task 0x00019790 rtems_libio_post_driver
我们搜索代码,可以知道这些函数指针通过RTEMS_SYSINIT_ITEM宏来设置,这里解析这个宏定义,如下
#define RTEMS_SYSINIT_ITEM( handler, module, order ) \ _RTEMS_SYSINIT_ITEM( handler, module, order )
上面只是封装,所以我们查看_RTEMS_SYSINIT_ITEM
#define _RTEMS_SYSINIT_ITEM( handler, module, order ) \ _RTEMS_SYSINIT_INDEX_ITEM( handler, 0x##module##order )
这里组合了module, order作为地址,我们继续看_RTEMS_SYSINIT_INDEX_ITEM
#define _RTEMS_SYSINIT_INDEX_ITEM( handler, index ) \ enum { _Sysinit_##handler = index }; \ RTEMS_LINKER_ROSET_ITEM_ORDERED( \ _Sysinit, \ rtems_sysinit_item, \ handler, \ index \ ) = { handler }
这里定义了一个enum值,并且设置了RTEMS_LINKER_ROSET_ITEM_ORDERED,我们查看其定义
#define RTEMS_LINKER_ROSET_ITEM_ORDERED( set, type, item, order ) \ RTEMS_LINKER_SET_ALIGN( type ) type const _Linker_set_##set##_##item \ RTEMS_SECTION( ".rtemsroset." #set ".content.0." RTEMS_XSTRING( order ) ) \ RTEMS_USED
这里看到
这里假设第一个初始化函数_Thread_Create_idle ,其定义如下:
RTEMS_SYSINIT_ITEM( _Thread_Create_idle, RTEMS_SYSINIT_IDLE_THREADS, RTEMS_SYSINIT_ORDER_MIDDLE );
其解析后如下:
enum { _Sysinit__Thread_Create_idle = 0x001d0080 }; __attribute__(( __aligned__( _Alignof( rtems_sysinit_item ) ) )) rtems_sysinit_item const _Linker_set__Sysinit__Thread_Create_idle __attribute__(( __section__( ".rtemsroset." "_Sysinit" ".content.0." "0x001d0080" ) )) __attribute__(( __used__ )) = { _Thread_Create_idle }
我们在rtems_initialize_executive中可以看到调用如下
/* Invoke the registered system initialization handlers */ RTEMS_LINKER_SET_FOREACH( _Sysinit, item ) { ( *item->handler )(); }
此时查看RTEMS_LINKER_SET_FOREACH定义
#define RTEMS_LINKER_SET_FOREACH( set, item ) \ for ( \ item = (void *) _Linker_set_Obfuscate( RTEMS_LINKER_SET_BEGIN( set ) ) ; \ item != RTEMS_LINKER_SET_END( set ) ; \ ++item \ )
然后查看两个宏定义
#define RTEMS_LINKER_SET_BEGIN( set ) \ _Linker_set_##set##_begin #define RTEMS_LINKER_SET_END( set ) \ _Linker_set_##set##_end
确定内联函数_Linker_set_Obfuscate
static inline uintptr_t _Linker_set_Obfuscate( const void *ptr ) { uintptr_t addr; addr = (uintptr_t) ptr; RTEMS_OBFUSCATE_VARIABLE( addr ); return addr; }
至此,我们可以知道,通过遍历_Linker_set__Sysinit_begin到_Linker_set__Sysinit_end获取到了每个item,然后之间调用handler函数指针,即如下
typedef void ( *rtems_sysinit_handler )( void ); typedef struct { rtems_sysinit_handler handler; } rtems_sysinit_item;
这里可以看到如下
(gdb) p _Linker_set__Sysinit_begin $49 = 0x32b68 <_Linker_set__Sysinit__Workspace_Handler_initialization> (gdb) p _Linker_set__Sysinit_end $50 = 0x32be0 <_Copyright_Notice>
至此,我们清楚的知道了rtems的初始化时序