序文
- RT-Threadの自動初期化メカニズムは非常に使いやすいですが、bspのシミュレーターはそれをサポートしていません。
- 自動初期化メカニズムを調べたところ、PCシミュレータも自動初期化できることがわかりました。
研究プロセス
- bspシミュレーターを実行するには、vs2019を使用します。
- 見つかった:INIT_BOARD_EXPORT INIT_COMPONENT_EXPORT、影響なし
- コードを分析したところ、PC側のシミュレーターはデフォルトではサポートされていないことがわかりました。
/* 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
- いくつかの検索、検証、分析の結果、自動初期化メカニズムは次のとおりであることがわかりました。
- セクション(セクション、セクション)を使用する必要があり、コンパイラーに関数ポインターを入れさせます
- __attribute __((section(x)))はVS2019(_MSC_VER)ではサポートされていません
- 自動初期化を実現するために、VS2019_MSC_VERに基づくセクション操作を見つけます
- MSH_CMD_EXPORTは、シミュレーターのセクションの操作をサポートし、MSHCMD関数をエクスポートするために使用されます
VS2019セクションに基づく操作:
#pragma section(".rti_fn.$0")
#define INIT_EXPORT_LEVEL0(fn) \
__declspec(allocate(".rti_fn.$0")) const init_fn_t __rt_init_##fn = fn
- 直接使用しないのはなぜですか:( "。rti_fn。"レベル)、コンパイルエラーのため
コードを変更する
rtdef.hの変更
/* 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
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 */
有効にする:RT_USING_COMPONENTS_INIT
Kconfig実装定義を構成できます
シミュレーター:application.cで、以下を追加します。
void rt_init_thread_entry(void *parameter)
{
rt_kprintf("Hello RT-Thread!\n");
rt_components_board_init();
rt_components_init();
platform_init();
mnt_init();
自動初期化テストルーチンを追加します。
#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);
機能検証
- コンパイル済み(最新のRTスレッドコード:レポートtimegmは未定義、最初にコメントアウト)
- 実行:
\ | /
- 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 />
- 自動初期化機能を見つけて実行しました。一部の手動で実行された関数はコメントアウトできます。
総括する
- VS(Visual Studio)環境でのセクションの操作を理解する必要があります。
- PC側のツール(OD、Die、およびその他のツール)を使用して、PEファイルを分析し、生成された実行可能ファイルセクションの内容を理解できます。
- OD逆コンパイルによって生成されたexeファイルを使用して、関数のアドレスとセクションを見つけます
- ダイを使用して、exeファイルのセクションを表示します