Sounds like this could've been solved with a simple ALIGN(8) in the ldscript, right? I don't know what made the compiler think that it would have to align i386 pointers to 8 byte (which seems to be what happened), but if it makes that decision then it should also conclude that sizeof(struct boot_state_init_entry) == 0x20 and the array traversal should still work. If those structures need to be writable we could simply move them from .rodata to .data in the ldscript.
Aaron, do you have a definitive source for the "no two symbols may be the same" rule? Because that's a pretty common pattern, I would be surprised if it was incorrect (especially since there's things like __attribute__((alias)) that explicitly allow you to do it even in C). I can't find anything in a cursory glance at the standard... in fact, 6.5.9.6 (of some weird 2007 draft version I found, at least) says:
"Two pointers compare equal if and only if [...] or one is a pointer to one past the end of an array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space."
From that I'd conclude that if you did:
extern struct boot_state_init_entry _bs_init_begin[]; extern struct boot_state_init_entry _bs_init_end[];
for (cur = _bs_init_begin; cur < _bs_init_end; cur++) ...
the compiler shouldn't be able to guarantee that the first array wasn't empty and therefore pointing to "one after the end" which is the start of the next array in the first iteration.