如何解决C++ 试图将地址转换为 void* 并分配给函数指针以便我的引导加载程序可以跳转到实际应用程序
我正在为 STM32 编写引导加载程序,我需要从引导加载程序跳转到真正的应用程序。
在 C 中这是可行的,因为我可以将地址转换为 void 指针并将其分配给函数指针,然后按如下方式调用函数指针:
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void *)reset_handler_add;
SCB->VTOR = address;
uint32_t msp_value = *((volatile uint32_t *)address);
__set_MSP(msp_value);
app_reset_handler();
}
如果我在 C++ 中使用相同的实现,gnu 编译器将在转换为 void 指针时出错。
include/bootloader.hpp:58:39: 错误:来自“void*”的无效转换 'void (*)()' [-fpermissive]
谷歌搜索后我找到了 this SO page,我尝试并在我的班级中实现了以下实现:
void JumpToApp()
{
// Quick test if C style cast does work
//jump_to_firmware(_appStartAddress);
uint32_t mspAdress = *((volatile uint32_t *)_appStartAddress);
uint32_t resetHandlerAddress = *((volatile uint32_t *)(_appStartAddress + sizeof(uint32_t)));
// https://stackoverflow.com/questions/1096341/function-pointers-casting-in-c
typedef void (*functionPointer)();
functionPointer resetHandler = 0;
reinterpret_cast<void*&>(resetHandler) = (void*)resetHandlerAddress;
SCB->VTOR = _appStartAddress;
__set_MSP(mspAdress);
resetHandler();
}
在 C++ 实现中:
-
functionPointer resetHandler
被分配了0x8035065
-
SCB->VTOR
被分配了0x08020000
-
mspAddress
被分配了 `0x20020000 - 然后调用函数指针
resetHandler
在 C 实现中:
-
app_reset_handler
被分配了0x8035065
-
SCB->VTOR
被分配了0x08020000
-
mspAddress
被分配了 `0x20020000 - 然后调用函数指针
app_reset_handler
C 实现有效,它跳转到我的应用程序,应用程序运行没有问题。
C++ 实现最终无处可去。它在以下(对我来说毫无意义)地址上挂起/崩溃:
我试图将源文件的数量保持在最低限度,因此我希望将逻辑保留在单个类定义中。
我的问题:
- 我是否误解了链接的 SO 页面,有人可以看到我在 C++ 实现中哪里出错了吗?
- 是否有更好/更简单的方法将地址转换为 C++ 中的函数指针?
- 或者是否有技术原因无法在 C++ 中完成?
PS:引导加载程序代码在两种情况下是相同的。我为测试这两种实现所做的唯一区别是注释掉 Bootloader::JumpToApp
中的代码并改为调用 C 函数 jump_to_firmware(uint32_t)
。
PPS:所有外围设备都已正确取消初始化。同样,它工作正常,只有当我使用这个 C++ 实现时才会出现问题。
解决方法
同样的代码可以在 C 和 C++ 中编译。您必须简单地转换为正确的转换(在 C++ 中,您不能将 void *
分配给非 void *
指针。它比在 C 中严格得多。
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void (*)(void))reset_handler_add;
/* ... */
}
如果你不喜欢那些奇怪的转换,你可以 typedef 函数。
typedef void handler(void);
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
handler *app_reset_handler = (handler *)reset_handler_add;
/* ... */
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。