Jing Yu
2009-04-15 23:08:17 UTC
Hi,
I am debugging one GCC-4.4 dejaGNU test case that fails on ARM-eabi target.
I build the toolchain with newlib and run the test on GNU arm-sim simulator.
The test case gcc/testsuite/gcc.dg/initpri1.c is testing whether the
compiler and linker process the constructor attribute and destructor
attribute correctly.
In initpri1.c, we see
void c1() __attribute__((constructor (500)));
void c2() __attribute__((constructor (700)));
void c3() __attribute__((constructor (600)));
void d1() __attribute__((destructor (500)));
void d2() __attribute__((destructor (700)));
void d3() __attribute__((destructor (600)));
void cd4() __attribute__((constructor (800), destructor (800)));
The correct execution order should be:
c1() -> c3() -> c2() -> cd4() -> cd4() -> d2() -> d3() -> d1()
However, on ARM-eabi target (GCC-4.4 + binutils-2.19 + newlib), the
sequence is wrong:
c1() -> c3() -> c2() -> cd4() -> d1() -> d3() -> d2() -> cd4()
I have checked both the assembly file (generated by arm-eabi-gcc -S)
and object dumped file (generated by arm-eabi-objdump -D). GCC puts
all constructors in .init_array section in increasing order and all
destructors in .fini_array section in increasing order.
Disassembly of section .init_array:
00013b10 <__init_array_start>:
13b10: 000081b8 .word 0x000081b8 <---- c1
13b14: 00008260 .word 0x00008260 <---- c3
13b18: 0000820c .word 0x0000820c <---- c2
13b1c: 000083b0 .word 0x000083b0 <--- cd4
00013b20 <__frame_dummy_init_array_entry>:
13b20: 00008058 .word 0x00008058 <--- frame_dummy
Disassembly of section .fini_array:
00013b24 <__do_global_dtors_aux_fini_array_entry>:
13b24: 00008018 .word 0x00008018 <-- __do_global_dtors_aux
13b28: 000082b4 .word 0x000082b4 <--- d1
13b2c: 0000834c .word 0x0000834c <--- d3
13b30: 00008300 .word 0x00008300 <--- d2
13b34: 000083b0 .word 0x000083b0 <--- cd4
However, newlib accesses entries in .fini_array in increasing order
too. So that we see a wrong order of destructors.
000084f8 <__libc_init_array>:
it calls entries in <__init_array_start> in increasing order.
000084b0 <__libc_fini_array>:
it calls entries in <__do_global_dtors_aux_fini_array_entry> in
increasing order.
000080ac <_mainCRTStartup>:
...
call <atexit> with argument <__libc_fini_array>
call <__libc_init_array>
call <main>
call <exit>
After discussing with a few GCC gurus, I was told this maybe a bug in
newlib. Because ELF specification
(http://www.caldera.com/developers/gabi/2003-12-17/ch5.dynamic.html#init_fini)
says:
"The functions pointed to in the arrays specified by DT_INIT_ARRAY and
by DT_PREINIT_ARRAY are executed by the dynamic linker in the same
order in which their addresses appear in the array; those specified by
DT_FINI_ARRAY are executed in reverse order."
The code in newlib which takes care of the fini_array is in
newlib/libc/misc/init.c:
/* Run all the cleanup routines. */
void
__libc_fini_array (void)
{
size_t count;
size_t i;
count = __fini_array_end - __fini_array_start;
for (i = 0; i < count; i++) <--------- This is the place!
__fini_array_start[i] ();
_fini ();
}
Should we change the access order or fini_array?
Thanks,
Jing
I am debugging one GCC-4.4 dejaGNU test case that fails on ARM-eabi target.
I build the toolchain with newlib and run the test on GNU arm-sim simulator.
The test case gcc/testsuite/gcc.dg/initpri1.c is testing whether the
compiler and linker process the constructor attribute and destructor
attribute correctly.
In initpri1.c, we see
void c1() __attribute__((constructor (500)));
void c2() __attribute__((constructor (700)));
void c3() __attribute__((constructor (600)));
void d1() __attribute__((destructor (500)));
void d2() __attribute__((destructor (700)));
void d3() __attribute__((destructor (600)));
void cd4() __attribute__((constructor (800), destructor (800)));
The correct execution order should be:
c1() -> c3() -> c2() -> cd4() -> cd4() -> d2() -> d3() -> d1()
However, on ARM-eabi target (GCC-4.4 + binutils-2.19 + newlib), the
sequence is wrong:
c1() -> c3() -> c2() -> cd4() -> d1() -> d3() -> d2() -> cd4()
I have checked both the assembly file (generated by arm-eabi-gcc -S)
and object dumped file (generated by arm-eabi-objdump -D). GCC puts
all constructors in .init_array section in increasing order and all
destructors in .fini_array section in increasing order.
Disassembly of section .init_array:
00013b10 <__init_array_start>:
13b10: 000081b8 .word 0x000081b8 <---- c1
13b14: 00008260 .word 0x00008260 <---- c3
13b18: 0000820c .word 0x0000820c <---- c2
13b1c: 000083b0 .word 0x000083b0 <--- cd4
00013b20 <__frame_dummy_init_array_entry>:
13b20: 00008058 .word 0x00008058 <--- frame_dummy
Disassembly of section .fini_array:
00013b24 <__do_global_dtors_aux_fini_array_entry>:
13b24: 00008018 .word 0x00008018 <-- __do_global_dtors_aux
13b28: 000082b4 .word 0x000082b4 <--- d1
13b2c: 0000834c .word 0x0000834c <--- d3
13b30: 00008300 .word 0x00008300 <--- d2
13b34: 000083b0 .word 0x000083b0 <--- cd4
However, newlib accesses entries in .fini_array in increasing order
too. So that we see a wrong order of destructors.
000084f8 <__libc_init_array>:
it calls entries in <__init_array_start> in increasing order.
000084b0 <__libc_fini_array>:
it calls entries in <__do_global_dtors_aux_fini_array_entry> in
increasing order.
000080ac <_mainCRTStartup>:
...
call <atexit> with argument <__libc_fini_array>
call <__libc_init_array>
call <main>
call <exit>
After discussing with a few GCC gurus, I was told this maybe a bug in
newlib. Because ELF specification
(http://www.caldera.com/developers/gabi/2003-12-17/ch5.dynamic.html#init_fini)
says:
"The functions pointed to in the arrays specified by DT_INIT_ARRAY and
by DT_PREINIT_ARRAY are executed by the dynamic linker in the same
order in which their addresses appear in the array; those specified by
DT_FINI_ARRAY are executed in reverse order."
The code in newlib which takes care of the fini_array is in
newlib/libc/misc/init.c:
/* Run all the cleanup routines. */
void
__libc_fini_array (void)
{
size_t count;
size_t i;
count = __fini_array_end - __fini_array_start;
for (i = 0; i < count; i++) <--------- This is the place!
__fini_array_start[i] ();
_fini ();
}
Should we change the access order or fini_array?
Thanks,
Jing