views:

89

answers:

1

Can somebody explain me how the following code works?

# if   defined(__ELF__)
#  define __SECTION_FLAGS   ", \"aw\" , @progbits"
    /* writable flag needed for ld ".[cd]tors" sections bug workaround) */
# elif defined(__COFF__)
#  define __SECTION_FLAGS   ", \"dr\""
    /* untested, may be writable flag needed */
# endif

asm
(
    ".section .ctors" __SECTION_FLAGS "\n"
    ".globl __ctors_begin__\n"
    "__ctors_begin__:\n"
    ".previous\n"
);
asm /* ld ".[cd]tors" sections bug workaround */
(
    ".section .ctors0" __SECTION_FLAGS "\n"
    ".globl __ctors0_begin__\n"
    "__ctors0_begin__:\n"
    ".previous\n"
);

Similarly we are getting __ctors_end__ , __ctors0_end__ and destructors location is also obtained this way. After some ld bug workarounds all functions pointed by pointers from __ctors_begin__ to __ctors_end__ are executed. I don't know assembler and this code is impossible for me to interpret.

BTW: I know that invoking C++ contructors/destructors from C is not a task to be considered safe or easy.

+4  A: 

This isn't actually code executed by the CPU but it's added to the metadata of the object files. It tells the linker to create some global variables (__ctors_begin__ in the example above) in the same section (= part) of the final executable where the constructors are stored (that section is called .ctors). To make it work, you just have to make sure that the file with the "begin" variable is linked first and the file with the "end" variable is linked last (but maybe you can also control this with the __SECTION_FLAGS). That gives you the memory range you're looking for.

As for "safe": Well, the C++ runtime isn't magic. Somehow it has to know how to run all the constructors and destructors at startup and that doesn't change all the time. So for a major version number of your compiler, this should be pretty safe. Also, you'll know pretty soon when it breaks :-)

Aaron Digulla