This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libstdc++/5625] [mips] exception unwinding creates invalid pointer on mips
- From: "wilson at gcc dot gnu dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 5 Feb 2004 02:39:45 -0000
- Subject: [Bug libstdc++/5625] [mips] exception unwinding creates invalid pointer on mips
- References: <20020207120601.5625.emaste@sandvine.com>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Additional Comments From wilson at gcc dot gnu dot org 2004-02-05 02:39 -------
This bug still exists on the gcc-3.4 branch, and presumably also mainline. It
can be reproduced by configuring for an sb1-elf target which defaults to the O64
ABI, linking with the idt.ld (or idt64.ld) linker script, and running the g++
testsuite on the simulator.
I don't see any evidence that anything was done to fix this problem. It was
closed because test results from cgd did not show the bug, but this test was
flawed. The problem shows up only if you have 64-bit code generation, an ILP32
type system, pointers with the high bit set, and pointers that do not extend
unsigned. The test that cgd did used the mipsisa64 target, which uses an LP64
type system by default and thus does not show the bug. Also, cgd tested
mipsisa64 with the -mips32 flag which generates 32-bit code, and thus does not
show the bug. In order to reproduce the bug, you have to use the O64 or N32
ABIs, or use the -mlong32 option with one of the true 64-bit ABIs. The problem
is easiest to see if you use an embedded target that defaults to the O64 ABI.
I tried to fix the problem in the personality routine by replacing the
_Unwind_Ptr cast with an _Unwind_Word cast. The cast is there only to suppress
a compiler warning about a cast from pointer to integer. Unfortunately, this
gives us a compiler warning about casting from a pointer to an integer of a
different size which is unfortunate. Also, this introduces a new problem, in
that targets which need unsigned extension for pointers are now broken. The
convert() function always does a signed extension when converting pointers to a
larger sized int. This is probably a bug, and is documented as such. What we
really need here is machine dependent conversion based on the value of the
POINTER_EXTEND_UNSIGNED macro.
The only place in the compiler that does conversions based on
POINTER_EXTEND_UNSIGNED is the convert_memory_address function which operates on
RTL. It does machine dependent conversions from ptr_mode to Pmode and vice
versa. So a possible solution here is to add a builtin function that calls
convert_memory_address, in order to get the proper pointer extension. This is
fairly easy to do, but it requires that the target define Pmode to the word
size, which strangely the MIPS port does not do. The MIPS port is the only
64-bit port that I am aware of which sets Pmode to SImode when generating ILP32
code. This is arguably a bug in the mips port.
So now we need two patches, one which adds the __builtin_extend_pointer
function, and modifies libsupc++ to use it, and one which changes the MIPS
backend to use a DImode Pmode when generating 64-bit code. The first patch is
easy. The second one seems to be hard. I tried making the obvious changes, and
ended up with problems with mixed-modes in address arithmetic. At the moment, I
am not sure if I missed something, or if there are latent bugs in the MIPS
backend. I ended up writing a hackish patch that worked well enough to compile
libstdc++ and newlib, which I used as a proof of concept patch to test my ideas.
The patch is pretty ugly though, in a number of places, I had to give up and
use GET_MODE instead of hard wiring in Pmode and/or ptr_mode as the code used to
do. I will attach these patches to the PR.
I did my experiments using the g++.old-deja/g++.eh/flow1.C testcase, as that
seemed to be one of the simplest EH testcases that was failing.
I applied my hacked up DImode Pmode patch, built a toolchain, and compiled the
flow1.C test. The personality routine still stores a zero-extended pointer when
it calls _Unwind_SetGR. However, the testcase now works on the simulator. I
noticed a couple of reasons for this. Because Pmode is now DImode, and we have
PROMOTE_MODES defined, we are now generating daddiu where we used to generate
addiu, so there is no longer a chance of tripping unpredictable behaviour where
we did before. Also, we have PROMOTE_PROTOTYPES defined, which causes the
pointer to be sign-extended in main right before the __cxa_begin_catch call, so
there is no longer a problem there either.
I then applied by __builtin_extend_pointer patch, and now I get the desired
signed pointer extension in the personality routine before the _Unwind_SetGR
call. However, based on the results of the above, I think that this patch is
unnecessary.
Since I can't think of anyway to solve the problem without changing Pmode to
DImode, and this change alone makes the testcase work, I don't see any real need
for any libsupc++ change in order to fix this problem. I think the mips backend
change is enough. Converting the MIPS backend looks like it may be a pain
though. I ran into problems when I tried a naive approach. Also, this will
require testing on a number of different systems, some of which I may not have
access to. I don't have any immediate plans to work on this, but may need to co
me back to it later.
--
What |Removed |Added
----------------------------------------------------------------------------
CC| |wilson at specifixinc dot
| |com
Status|RESOLVED |REOPENED
Resolution|FIXED |
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=5625