Bug 20966

Summary: binutils break C++ in GCC 2.95.x and GCC-current
Product: Base System Reporter: pfeifer <pfeifer>
Component: gnuAssignee: David E. O'Brien <obrien>
Status: Closed FIXED    
Severity: Affects Only Me CC: pfeifer
Priority: Normal    
Version: 4.1-RELEASE   
Hardware: Any   
OS: Any   

Description pfeifer 2000-08-31 17:30:00 UTC
	[ This is a resend of 20942 which was forwarded to the mailing
	list but then lost by the GNATS machinery. Suggested by sheldonh. ]

	Apparently binutils as of 4.1-RELEASE break static constructors
	in C++ for GCC 2.95.x and GCC-current. Both work fine (w/o FreeBSD
	patches) on FreeBSD 3.x and also GCC 2.95.2 as shipped with
	4.1-RELEASE is fine.

	You'll experience the problem only, if you build GCC by yourself.

	I assume that there is a problem (change) in binutils on 4.1-RELEASE
	that causes this breakage and that has been fixed (also made) in the
	imported version of GCC?

Fix: 

1. Fix (the local copy?) of binutils.
	2. If it is a GCC bug (which I don't believe) that has been fixed in
	   the FreeBSD tree, submit the change back to the GCC maintainers.
How-To-Repeat: 
	Compile and run the following small C++ program with either GCC 2.95.2
	(original GNU version, w/o FreeBSD patches) or GCC-current and you'll
	get a core dump as the static constructor is not invoked.

	GCC as shipped with 4.1-RELEASE is not affected.

	-------- cut --------
	#include <map>
	#include <iostream>

	struct NAMESTABLE
	    {
	    map<int,int> lookup;

	    NAMESTABLE()
	        : lookup()
	        {
	        cout << "constructor" << endl;
	        }

	    void add(const char *s, const int &item)
	        {
	        cout << s << endl;
	        lookup.insert(pair<int,int>(item,0));
	        }
	    };

	NAMESTABLE q;

	int main() {
	    NAMESTABLE p;
	    p.add("auto",1);
	    q.add("static",1);
	}
Comment 1 Sheldon Hearn freebsd_committer freebsd_triage 2000-08-31 17:53:18 UTC
Responsible Changed
From-To: freebsd-bugs->obrien

Over to maintainer.
Comment 2 pfeifer 2000-10-08 19:52:51 UTC
I've been asked for some clarifications (as the original report was a
bit confusing):

Both stock FSF/GCC 2.95.2 and current CVS sources of GCC (both without
any additional FreeBSD-specific modifications) build fine on FreeBSD
4.1-RELEASE.

However, unlike the base FreeBSD 4.1-RELEASE compiler, which is also
labeled GCC 2.95.2, both of these unpatched stock versions of GCC
generate broken C++ binaries.

(Simple C++ code does work, but static constructors, as in the example
in this PR do not work properly.) 

I have not tested any of the versions in our ports collection in any way.

Gerald
Comment 3 kabaev 2000-10-15 16:22:47 UTC
Gerald,

as far as I can tell, the breakage occured because FreeBSD is now using
architecture-independent crtbegin.c file. As a side effect to this change,
crtn.S and crtn.S files are now empty. Consequently, .fini and .init sections in
elf output file never get corresponding _init of _fini label and required
__asm(ret) instruction never gets appended to it.

I am not sure what is the best srategy to use in order to make GCC snapshots to
work out of the box on FreeBSD again. I suggest that FreeBSD just should remove
it's custom _init and _fini functions from crtbegin.c altogether and use code
from GCC stock crtbegin.c file. If I am not mistaken, David O'Brien has this
change on his todo list already.

For the time being, you may want to check versions 1.3 and 1.2 of crti.S and
crtn.o recpectively, compile them and place resulting .o files into your
/usr/local/lib/gcc-lib/i386-portbld-freebsd5.0/2.97 directory (or whatever
directory is correct for the version of gcc you are using). This will at least
will get you going for the time being. If you prefer, I will send you these
object files.
Comment 4 David E. O'Brien freebsd_committer freebsd_triage 2000-10-15 21:36:13 UTC
On Sun, Oct 15, 2000 at 08:30:02AM -0700, Alexander N. Kabaev wrote:
>  as far as I can tell, the breakage occured because FreeBSD is now using
>  architecture-independent crtbegin.c file. As a side effect to this change,
>  crtn.S and crtn.S files are now empty.

I tought GCC (as built from FSF sources) provided all the crt foo it
needed.  I see now, it only provides its own crt{begin,end}.o.

-- 
-- David  (obrien@FreeBSD.org)
Comment 5 peter 2000-10-17 22:46:22 UTC
The problem is that our crt foo is incompatable with g++'s constructor
and thread mechanism.  In order to get g++ working at yahoo, we had
to back out to the old crt{i,n}.o and use gcc's crt{begin,end}.o
so that the frame hooks etc were called in the right places.

See glibc's own crtbegin/end etc for how to do an elf-specific set
of crt files that remain gcc/g++ compatable.

According to my recollection of the original AT&T/USL manuals that I
have (in Australia) that cover ELF, toolchain, linking, abi's, etc, I
still believe our crt{i,n}.o are broken.  We have replaced the extensible
"linker set"-like mechanism that was part of the ELF linking defintion
with a static _init() and _fini() function.  Other systems, notably
g++, depend on the original system working.  Anyway, I will be checking
out the details in about 2 weeks when I get back to .au and look it up.

-Peter
Comment 6 kabaev 2000-10-18 05:33:56 UTC
> The problem is that our crt foo is incompatable with g++'s constructor
> and thread mechanism.  In order to get g++ working at yahoo, we had
> to back out to the old crt{i,n}.o and use gcc's crt{begin,end}.o
> so that the frame hooks etc were called in the right places.

I disagree. Our custom crtbegin.c was and is indeed incompatible with DWARF2
exception unwinding method GCC is using by default, but our crt1.c, crti.S and
crtn.S were working just fine until FreeBSD started to use architecture
independent crtbegin.c implementation. Since non-system GCC versions do not use
FreeBSD crtbegin.c at all, this incompatibility does not prevent them from
working correctly.

> According to my recollection of the original AT&T/USL manuals that I
> have (in Australia) that cover ELF, toolchain, linking, abi's, etc, I
> still believe our crt{i,n}.o are broken.  We have replaced the extensible
> "linker set"-like mechanism that was part of the ELF linking defintion
> with a static _init() and _fini() function. 

All that previous versions of crti.S and crtn.S files were doing is they were
providing function prologue (function name label) and epilogue (ret
instruction) for compiler generated .init and .fini sections. The way
compiler generates .init and .fini sections is indeed similar to linker
sets. Our startup files were working OK with any version of GCC as long as
GCC .init|.fini section with all initialization calls it needs. The new platform
independent implementation does not use these sections anymore and implements
it's own _init and _fini functions instead. That is IMHO wrong not only because
it breaks GCC but also because crtbegin.o will require modification each time
GCC developers add feature which requires non-trivial initialization at startup
time. 

 Presenting .init and .fini sections as functions allows us
to call them from crt1.c right before and after _main. Alternatively, ld.so
dynamic loader could be changed to run contents of these sections at the module
load time but that way we will lose the possibility to run some other code (such
as profiling related initialization) before constructors are run. Changing
dynamic loader is not feasible at this point anyway because it will introduce
severe backwards binary compatibility problems without providing any significant
advantage.
Comment 7 David E. O'Brien freebsd_committer freebsd_triage 2000-11-05 19:41:14 UTC
State Changed
From-To: open->closed

done