2012-02-01 64 views
6

我遇到了我彻底不明白的东西。 有一个函数原型:功能指针与海湾合作委员会,分配地址

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的偏移量,或者这或多或少是偶然的? 还是有更好的(和工作)的方式来完成任务?

非常感谢任何提示。 Walter

+2

不确定,但这可能取决于架构。所以可能想说哪个是目标架构。 – phimuemue 2012-02-01 09:34:35

+1

是'TMain []''类型的myTable'数组吗?我认为这不是因为你在投它。 – 2012-02-01 09:35:36

+1

对你有些问题:你在使用什么平台(ARM,x86 ...)?你有没有用调试器检查函数的实际地址?你能看到编译器如何生成间接调用“myFunc()”吗? – 2012-02-01 09:39:20

回答

3

几种CPU架构为特定目的保留函数的第一个字节。 VAXen在那里有一个保存寄存器掩码。 CDC Cyber​​将回复地址放在那里。有些使用“地址”的某些位来表示地址间接(我不记得哪一个,但他们是从20世纪70年代开始的)。

除非你真的知道你在做什么,否则你不应该编写那种做指针算术的代码。为变量分配函数名称并用它完成:保证在每个C实现中都能正常工作。

3

我的猜测是你在ARM的目标,你已经建立你的程序在拇指模式? (Thumb是ARM Ubuntu或Linaro的默认设置。)

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

其他体系结构也以这种或那种方式使用这种习语。通常只需将地址的底部两位清零(使其4字节对齐)并假定这是该函数的真实位置即可。

相关问题