This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Exception Handling Bug (smashing global registers) -- 19990628 andearlier
- To: EGCS Bugs <egcs-bugs at egcs dot cygnus dot com>
- Subject: Exception Handling Bug (smashing global registers) -- 19990628 andearlier
- From: "Melissa O'Neill" <oneill at cs dot sfu dot ca>
- Date: Tue, 29 Jun 1999 01:46:11 -0700
- cc: EGCS <egcs at egcs dot cygnus dot com>
It seems the code that handles exceptions doesn't take account of global
register assignments a program may have, at least on solaris-sparc
platforms.
The following program shows an example of the problem:
--8<---cut-here---8<---cut-here---8<---cut-here---8<---cut-here---8<---
// foo.cc, compile with: g++ -Wall -o foo -mno-app-regs foo.cc
// or: g++ -Wall -o foo -ffixed-g3 -ffixed-g4 foo.cc
#include <stdexcept>
#include <cstdio>
register int global_g4 asm("g4");
register int global_g3 asm("g3");
void show_globals() {
printf("global_g4 = %x, global_g3 = %x\n", global_g4, global_g4);
}
int main() {
glob_g3 = 0xbadac1d;
glob_g4 = 0xaddc0c0a;
printf("before throw glob_g3 = %x, glob_g4 = %x\n", glob_g3, glob_g4);
try {
throw logic_error("libgcc corrupts registers");
}
catch (logic_error &err) {
printf("after throw glob_g3 = %x, glob_g4 = %x\n", glob_g3, glob_g4);
}
}
---8<---cut-here---8<---cut-here---8<---cut-here---8<---cut-here---8<---
According to the gcc documentation, I should be able to use these
`application registers' if I give gcc the -mno-app-regs option (in the
absence of this option gcc allocates g2-g4 as call-clobbered temporaries),
but watch:
solaris% g++ -o foo -mno-app-regs foo.cc
solaris% foo
before throw glob_g3 = badac1d, glob_g4 = addc0c0a
after throw glob_g3 = 7c, glob_g4 = 4f060
Unfortunately, libgcc gets compiled *without* -mno-app-regs, so any time
a libgcc function is called, it thinks it is free to smash these registers.
Recompiling libgcc.a with -mno-app-regs eliminates the problem:
solaris% g++ -o foo -mno-app-regs foo.cc
solaris% foo
before throw glob_g3 = badac1d, glob_g4 = addc0c0a
after throw glob_g3 = badac1d, glob_g4 = addc0c0a
I realize that compiling libgcc with -mno-app-regs will cause its
functions to run more slowly, but it seems like our only choice is to
compile it that way, or to say goodbye to reliably using -mno-app-regs
or -ffixed.
Presumably, other libraries such as libstdc++ are similarly affected.
(But the user has a little choice when it comes to what other libraries
to use -- they don't have much of a choice about libgcc).
I realize that using things like global registers is nasty and low level,
but for some kinds of multithreaded program, it's a major win so I end
up needing to stoop to such things.
Opinions and fixes welcome,
Melissa.
P.S. If the libraries don't care about preserving the values of `fixed'
registers for things like Unix signal handlers, we could define these
registers as call-saved registers when compiling the libraries. This
seems like the most reasonable compromise position, although my preferred
compromised would be to make one application register default to being
call-saved.