Prefacio
- El mecanismo de inicialización automática de RT-Thread es muy fácil de usar, pero el simulador en bsp no lo admite.
- Estudié el mecanismo de inicialización automática y descubrí que el simulador de PC también se puede inicializar automáticamente.
proceso de investigación
- Para ejecutar el simulador bsp, use vs2019.
- Encontrado: INIT_BOARD_EXPORT INIT_COMPONENT_EXPORT, sin efecto
- El análisis del código encontró que el simulador del lado de la PC no es compatible de forma predeterminada:
/* initialization export */
#ifdef RT_USING_COMPONENTS_INIT
typedef int (*init_fn_t)(void);
#ifdef _MSC_VER /* we do not support MS VC++ compiler */
#define INIT_EXPORT(fn, level)
#else
- Después de algunas búsquedas, verificación y análisis, se encuentra que el mecanismo de inicialización automática es el siguiente:
- Necesita usar la sección (sección, sección), deje que el compilador coloque el puntero de la función en él
- __attribute __ ((section (x))) no es compatible con VS2019 (_MSC_VER)
- Encuentre la operación de la sección basada en VS2019 _MSC_VER para realizar la inicialización automática
- MSH_CMD_EXPORT, admite el funcionamiento de la sección del simulador y se utiliza para exportar la función MSH CMD
Operación basada en la sección VS2019:
#pragma section(".rti_fn.$0")
#define INIT_EXPORT_LEVEL0(fn) \
__declspec(allocate(".rti_fn.$0")) const init_fn_t __rt_init_##fn = fn
- ¿Por qué no usarlo directamente: (nivel ".rti_fn."), Porque el error de compilación
Modifica el código
rtdef.h modificación
/* initialization export */
#ifdef RT_USING_COMPONENTS_INIT
typedef int (*init_fn_t)(void);
#ifdef _MSC_VER /* we do not support MS VC++ compiler */
#pragma section(".rti_fn.$0")
#pragma section(".rti_fn.$1")
#pragma section(".rti_fn.$2")
#pragma section(".rti_fn.$3")
#pragma section(".rti_fn.$4")
#pragma section(".rti_fn.$5")
#pragma section(".rti_fn.$6")
#pragma section(".rti_fn.$0.end")
#pragma section(".rti_fn.$1.end")
#pragma section(".rti_fn.$6.end")
#define INIT_EXPORT_LEVEL0(fn) \
__declspec(allocate(".rti_fn.$0")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL0_END(fn) \
__declspec(allocate(".rti_fn.$0.end")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL1_END(fn) \
__declspec(allocate(".rti_fn.$1.end")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL6_END(fn) \
__declspec(allocate(".rti_fn.$6.end")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL1(fn) \
__declspec(allocate(".rti_fn.$1")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL2(fn) \
__declspec(allocate(".rti_fn.$2")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL3(fn) \
__declspec(allocate(".rti_fn.$3")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL4(fn) \
__declspec(allocate(".rti_fn.$4")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL5(fn) \
__declspec(allocate(".rti_fn.$5")) const init_fn_t __rt_init_##fn = fn
#define INIT_EXPORT_LEVEL6(fn) \
__declspec(allocate(".rti_fn.$6")) const init_fn_t __rt_init_##fn = fn
#else
#if RT_DEBUG_INIT
struct rt_init_desc
{
const char* fn_name;
const init_fn_t fn;
};
#define INIT_EXPORT(fn, level) \
const char __rti_##fn##_name[] = #fn; \
RT_USED const struct rt_init_desc __rt_init_desc_##fn RT_SECTION(".rti_fn." level) = \
{ __rti_##fn##_name, fn};
#else
#define INIT_EXPORT(fn, level) \
RT_USED const init_fn_t __rt_init_##fn RT_SECTION(".rti_fn." level) = fn
#endif
#endif
#else
#define INIT_EXPORT(fn, level)
#endif
/* board init routines will be called in board_init() function */
#ifdef _MSC_VER
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT_LEVEL1(fn)
#else
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
#endif
/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#ifdef _MSC_VER
#define INIT_PREV_EXPORT(fn) INIT_EXPORT_LEVEL2(fn)
#else
#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")
#endif
/* device initialization */
#ifdef _MSC_VER
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT_LEVEL3(fn)
#else
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")
#endif
/* components initialization (dfs, lwip, ...) */
#ifdef _MSC_VER
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT_LEVEL4(fn)
#else
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")
#endif
/* environment initialization (mount disk, ...) */
#ifdef _MSC_VER
#define INIT_ENV_EXPORT(fn) INIT_EXPORT_LEVEL5(fn)
#else
#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
#endif
/* appliation initialization (rtgui application etc ...) */
#ifdef _MSC_VER
#define INIT_APP_EXPORT(fn) INIT_EXPORT_LEVEL6(fn)
#else
#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")
#endif
modificación de components.c:
static int rti_start(void)
{
return 0;
}
#ifdef _MSC_VER
INIT_EXPORT_LEVEL0(rti_start);
#else
INIT_EXPORT(rti_start, "0");
#endif
static int rti_board_start(void)
{
return 0;
}
#ifdef _MSC_VER
INIT_EXPORT_LEVEL0_END(rti_board_start);
#else
INIT_EXPORT(rti_board_start, "0.end");
#endif
static int rti_board_end(void)
{
return 0;
}
#ifdef _MSC_VER
INIT_EXPORT_LEVEL1_END(rti_board_end);
#else
INIT_EXPORT(rti_board_end, "1.end");
#endif
static int rti_end(void)
{
return 0;
}
#ifdef _MSC_VER
INIT_EXPORT_LEVEL6_END(rti_end);
#else
INIT_EXPORT(rti_end, "6.end");
#endif
/**
* RT-Thread Components Initialization for board
*/
void rt_components_board_init(void)
{
#if RT_DEBUG_INIT
int result;
const struct rt_init_desc *desc;
for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
result = desc->fn();
rt_kprintf(":%d done\n", result);
}
#else
volatile const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
{
if (*fn_ptr != RT_NULL)
(*fn_ptr)();
}
#endif
}
/**
* RT-Thread Components Initialization
*/
void rt_components_init(void)
{
#if RT_DEBUG_INIT
int result;
const struct rt_init_desc *desc;
rt_kprintf("do components initialization.\n");
for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
result = desc->fn();
rt_kprintf(":%d done\n", result);
}
#else
volatile const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
{
if (*fn_ptr != RT_NULL)
(*fn_ptr)();
}
#endif
}
#endif /* RT_USING_COMPONENTS_INIT */
Habilitar: RT_USING_COMPONENTS_INIT
La definición de implementación de Kconfig se puede configurar
En el simulador: application.c, agregue:
void rt_init_thread_entry(void *parameter)
{
rt_kprintf("Hello RT-Thread!\n");
rt_components_board_init();
rt_components_init();
platform_init();
mnt_init();
Agregue rutinas de prueba de inicialización automática:
#include <rtthread.h>
int func_a1(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
int func_a2(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
int func_a3(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
int func_a4(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
int func_a5(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
int func_a6(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
int func_a7(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
int func_a8(void)
{
rt_kprintf("%s: init ok!\n", __func__);
return 0;
}
INIT_BOARD_EXPORT(func_a1);
INIT_PREV_EXPORT(func_a2);
INIT_DEVICE_EXPORT(func_a3);
INIT_COMPONENT_EXPORT(func_a4);
INIT_ENV_EXPORT(func_a5);
INIT_APP_EXPORT(func_a6);
INIT_DEVICE_EXPORT(func_a7);
INIT_ENV_EXPORT(func_a8);
Verificación funcional
- Compilado (el último código RT-Thread: report timegm no está definido, comenta primero)
- correr:
\ | /
- RT - Thread Operating System
/ | \ 4.0.3 build Mar 13 2021
2006 - 2021 Copyright by rt-thread team
Hello RT-Thread!
func_a1: init ok!
func_a2: init ok!
func_a3: init ok!
func_a7: init ok!
func_a4: init ok!
func_a5: init ok!
func_a8: init ok!
func_a6: init ok!
finsh shell already init.
dfs already init.
File System on root initialized!
[E/DFS] There is no space to mount this file system (elm).
File System on sd initialization failed!
msh />
- Encontré la función de inicialización automática y la ejecuté. Algunas funciones ejecutadas manualmente se pueden comentar.
para resumir
- Necesita comprender el funcionamiento de la sección en el entorno VS (Visual Studio).
- Puede utilizar las herramientas del lado de la PC: OD, Die y otras herramientas para analizar el archivo PE y comprender el contenido de la sección del archivo ejecutable generado
- Utilice el archivo exe generado por la descompilación OD para encontrar la dirección y la sección de la función
- Utilice Die para ver la sección del archivo exe