Exceptions workaround for older systems that don't USE_COLLECT2
Melissa O'Neill
oneill@cs.sfu.ca
Fri Sep 4 22:36:00 GMT 1998
Received wisdom states that you're on a system that doesn't need
to ``USE_COLLECT2'', you should make sure you're running a recent
version of GNU ld if you want exception support to work (at least
if it's using __throw for exceptions).
However, under NEXTSTEP 3.3 one can't install a recent GNU ld,
because GNU ld doesn't support NEXTSTEP's object format. But,
because NEXTSTEP's ld is smart enough to grok constructors and
destructors, EGCS 1.1 (and every earlier release) isn't set to
``USE_COLLECT2''. Net result: while static constructors and
destructors work fine, exceptions don't.
The enclosed Perl script (which could easily be rewritten as a
shell script) creates a C++ file for a set of object files, which
when linked with those object files initializes the necessary data
structures (i.e., the frame info table) for exception handling to
work.
Typical use:
unix% g++ -c foo.cc
unix% g++ -c bar.cc
unix% exnpatch foo.o bar.o > foobar-exnpatch.cc
unix% g++ -c foobar-exnpatch.cc
unix% g++ -o foobar foo.o bar.o foobar-exnpatch.o
The script is based on the C code collect2 would emit if ``USE_COLLECT2''
were defined. It has the known limitation that exceptions in static
constructors or destructors may not be handled correctly because
registering/deregistering the frame info table is handled by the
same mechanism that handles static constructors, and which
(purported) constructor/destructor executes first is not defined.
Enjoy.
Melissa.
P.S. Probably if anyone wanted to distribute something like this,
they'd want to rewrite it as a shell script, it's a pretty trivial
piece of code after all, but I've assigned copyright to the FSF,
just in case (and anyway more of the code is FSF code from collect2
than mine).
Enc.
#!/usr/local/bin/perl -w
#
# exnpatch, a quick fix for exception handling when you can't install a
# recent version of GNU ld.
# Copyright (C) 1998 Free Software Foundation, Inc.
# Written by Melissa O'Neill (oneill@cs.sfu.ca), with code taken from
# GNU CC's collect2.c, which is authored by Chris Smith (csmith@convex.com),
# Michael Meissner (meissner@cygnus.com), Per Bothner (bothner@cygnus.com),
# and John Gilmore (gnu@cygnus.com).
use strict;
require 5.005;
# ^--- maybe not, but hey...
my $tempobj = "/tmp/exnpatch-$$";
my @symbols = `g++ -o $tempobj @ARGV && nm $tempobj && rm $tempobj | fgrep GLOBAL`;
my @frames = grep { s/^[\da-fA-F]+ [DT] (__GLOBAL_\$F\$)/$1/ } @symbols;
foreach (@frames) {
s/\n$//s;
}
print <<'--END----';
#ifdef __cplusplus
extern "C" {
#endif
typedef void entry_pt();
--END----
my $varno = 0;
foreach my $frame (@frames) {
++$varno;
print "extern void *x$varno __asm__ (\"", $frame, "\");\n";
}
print "static void *frame_table[] = {\n";
foreach my $var (1 .. $varno) {
print " &x$var,\n";
}
print <<'--END----';
0
};
struct object {
void *pc_begin;
void *pc_end;
void *fde_begin;
void *fde_array;
__SIZE_TYPE__ count;
struct object *next;
};
extern void __register_frame_info_table (void *, struct object *);
extern void *__deregister_frame_info (void *);
void reg_frame () {
static struct object ob;
__register_frame_info_table (frame_table, &ob);
}
void dereg_frame () {
__deregister_frame_info (frame_table);
}
entry_pt * __CTOR_LIST__[] = {
(entry_pt *) 1,
reg_frame,
0
};
entry_pt * __DTOR_LIST__[] = {
(entry_pt *) 1,
dereg_frame,
0
};
asm(".constructor");
asm(".align 1");
asm(".long _reg_frame");
asm(".destructor");
asm(".align 1");
asm(".long _dereg_frame");
asm(".reference .constructors_used");
asm(".text");
#ifdef __cplusplus
}
#endif
--END----
More information about the Gcc
mailing list