I'm writing my own init code that should traverse an array of global constructors and call them. The pointers to these constructors are stored in the .init_array section. My code looks like this:
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)();
}
}
The externals are defined in a linker script like this:
.init_array :
{
. = ALIGN(4);
_init_array_start = .;
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
. = ALIGN(4);
_init_array_end = .;
} >rom
However, the final assembler code looks like this:
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
Now, the interesting part here is 0x16 and 0x18. These two instructions dereference _init_array_start and _init_array_end in the loop header. This is not what I intended. I want to work on the pointers to the function pointers, not on their values (i.e. the function pointers directly). Now, when I change the extern declarations to the following, the two dereferencing instructions magically disappear:
extern void (*_init_array_start[0])();
extern void (*_init_array_end[0])();
So, why does the compiler dereference the pointers in the first place, and why does it not do that with the array syntax? Shouldn't these two syntaxes be equivalent?