Summary: | #include <iostream> implies global constructor. | ||
---|---|---|---|
Product: | gcc | Reporter: | Jan Hubicka <hubicka> |
Component: | libstdc++ | Assignee: | Patrick Palka <ppalka> |
Status: | ASSIGNED --- | ||
Severity: | enhancement | CC: | ccoutant, fw, gcc-bugs, jason, noloader, paolo.carlini, ppalka, redi, rguenth, sjames, webrown.cpp |
Priority: | P3 | ||
Version: | 4.6.0 | ||
Target Milestone: | --- | ||
See Also: |
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98108 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94810 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62200 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108969 |
||
Host: | Target: | ||
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | 2022-11-03 00:00:00 |
Description
Jan Hubicka
2010-07-15 15:51:43 UTC
Subject: Re: New: #include <iostream.h> imply global constructor. This is expected and iirc required by the c++ standard too. On Jul 15, 2010, at 8:51 AM, "hubicka at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org > wrote: > Noticed while reading > http://comments.gmane.org/gmane.comp.web.chromium.devel/16789 > > evans:/abuild/jh/trunk-install/bin/:[0]# more g.C > #include <iostream> > evans:/abuild/jh/trunk-install/bin/:[0]# ./g++ -O2 g.C -S > evans:/abuild/jh/trunk-install/bin/:[0]# more g.s > .file "g.C" > .text > .p2align 4,,15 > .type _GLOBAL__I_g.C, @function > _GLOBAL__I_g.C: > .LFB969: > .cfi_startproc > subq $8, %rsp > .cfi_def_cfa_offset 16 > movl $_ZStL8__ioinit, %edi > call _ZNSt8ios_base4InitC1Ev > movl $__dso_handle, %edx > movl $_ZStL8__ioinit, %esi > movl $_ZNSt8ios_base4InitD1Ev, %edi > addq $8, %rsp > .cfi_def_cfa_offset 8 > jmp __cxa_atexit > .cfi_endproc > .LFE969: > > > -- > Summary: #include <iostream.h> imply global constructor. > Product: gcc > Version: 4.6.0 > Status: UNCONFIRMED > Severity: normal > Priority: P3 > Component: libstdc++ > AssignedTo: unassigned at gcc dot gnu dot org > ReportedBy: hubicka at gcc dot gnu dot org > > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44952 > Why's this not in libstdc++.so .init? ... and are we required to emit the constructor even if we know var is not used? (In reply to comment #2) > Why's this not in libstdc++.so .init? because this will not work if libstdc++ is a static library. Take: #include <iostream> namespace { struct g { g(){ std::cout << "t"; } }; g one; } --- CUT --- The C++ standard says order of initializers between TUs is unspecified (though the order inside TUs is specified as being the first one will run first). So with a static version, the above will be included first and that will cause std::cout to be used without being initialized. >... and are we required to emit the constructor even if we know var is not used? It is hard to do that in Standard C++ really or imposable. This is why you should only include <iostream> if you want actually want std::cin, std::cout or std::cerr (or the wide character equivalents.) Otherwise you should only include one or more of <iosfwd>, <istream> and <ostream>, as needed. (In reply to comment #3) > ... and are we required to emit the constructor even if we know var is not > used? 27.4 [iostream.objects] paragraph 2 The results of including <iostream> in a translation unit shall be as if <iostream> defined an instance of ios_base::Init with static storage duration. Similarly, the entire program shall behave as if there were at least one instance of ios_base::Init with static storage duration. and please ... it's 2010, <iostream> not <iostream.h> ;-) Hehe, I am really not C++ guy even in 2010, but I have impression that people are including iostream without really thinking about consequences here. Well, so what we can do about the startup times then? I will teach ipa-profile to propagate info if function is only called from constructor and will put them into separate section. This will save the random access at file startup. But we ought to be able to do better. (In reply to comment #7) > Hehe, I am really not C++ guy even in 2010, but I have impression that people > are including iostream without really thinking about consequences here. Yes, and in many cases that's the simplest thing to do, but it has a cost. > Well, so what we can do about the startup times then? I would do nothing. If people care about startup times they should not include facilities they don't use. Let's say we remove that horrible .h from the Summary, since, to be fair, didn't exist in g.C in the first place ;) That said, I agree with Jon, by and large, with the following minor additional observations: 1- I'm pretty sure the library is correct, but we should double check whether other established and new implementations of the C++ runtime are trying to do something special, performance-wise - low priority I'm afraid; 2- As library maintainers we certainly welcome any improvement to the optimizers improving the code GCC generates for these constructors, because certainly many user applications could benefit, not just because the library would; -3 While we are at it, I think we should make sure not regressing on libstdc++/39796, or even making progress at once. Ideas? (I didn't really manage to study it in any detail) The C++ standard actually requires this as noted in comment #5. Perhaps with LTO we could special case this (perhaps using some special attribute) and only construct/destruct the first of these static ios_base::Init __ioinit; vars and optimize all the others away together with their construction/destruction, assuming they aren't otherwise referenced. The same idea vaguely occurred to me... So reopening for this enhancement... Another alternative would be some .init.first array or something similar which would contain pointers to functions to be run as early constructors and linker would remove duplicates in it and put it at the beginning of .init_array section. Well, it might be easy to modify libstdc++ implementation so the static constructor compiles into single function call. Then we can teach GCC to optimize constructor containing only a call into entry in ctors table. Then we will get a lot of duplicate calls, but all at one place and we won't have the locality problem at startup. (In reply to comment #13) > So reopening for this enhancement... > > Another alternative would be some .init.first array or something similar which > would contain pointers to functions to be run as early constructors and linker > would remove duplicates in it and put it at the beginning of .init_array > section. For ELF targets, this is what DT_PREINIT_ARRAY is for. http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#init_fini -cary (In reply to Jonathan Wakely from comment #5) > 27.4 [iostream.objects] paragraph 2 > The results of including <iostream> in a translation unit shall be as if > <iostream> defined an instance of ios_base::Init with static storage > duration. Similarly, the entire program shall behave as if there were at > least one instance of ios_base::Init with static storage duration. N.B. https://wg21.link/lwg2765 removed that last sentence, so we are no longer required to run the stream initialization in all programs. Only in programs which include <iostream> in at least one TU. The __ioinit hack won't work with the move to modules, and it doesn't seem necessary either: For programs that use libstdc++ as a shared library, it should be fine for the initialization to run in the library, before the main program is loaded. For programs that use a static libstdc++, attribute init_priority should be sufficient to make sure it runs first. The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:4e4e3ffd10f53ef71696bc728ab40258751a2df4 commit r13-3707-g4e4e3ffd10f53ef71696bc728ab40258751a2df4 Author: Patrick Palka <ppalka@redhat.com> Date: Sun Nov 6 11:16:00 2022 -0500 libstdc++: Move stream initialization into compiled library [PR44952] This patch moves the static object for constructing the standard streams out from <iostream> and into the compiled library on systems that support init priorities. This'll mean <iostream> no longer introduces a separate global constructor in each TU that includes it. We can do this only if the init_priority attribute is supported because we need a way to ensure the stream initialization runs first before any user global initializer, particularly when linking with a static libstdc++.a. PR libstdc++/44952 PR libstdc++/39796 PR libstdc++/98108 libstdc++-v3/ChangeLog: * include/std/iostream (__ioinit): No longer define here if the init_priority attribute is usable. * src/c++98/ios_init.cc (__ioinit): Define here instead if init_priority is usable, via ... * src/c++98/ios_base_init.h: ... this new file. |