This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

MIPS (cross) -G 0 libgcc vs. (default -G) stdc++ data problem.


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]