【问题标题】:Return value from function in "function pointer mode"从“函数指针模式”中的函数返回值
【发布时间】:2021-10-22 21:09:05
【问题描述】:

首先,对不起我的英语。我是巴西人,仍在努力学习(英语和编程)。

我正在尝试创建一个固件应用程序(STM32 uc),它可以访问其他固件(我的地址分为 BL + FWA + FWB),但我有一个问题,找不到原因。 FWB 需要访问 FWA 上的一个函数,以使用更少的 flash 区域。 我可以访问函数本身,执行其中的任何操作,但是当达到返回时,它给了我一个 HardFault。 我正在使用分散文件来使用 FWA 和 B 上共享的内存。

  LR_IROM1 0x08004000 0x00004000  {    ; load region size_region
  ER_IROM1 0x08004000 0x00004000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 UNINIT 0x00001000  {  ; No init data
   *(.noinit)
  }
  RW_IRAM2 0x20001000 0x00004000  {
   .ANY (+RW +ZI) //RW data
  }
}

我的功能被定义为

uint getInt(void) __attribute__((section(".ARM.__at_0x8006000")));//My fw was at 0x4000, total size is 0x4000,
                                                                  //so space is not the problem.
uint getInt(void){
    return 42;
}

在我的应用程序上(在 FWA 上运行以测试自身,但没有结果),我试图这样称呼它:

uint (*fun_ptr)(void) = (uint(*)(void))0x8006000;
uint _get_int= fun_ptr();
uint result = _get_int();

编辑: 使用时

IntFunc p =             getInt;
uint ccccc = p();
uint aaaa = getInt();

所有选项都可以正常工作,问题出在使用地址时。

正如我所提到的,我可以进入函数“getInt()”,我可以执行其中的任何代码指令,但是当达到“return 42”时,我有一个 HardFault。

我找到了另一种方法来做到这一点,使用结构,工作,但我认为理解这个问题非常重要,了解错误在哪里,这有助于不再犯错误。

编辑 2: 我想了解问题,而不仅仅是简单地获得解决方案。 这种方法对我有用: main.h 文件

typedef struct bootloaderApi bootloaderApi;
typedef   unsigned int (*do_something_t)(void);
struct bootloaderApi{
    do_something_t do_something;
};

和 Main.c:

const struct bootloaderApi api __attribute__((section(".ARM.__at_0x8005000")))
= {.do_something = &getInt}; //address 0x5000 to test.

并将其用作

struct bootloaderApi *apit = (struct bootloaderApi *)0x8005000;
uint pa = api.do_something();

它工作正常,pa 将 uint 42 返回给我。

谢谢。

【问题讨论】:

  • 但是当达到“return 42”时,我有一个 HardFault。 -- 我没有在 stm32 上工作过,但是根据我在 Windows 上的经验,每当return崩溃,这通常表明调用者和被调用者之间的调用约定不匹配。请注意,您的功能非常简单,所以对我来说这就是我怀疑或类似的东西。
  • 如果您不熟悉什么是调用约定,here is a link。当然,如果您知道它们是什么,那么您就会知道我在说什么。
  • 另外,准备函数时的环境是否知道正在返回uint(就大小而言)而不是不同字节大小的东西?如果不是,那么这可能是另一个原因(我看到你说它适用于结构,但不适用于非常简单的uint)。此外,我会坚持使用已知的 C++ 类型,例如 uint32_t 或类似类型,而不是 uint,只是为了明确说明实际类型是什么。
  • @PaulMcKenzie,感谢您的链接,我会阅读的。抱歉,我认为我解释错了:“当我使用一个内部带有函数的结构时,将函数 getInt 映射到 struct 的成员,并将结构映射到地址,而不映射 getInt 函数本身,它可以工作。当我调用mystruct.getIntMethod(),它工作正常。我将编辑问题以提出工作方法,以澄清它。
  • @PaulMcKenzie 我编辑了我的问题,以解释什么更好。

标签: c++ c stm32


【解决方案1】:

试试:

uint (*fun_ptr)(void) = (uint(*)(void))0x8006001;

因为这个架构上的所有函数指针都必须是奇数。

地址是第一条指令的真实地址(总是偶数)加一。最后一位表示该指令使用的是“thumb”指令集,而不是“arm”指令集,该指令集在该设备上不可用。

【讨论】:

  • 谢谢。我现在不能尝试,但这对我来说很有意义。当我尝试时,我会回来告诉你。
  • 我等不及了,现在就测试它。有用。非常感谢,不是代码本身,而是解释原因。
  • 汤姆,还有一个问题:地址的设置是否正确?设置在0x8006000并在0x8006001访问,或者设置也需要在0x8006001?你有什么链接可以让我多学习一点吗?
  • 指令的地址是 8006000。Thumb 指令是 16 位或 32 位的,所以 8006001 处的字节也是指令的一部分,但要使指令正确对齐,您必须将 8006000 放入链接器脚本。当处理器被告知调用 8006001 处的函数时,它会减一并从地址 8006000 中获取。它执行包括两个字节的 32 位加载,但程序计数器寄存器中的地址不包括最低位。
猜你喜欢
  • 2018-03-07
  • 2011-12-06
  • 1970-01-01
  • 2017-09-05
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
相关资源
最近更新 更多