【问题标题】:Function pointer with GCC, assigning an address带有 GCC 的函数指针,分配地址
【发布时间】:2012-02-23 23:44:36
【问题描述】:

我遇到了一些我完全不明白的事情。 有一个函数原型:

typedef void ( * TMain ) ( void );

还有一个函数变量:

TMain myFunc = MyFunc;
...
myFunc ();

当然,这很好用。为什么不应该呢。

从 MAP 文件中,我知道“MyFunc”位于位置 0x20100。 现在有趣的事情。赋值后“myFunc = MyFunc;”变量“myFunc”不包含值 0x20100 而是 0x20101!

我的问题是,我需要调用一个我从表中知道地址的函数。所以我想我可以这样做

myFunc = ( TMain ) myTable [ 5 ];    // that would be 0x20100
myFunc ();                           // which produces a proper crash

如果我这样做了

myFunc = ( TMain ) ( ( Int8 * ) myTable [ 5 ] + 1 );  
myFunc ();

然后就可以了。

这里发生了什么?我是否总是必须添加 1 的偏移量,或者这或多或少是偶然的? 还是有更好的(和有效的)方法来完成任务?

非常感谢任何提示。 沃尔特

【问题讨论】:

  • 不确定,但这可能取决于架构。所以可能想说哪个是目标架构。
  • myTable 数组是 TMain[] 类型的吗?我想不是因为你在施放它。
  • 问你一些问题:你使用什么平台(ARM,x86...)?你有没有用调试器检查过函数的实际地址?你能看到编译器是如何生成间接调用“myFunc()”的吗?
  • 为什么要存储地址而不是函数?而不是声明int myTable[N],你可以做TMain myTable[N],然后你不需要演员:myfunc = myTable[5],或者你直接调用mytable[5](),即使你确实转换了函数来填充数组它会正常工作。
  • Or-ing 1 可能更适合在此处设置 Thumb 模式。

标签: c gcc function-pointers


【解决方案1】:

我猜你是在一个 ARM 目标上并且你已经在 Thumb 模式下构建了你的程序? (拇指是 ARM Ubuntu 或 Linaro 的默认设置。)

函数地址的低位告诉 CPU 它应该在哪个指令集中解释函数。 0 为 ARM 模式。 1 是拇指模式。因此所有 Thumb 模式的函数指针都是奇数。

其他架构也以一种或另一种方式使用这个习语。通常将地址的低两位归零(使其对齐 4 字节)并假设这是函数的真实位置是安全的。

【讨论】:

    【解决方案2】:

    一些 CPU 架构为特定目的保留函数的第一个字节。 VAXen 在那里有一个保存寄存器掩码。 CDC Cyber​​ 将退货地址放在那里。有些人使用“地址”的一些位来指示地址间接(我不记得是哪些,但它们来自 1970 年代)。

    除非您真的知道自己在做什么,否则您不应该编写执行这种指针运算的代码。为变量分配函数名称并完成它:保证在每个C 实现上都有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-16
      • 1970-01-01
      • 2022-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多