当用于ARM Cortex-M3的GCC 4.7.3(20121207)获取函数的地址时,它不会获得该函数的确切地址。我可以看到指针上有一个一分之差。
// assume at address 0x00001204;
int foo() {
return 42;
}
void bar() {
int(*p)() = &foo; // p = 0x1205;
p(); // executed successfully
foo(); // assembly: "bl 0x00001204;"
}
字符串
尽管指针指向奇数地址,但执行成功。我希望在这一点上有例外。为什么它需要那个奇怪的地址,为什么它不疼。
编辑
- SO article描述了thumb和ARM模式之间的差异。为什么当直接调用函数时,尽管CPU处于相同的模式,但该偏移量不可见?
- 是否应该保留奇数地址,或者重置位0是否会导致硬地址?(我现在才看到的)
1条答案
按热度按时间flvlnr441#
我从我的一个例子中拼凑了一些东西来快速演示正在发生的事情。
vectors.s
:字符串
blinker01.c
:型
Makefile:
型
拆卸:
型
首先注意
hang
和hello
,这是一个gnuism,你需要在汇编中声明一个标签作为一个thumb函数,以便它实际上可以处理这种事情。hang
被正确声明,向量表正确使用奇数地址,hello
没有正确声明,偶数地址被放在那里。C编译的代码会自动正确地执行此操作。这里有一个很好的例子,
bl
到C函数notmain
没有,也不能使用奇数地址。但是要使用bx
,您需要函数main
的地址,该地址将作为0x 8000069提供给代码,用于地址为0x 8000068的函数,如果您在ARMvsometingT上执行bx
到0x 800068操作,它将切换到arm模式,如果它进入thumb模式,则最终会崩溃(希望崩溃,而不是跌跌撞沿着)在一个cortex-m的bx
到一个偶数地址应该立即故障。型
为什么
bl
不能是奇数?看看上面的编码bl
从0x 8000050到0x 8000068,pc
是2个字节,所以用0x 8000068 - 0x 8000054 = 0x 14除以2,你得到0x 00 A。这是pc
的偏移量,也是指令中编码的内容(指令后半部分的0A)。除以2是基于thumb指令总是2字节(在当时)的知识,因此如果它们将偏移量放在2字节指令中而不是字节中,则它们可以达到两倍的距离。因此,lsbit
丢失了两者之间的增量,因此由硬件控制。你的代码所做的是在一个地方你要求一个thumb函数的地址,它给出了奇数地址,另一种情况是查看一个分支链接的反汇编,它总是偶数。