我正在编写自己的init代码,该代码应遍历全局构造函数数组并调用它们。指向这些构造函数的指针存储在.init_array部分中。我的代码如下所示:
extern void (**_init_array_start)();
extern void (**_init_array_end)();
void _init()
{
void (**ctor)();
for (ctor = _init_array_start ; ctor != _init_array_end ; ctor++) {
(*ctor)();
}
}
externals在链接器脚本中定义如下:
.init_array :
{
. = ALIGN(4);
_init_array_start = .;
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
. = ALIGN(4);
_init_array_end = .;
} >rom
但是,最终的汇编程序代码如下所示:
00000010 <_init>:
10: b538 push {r3, r4, r5, lr}
12: 4b05 ldr r3, [pc, #20] ; (28 <_init+0x18>)
14: 4d05 ldr r5, [pc, #20] ; (2c <_init+0x1c>)
16: 681c ldr r4, [r3, #0]
18: 682b ldr r3, [r5, #0]
1a: 429c cmp r4, r3
1c: d003 beq.n 26 <_init+0x16>
1e: f854 3b04 ldr.w r3, [r4], #4
22: 4798 blx r3
24: e7f8 b.n 18 <_init+0x8>
26: bd38 pop {r3, r4, r5, pc}
28: 00000144 andeq r0, r0, r4, asr #2
2c: 00000150 andeq r0, r0, r0, asr r1
现在,这里有趣的部分是0x16和0x18。这两条指令在循环头中取消引用_init_array_start和_init_array_end。这不是我的意图。我想处理函数指针的指针,而不是它们的值(即函数指针直接)。 现在,当我将extern声明更改为以下内容时,两个解除引用指令神奇地消失了:
extern void (*_init_array_start[0])();
extern void (*_init_array_end[0])();
那么,为什么编译器首先取消引用指针,为什么它不使用数组语法呢?这两种语法不应该等价吗?
答案 0 :(得分:1)
符号(几乎)总是地址,而指针与数组不同。
extern int* i;
表示“符号'i'是int *的地址。”
i
则表示“符号'i'指定的地址处的值,这是一个指针取消引用。 &i
表示“符号'i'指定的地址,而不是。
在数组的情况下,“extern int a [42];”表示“符号'a'是42个整数的数组的地址。”当数组名在C中单独使用时,它引用数组的地址,因此a
在此处等同于前一个示例中的&i
。 &a
也指向相同的地址,但具有不同的类型。两者都具有由符号'a'指定的地址。
如果您不想使用数组语法,那么如果您将extern void (**_init_array_start)();
更改为extern void (*_init_array_start)();
并将_init_array_start
更改为&_init_array_start
,则您发布的第一个代码应该有效。
编辑:另一种看待这种情况的方法是_init_array_start不是指向第一个初始化程序的指针 - 它是第一个初始化程序 - 因此将其声明为指向函数指针的指针是错误的。数组语法将其声明为函数指针数组,这实际上就是它。
答案 1 :(得分:0)
_init_array_start
是存储构造函数的第一个指针的地址。您必须从此变量中获取地址并迭代到_init_array_end
的地址。考虑到这一点,你必须调整指针类型以适应这种方法。
答案 2 :(得分:0)
这是指向指针类型的指针对象的声明:
extern void (**_init_array_start)();
这是与数组开头关联的符号名称的定义:
_init_array_start = .;
但是你没有为指针类型的指针分配存储空间,只有数组。
听起来你可能想以这种方式处理C方面:
extern void (*_init_array_start)();
extern void (*_init_array_end)(); // One past the end; not a real object.
void _init()
{
void (**ctor)();
for (ctor = &_init_array_start ; ctor != &_init_array_end ; ctor++) {
(*ctor)();
}
}
生成一个全局整数值来表示数组的大小并从C访问它可能会更清晰,尽管这意味着为所述整数分配存储空间。