[Bug c/61395] New: Linker cannot find symbols in object files compiled with recent GCC
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61395 Bug ID: 61395 Summary: Linker cannot find symbols in object files compiled with recent GCC Product: gcc Version: 4.9.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: mimamer at gmail dot com Apologies in advance for any mistakes in posting this bug report. If what I am describing is not a bug in GCC please direct me to a place where I can ask for help on this issue -- thanks! I recently upgraded from GCC 4.3.4 to 4.9.0, which I set up as a cross compiler from i686-pc-cygwin to i686-pc-elf together with static and shared libgcc support. I created a shared libgcc.so version from libgcc.a using 'ld' and specifying --whole-archive (as well as the other usual flags). Now, when I try to link even a very simple test program that emits a symbol defined in a shared library such as libgcc.so the link step fails with GCC/ld complaining that the symbol (e.g., __divdi3) cannot be found. I can verify that the symbol is available in libgcc.so's .symtab (as FUNC LOCAL DEFAULT 12) and specified in main.o's .symtab (as NOTYPE GLOBAL DEFAULT UND), yet when I try to link main.o with -lgcc (or libgcc.so) I get "Undefined reference to `__divdi3'". Upgrading the linker did not have any effect. I can also verify that the linker finds all input files in the right places, so I am completely at lost what is going wrong here, and though I suspect a compiler bug (since this did work for me with GCC 4.3.4) I may easily be wrong. Apologies again!
[Bug c/61395] Linker cannot find symbols in object files compiled with recent GCC
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61395 mimamer at gmail dot com changed: What|Removed |Added Resolution|INVALID |FIXED --- Comment #2 from mimamer at gmail dot com --- Well, since this did work for 4.3.4, what is the proper way to build libgcc.so? No, I cannot specify my own triplet, the target is a custom OS under development.
[Bug c/61395] Linker cannot find symbols in object files compiled with recent GCC
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61395 --- Comment #4 from mimamer at gmail dot com --- I'm sorry to bother you one more time. All symbols are marked as hidden in libgcc.a, true. But they become "local default" when I create a shared libgcc.so from it. Just to help me understand what is going on I tried globalizing the __divdi symbol in my libgcc.so with objcopy, but I still cannot successfully link it. Why? (Thanks again.) (And btw, creating my own t-* files seems like horror.)
[Bug c/61395] Linker cannot find symbols in object files compiled with recent GCC
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61395 mimamer at gmail dot com changed: What|Removed |Added Status|RESOLVED|CLOSED Resolution|FIXED |INVALID --- Comment #5 from mimamer at gmail dot com --- (change status to INVALID, erroneously had it changed before)
[Bug c++/61421] New: Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 Bug ID: 61421 Summary: Invalid -O2 optimization breaks program Product: gcc Version: 4.9.0 Status: UNCONFIRMED Severity: major Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: mimamer at gmail dot com Created attachment 32895 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=32895&action=edit disassembly of faulty binary snippet It seems that C++ carries out an invalid optimization when compiled with -O2 that breaks the following code snippet: _dprintf("p %p, n %p, t %p\n", include_list2.head()->prev, include_list2.head()->next, include_list2.end()); while ( (node = include_list2.dequeue()) != include_list2.end() ) { //asm volatile("":::"memory"); main_list.insert_at( &iterator->main_node, &node->main_node ); iterator = node; } _dprintf("p %p, n %p, t %p\n", include_list2.head()->prev, include_list2.head()->next, include_list2.end()); Output: p 0x007f9e44, n 0x007f9e44, t 0x007f9e44 p 0x007f9e44, n 0x, t 0x007f9e44 Expected output: p 0x007f9e44, n 0x007f9e44, t 0x007f9e44 p 0x007f9e44, n 0x007f9e44, t 0x007f9e44 Explanation: include_list2 implements a simple doubly-linked list, which happens to be empty at the beginning (i.e., the head's previous and next pointers both point to the list's anchor, returned by end()). dequeue() thus should return the anchor, which equals end() (i.e., the while loop should not be entered). So, nothing should have changed after the loop, yet the anchor's next pointer suddenly has become zero. Adding the memory barrier (i.e., uncommenting the line with the asm statement) gives the expected result. Disassambled binary output for the snippet is attached, once in its faulty version and once with the memory barrier. A minimal implementation of list2 is attached as well. All in one file (why can't I submit more than one?).
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #1 from mimamer at gmail dot com --- A minimalistic version that breaks with all -O2 flags set: Starting from an empty main_list: Node *node; //asm volatile("":::"memory"); while ( (node = main_list.dequeue()) != main_list.end() ) _dprintf(""); Uncomment the memory barrier and it works.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #2 from mimamer at gmail dot com --- Turns out the problems arise in different places but only in the list2::dequeue() function: inline T *dequeue() { //asm volatile("":::"memory"); T *head = anchor.next; anchor.next = head->next; head->next->prev = (T *)&anchor; #if 1//(defined(DEBUG) || defined(_DEBUG)) && !defined(NDEBUG) if ( head != (T *)&anchor ) head->prev = head->next = NULL; #endif return head; }; Uncommenting the memory barrier resolves all issues.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #4 from mimamer at gmail dot com --- Indeed, this is alias-related. Two questions: (1) What is a concrete solution for this problem when -fstrict-aliasing is being used? How should I change my code? (Sorry, I am no expert on this.) (2) Why is -fno-strict-aliasing being ignored when placed after -O2, just as I had it all the time in my Makefile?
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #5 from mimamer at gmail dot com --- T is derived from list2::node, and yes, I'm "up"casting from node to T. There is no other way around it in the implementation, and if this causes a problem with aliasing then I don't know what it's good for. Any input appreciated.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #6 from mimamer at gmail dot com --- Btw, C++ doesn't give me any aliasing warnings even with -Wstrict-aliasing=1.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #7 from mimamer at gmail dot com --- Violation of aliasing or not, the problem arises prior to the downcasting from list2::node* to T*: T *head = anchor.next; anchor.next = head->next; head->next->prev = (T *)&anchor; // where did head->next become NULL??? where anchor is defined as struct node { T*next; T*prev; } anchor; I don't see actually why this should be invalid under any (retarded) aliasing rules. If Andrew or any of the other experts here could point out to me how the problem can be solved _without_ fundamentally changing the implementation of list2 (such as specifying anchor as of type T) I would be very grateful. Thanks a LOT in advance! Also, again, why does -fno-strict-aliasing (placed _after_ -O2) not have any effect?
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #8 from mimamer at gmail dot com --- As concerns -fno-strict-aliasing, I have to put it before -O2. Sorry for the mixup.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #9 from mimamer at gmail dot com --- Now that I have read enough about aliasing rules I realize that they are considerably fucked up and that their is no way to efficiently downcast without violating strict aliasing rules. In explanation, you need to copy your data out and back (which takes time), or implement an instance of a derived class in the first place (which consumes memory). Yes, my code is efficiency-critical. Hooray for retarded aliasing rules. (If I don't care about efficiency I could just as well switch to Java, which gives all the safety that one needs.)
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #11 from mimamer at gmail dot com --- In short form, template class list2 { public: struct node { T*next; T*prev; }; nodeanchor; public: /* API */ } struct Obj : list2::node { /* obj-specific elements */ } list2main_list; So, anchor is of type list2::node while Obj is derived from list2::node.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #14 from mimamer at gmail dot com --- Can you explain what you mean by "use type node inside the struct node"? Because I still cannot see an (efficient) way for solving this problem.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #16 from mimamer at gmail dot com --- Ah ok, but that doesn't solve my problem as I will eventually need to cast a node pointer back to T (either at the caller or the callee side). So there _is_ no efficient solution with strict aliasing rules. Which makes it kinda broken, IMO.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #18 from mimamer at gmail dot com --- Ah? I didn't figure that was allowed per strict aliasing rules. But it still doesn't solve one problem: inline T *dequeue() { node *head = anchor.next; anchor.next = head->next; head->next->prev = &anchor; return (T *)head; }; The last typecast is invalid when the list is empty and thus returns the anchor, a special element that so far I checked with equality to list2::end(): inline T* end() const { return (T *)&anchor; } But it is a huge step forward as checking for an empty list in dequeue() is just ok so as to return NULL instead of the anchor.
[Bug c++/61421] Invalid -O2 optimization breaks program
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61421 --- Comment #19 from mimamer at gmail dot com --- One last comment on strict aliasing rules: It is ironic that these rules are supposed to make programs faster, but those developers that really care about speed are prevented from implementing even moderate optimizations (see discussion) because of these rules! Again, the concept of strict aliasing rules is broken.