9

The answer here demonstrates that __attribute__((constructor)) is not called after static initialization, it is called in the declaration order.

Then, what is the purpose of it, if it is not guaranteed to be called when all data is initialized? We could as well have our ((constructor)) code in the Foo constructor.

What I'm looking for is a way to have, in a shared library, a code that will be executed after all static data is initialized and static constructors are called. I saw people recommending __attribute__((constructor)) as a replacement for DllMain; as we can see this is wrong, because some static data may still be not initialized.

Of course in single file (compilation unit) we could arrange statics. But in a typical program there's a lot of files. Is there a way to guarantee that ((constructor)) in one file will be definitely called after all other statics in a shared library are initialized?

If I put a file with static initialization (constructor, object, etc) to the end of the gcc command line:

g++ -shared -fPIC source1.o source2.o MyLastInitChance.o

are this file's static constructors guaranteed to be called last? I experimented and when I change order of source files, printfs' order is changed; but is it specified somewhere and guaranteed to be the same across compilation systems/computers?

For example, a quote:

At link time, the gcc driver places crtbegin.o immediately before all the relocatable files and crtend.o immediately after all the relocatable files. ©

From what I understand the quote above implies that order of .o files passed to the linker defines order of the static initialization. Am I correct?

Another interesting possible solution, maybe, is to write a GCC plugin that adjusts static initialization (e.g. adds code to .ctors section, etc). But this is just an idea that maybe someone can extend.

One more possible solution is presented here. In short, an external post-build tool can be used to reorder .ctors entries in the executable file (library). But I'm not an expert in ELF format; I wonder if this is possible and easy enough to tweak .so files in this way.

What I'm interested in is solving a particular problem, or proving that it is impossible to solve (at least why the solutions above would not work).

Community
  • 1
  • 1
queen3
  • 14,883
  • 8
  • 54
  • 114
  • 7
    `__attribute((constructor))__` makes more sense for pure C, rather than C++. – Oliver Charlesworth Jun 19 '12 at 18:30
  • 1
    You can also specify __attribute__((constructor(0))) etc. for specifying the order the functions are called in. –  Jun 19 '12 at 19:05
  • Unfortunately, priority 0 causes it to be called first, while I need it to be called last. Higher priorities do not help, too. – queen3 Jun 19 '12 at 19:12
  • Why doesn't `DllMain` work for you? – TonyK Jun 23 '12 at 22:16
  • What I would like to do is to port large existing legacy Windows code (that uses DllMain) without changing it. – queen3 Jun 24 '12 at 07:01
  • @H2CO3, Priorities lower than 101 are reserved, **do not use them**! Priorities can go up to 65535, just don't use anything below 101 – Jonathan Wakely Jun 26 '12 at 22:16
  • @Jonathan Wakely is it possible then that priority 101 is that OP needs? –  Jun 27 '12 at 02:28
  • No, because [Lower numbers indicate a higher priority.](http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html) (does noone read documentation these days?!) Maybe priority 65535 so it runs _later_ not earlier. But I think that won't help, even priority 65535 doesn't enforce any ordering relative to statics in other translation units. – Jonathan Wakely Jun 27 '12 at 07:54
  • Yes, 65535 just means "default priority". – queen3 Jun 28 '12 at 07:41

4 Answers4

13

You might try using linker scripts for ld. You can read more about it here, but I guess what you are looking for is

.ctors : { *(SORT(.ctors)) MyLastInitChance.o(SORT(.ctors)) }
.dtors : { *(SORT(.dtors)) MyLastInitChance.o(SORT(.dtors)) }

in SECTIONS{...} block. That should rearrange .ctors sections so file provided will call it's constructors as the last one. Obviously more advanced solutions are also available if you find yorself in need for one;)

HINT: writing your own link-script is tedious. Use ld's --verbose option that prints out used link script and modify it. Then add your linking script using -T switch.

j_kubik
  • 5,914
  • 1
  • 21
  • 42
  • The bounty ends tomorrow and I did not have time to experiment with linkers scripts, but this is close to what I need and looks promising, thanks. I will definitely check that out. – queen3 Jun 28 '12 at 08:02
  • 1
    After investigations objdump gives .ctors to be empty (only FFFFFFFF), .init_array has some data but doesn't seem to be affected by rearranging. I wonder if what I need to rearrange is \__CTOR_LIST__ data. I think gcc puts single initialization func into .init_array and this func walks \_\_CTOR_LIST\_\_. – queen3 Jun 28 '12 at 20:14
2

the biggest advantage of attribute((constructor))__ is the priority associated with each block and specifically helps your case.

You have two block of codes which have data hazard (one set should be executed first). This cannot be achieved by single static block. Using one static block and one attribute((constructor))__ will not solve your problem because of confusion regarding the order.

The best way to deal with the problem is to have two attribute((constructor))__ with two different priorities. Move your existing static initialization block to higher priority (0) and the other code block to lower priority.

  • No, I can use priorities only for my code, not for the "other" static variables. – queen3 Jun 22 '12 at 18:08
  • If you can't change the "other" static variables it is better to not implement the feature at all, as you will be hampering the maintainability of Code. Even if you achieve what you are trying to achieve with some hacking, you will be flooded with hard to find bugs. **Either change your design or change the other code** –  Jun 22 '12 at 18:41
  • Both solutions in bold do not answer my question. – queen3 Jun 22 '12 at 19:50
  • I know answers to other questions. – queen3 Jun 23 '12 at 07:17
  • I am afraid that you know the answer to this question as well. But the answer is not what you want to be. The answer is **NO you cannot order static and constructor attribute**. You should know that your asking the question will not create a new feature, to implement a new feature you should join the GCC contributors and implement the functionality, and that is only after you have convinced all others that such kind of functionality is actually needed! –  Jun 23 '12 at 10:46
  • "NO you cannot order" - this is wrong because there IS the order feature - ALREADY, and it is init_priority. But I do not want to order all of them; I only want to run last. – queen3 Jun 23 '12 at 16:11
  • You are confused... Running first / last is actually called order of execution. I would be better if you just close the question, because you do not understand what you are asking... –  Jun 23 '12 at 16:20
  • Order of execution? You said I cannot order. – queen3 Jun 23 '12 at 17:54
  • Anyway, what I'm interested in is solving a particular problem, OR proving that it is impossible to solve. "Proving" here means few quotes and/pr proof links, not just NO. – queen3 Jun 23 '12 at 21:27
  • 1. To solve the problem **Either change your design or change the other code**. Both with constructor attribute and init-priority you have to do the same
    2. This is a QA site not a proof site. Some of the proofs actually require a Masters or Doctorate level dissertation.
    –  Jun 24 '12 at 05:51
  • In case the answer is complex enough to require a dissertation, I probably won't get it here. This I can understand. I will close the question is _your_ answer will prove that this is the case. For now it does not. – queen3 Jun 24 '12 at 06:56
  • The answer could be "you may rearrange .ctors section" (which is what even folks at Mozilla considered doing), that I found myself some time afterwards, still investigating (this is why I am also asking for proof, e.g. maybe .ctors is a bad idea). Another solution is probably still possible. If you don't want to waste your time just don't answer, this is easy. – queen3 Jun 24 '12 at 18:30
  • You may rearrange .ctors, and in this case it shouldn't be that difficult to do - look at my answer. – j_kubik Jun 27 '12 at 22:42
2

See this: http://gcc.gnu.org/ml/gcc-help/2011-05/msg00220.html and the answer http://gcc.gnu.org/ml/gcc-help/2011-05/msg00221.html

In particular quoting from the answer:

All objects with an init_priority attribute are constructed before any object with no init_priority attribute.

Note it is actually about __attribute__((init_priority)) and not about __attribute__((constructor)) but I believe they both actually use the same code in gcc, respectively in gnu linker. First just corresponds to C++ objects, i.e. calling their constructor/destructor, the latter is about marking specific functions as constructor or destructor.

IMHO, the __attribute__((constructor)) exists mainly because of C, not C++.

mity
  • 2,231
  • 14
  • 19
  • Unfortunately, init_priority causes my code to be called first, while I need it to be called last. This is the same solution as constructor(0), it does not help me. I can't setup _all_ static variables in all modules with init_priority attributes, that's nonsense. – queen3 Jun 22 '12 at 19:39
  • Yes, my post tells you can not use it for this purpose at all, because of the bold text. You would have to assign priority to all the other static objects which is impractical. – mity Jun 22 '12 at 19:41
2

Can you implement a "construct on first use" pattern for this global?

e.g.

Magic& gMagic()
{
    static Magic magic;
    return magic;
}

It will get built after all regular static ctors, but before any regular code needs it.

Rafael Baptista
  • 10,259
  • 4
  • 35
  • 56
  • Yes, this is a good pattern, thanks. Unfortunately there's no single object or function that will be called in the loaded shared library, that I can use or wrap into gMagic() and be sure that it _will_ be used before other objects. – queen3 Jun 28 '12 at 07:45
  • Does your last-initialized object have some external effects? Does it actually need to be created if it's not explicitly used? If not, then you shouldn't worry that it's not created yet. When you need it to be created, it will be :D – j_kubik Jun 30 '12 at 16:32