This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
MIPS (cross) -G 0 libgcc vs. (default -G) stdc++ data problem.
- To: gcc-bugs at gcc dot gnu dot org
- Subject: MIPS (cross) -G 0 libgcc vs. (default -G) stdc++ data problem.
- From: cgd at sibyte dot com (Chris G. Demetriou)
- Date: 28 Oct 2000 00:00:34 -0700
I ran into this this evening. Based on my recently-acquired
understanding of gas (see the binutils list 8-) I believe it's an
issue with the related-to-compiler sources.
Background/configuration:
I ran into this on a mips-elf-like target. For gcc, it uses the same
configuration goop as mips-elf, and i've tweaked the few places which
check the target name that were relevant (e.g. setting attrs on
.reginfo, etc.) to act like mips-elf.
My gcc and binutils sources are based on those in the master source
trees, dated 2000-10-10 00:00 UTC. gcc has pretty much only configury
and "be like elf" patches as described bove. My binutils have some
pretty substantial patches related to MIPS32 and MIPS64 support, but i
verified that I touched none of the code in binutils in the path that
provokes the issue.
I'm using a hacked version of newlib, too, but that's _really_
irrelevant.
The issue:
libgcc is compiled with -G 0 on mips-elf (and therefore in my
configuration), so that the user can link code that doesn't use the GP
(according to the comments). As a result of this, the variable
__terminate_func (a function pointer, 4 bytes) gets put into the data
section, not into small data section(s) which will be kept close to
the GP for use with a gp-relative operation.
libstdc++ is compiled with no -G flag, so the default behaviour is
used, which for the assembler is a value of '8'.
libstdc++ exception.cc contains code which directly accesses the
__terminate_func pointer (loads and stores it), which gets compiled
into assembly code like:
lw $2, __terminate_func
At the end of the file, the compiler seems to rightly output:
.extern __terminate_func, 4
indicating that __terminate_func has a size of 4.
When assembling that code, the assembler notes the size of the
__terminate_func, and therefore thinks -- since its -G value is 8, the
default -- that __terminate_func is small data, and can be accessed
with a GP-relative operation.
When linking a large enough program -- and a trivial
hello-world-from-c++ program seems large enough -- the gp-relative
relocation doesn't fit, and so the linker says so and punts.
My believe is that the fault is in accessing data compiled with -G 0
from code compiled with the default -G setting (if that is non-zero,
as is true in this case).
The closest thing that I can think of to a solution is:
(1) frob libstdc++ terminate so that it calls libgcc.a __terminate
rather than using __terminate_func.
(2) introduce a function to set-new/return-old terminate function into
libgcc2.c's eh bits.
This eliminates non-libgcc access to __terminate_func, and means that
only libgcc's -G 0 code will access that little bit of -G 0 data.
As far as I can tell, the __terminate_func-using code is also present
in libstdc++-v3, so using libstdc++-v3 is no magic bullet. 8-)
Any comments on this? I'd like to get at least a little feedback
before I go and implement it, but if I beat y'all to the punch i'll
just submit the patch. 8-)
I could easily believe that there are other bugs like this running
around, but I don't know what (data) variables are exported from
libgcc.a for (erroneous) use elsewhere...
chris