This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
vtrelocs: large/modular C++ app speedup ...
- From: Michael Meeks <michael dot meeks at novell dot com>
- To: binutils at sources dot redhat dot com, libc-alpha at sources dot redhat dot com, gcc at gcc dot gnu dot org
- Date: Wed, 02 Apr 2008 12:29:28 +0100
- Subject: vtrelocs: large/modular C++ app speedup ...
- Reply-to: michael dot meeks at novell dot com
Hi guys,
I spent a little time recently researching ways to reduce the number of
unique named relocations that must be processed at dlopen time for large
C++ libraries[1]. Apologies for spamming all 3 lists like this, but it
touches all 3 projects.
Since almost all function relocations of this type are inside vtables,
I implemented a new way of relocating vtables. This is a new
'.suse.vtrelocs' section.
As we inherit a class across a shared library boundary we construct new
vtables that are often extremely similar to their parents. However -
this similarity is not exposed - instead we fill the new vtable with
many unique named relocations, one per method. This generates lots
of .rel entries, and emits lots of external symbols; worse these symbols
tend to be duplicated across ~all libraries deriving from the base
class.
Instead a vtreloc sections contains (a sorted):
struct {
void **src, **dest;
int copy_slot_bitmask;
} vtreloc_entries[] = { ... }
The run-time cost of processing these is insignificant in comparison to
the cost of processing the remaining relocations, giving a pleasant
speed win.
A brief slide-deck with the results of my research is here:
http://www.gnome.org/~michael/vtrelocs-gcc.pdf
and has a comparison against the current state of the art wrt. reducing
relocations: -Bsymbolic-functions [ in itself a substantial
optimisation ].
The 3 prototype patches for discussion are attached. There are a number
of trivial hacks in there (of course) - eg. environment variables to
turn the feature on, leaving an empty .vtrelocs section in object files
etc.
The more interesting problems are:
* glibc - the memory protection semantics need adjusting - since
we need to fixup relocations in 'init' order: shouldn't be
impossibly hard to fix but I just turn off protection ;-)
+ subsequent dlopens can (I think) avoid touching
already relocated libraries they don't own avoiding
this sort of problem.
* gcc - the code to generate the vtreloc sections is <cough>
written for comfort not speed. This is a fall-back from having
initially tried to integrate the work into
build_vtbl_initializer & friends with some success, but rather
a tangling of the code.
* vtreloc section design - the section should be readonly, and
prolly refer by offset to .bss relocations that can be re-used
for implementing indirect calls via. parent vtable to virtual
functions. That should save relocs, but make each entry
slightly larger.
Of course, apart from the run-time speed wins, some of the nicest
potential size wins come from breaking the ABI[2] & depending on the
vtrelocs to fixup vtables: eg. hiding all thunks (implemented), or
potentially hiding all virtual function symbols & invoking them via
their parent vtable (not implemented).
Wrt. testing, I can build & run an OO.o built with this - clearly not a
unit-test ;-) but perhaps helpful.
Feedback much appreciated,
Thanks,
Michael.
[1] - specifically OpenOffice.org ;-)
[2] - which while bad, can be done in isolated islands like OO.o.
--
michael.meeks@novell.com <><, Pseudo Engineer, itinerant idiot
diff -u -r -x '*~' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-binutils-2.17.50/bfd/elf.c binutils-2.17.50/bfd/elf.c
--- pristine-binutils-2.17.50/bfd/elf.c 2008-01-09 16:45:22.000000000 +0000
+++ binutils-2.17.50/bfd/elf.c 2008-01-23 16:48:45.000000000 +0000
@@ -1240,6 +1240,7 @@
case DT_USED: name = "USED"; break;
case DT_FILTER: name = "FILTER"; stringp = TRUE; break;
case DT_GNU_HASH: name = "GNU_HASH"; break;
+ case DT_SUSE_VTRELOC: name = "SUSE_VTRELOC"; break;
}
fprintf (f, " %-11s ", name);
diff -u -r -x '*~' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-binutils-2.17.50/bfd/elflink.c binutils-2.17.50/bfd/elflink.c
--- pristine-binutils-2.17.50/bfd/elflink.c 2008-01-09 16:45:22.000000000 +0000
+++ binutils-2.17.50/bfd/elflink.c 2008-01-23 16:50:07.000000000 +0000
@@ -5652,6 +5652,13 @@
return FALSE;
}
+ s = bfd_get_section_by_name (output_bfd, ".suse.vtrelocs");
+ if (s != NULL)
+ {
+ if (!_bfd_elf_add_dynamic_entry (info, DT_SUSE_VTRELOC, 0))
+ return FALSE;
+ }
+
dynstr = bfd_get_section_by_name (dynobj, ".dynstr");
/* If .dynstr is excluded from the link, we don't want any of
these tags. Strictly, we should be checking each section
@@ -10869,6 +10876,10 @@
case DT_VERNEED:
name = ".gnu.version_r";
goto get_vma;
+ case DT_SUSE_VTRELOC:
+ name = ".suse.vtrelocs";
+ o = bfd_get_section_by_name (abfd, name);
+ goto get_vma;
case DT_VERSYM:
name = ".gnu.version";
get_vma:
diff -u -r -x '*~' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-binutils-2.17.50/include/elf/common.h binutils-2.17.50/include/elf/common.h
--- pristine-binutils-2.17.50/include/elf/common.h 2008-01-09 16:45:22.000000000 +0000
+++ binutils-2.17.50/include/elf/common.h 2008-01-23 16:40:38.000000000 +0000
@@ -624,6 +624,13 @@
#define DT_USED 0x7ffffffe
#define DT_FILTER 0x7fffffff
+/* SUSE specific pieces - at a random OS specific address, after
+ previous 2 (direct/hashvals) development sections */
+#define DT_SUSE_LO (0x6cbdd030 + 2)
+#define DT_SUSE_VTRELOC DT_SUSE_LO
+#define DT_SUSE_HI 0x6cbdd040
+#define DT_SUSE_TAGIDX(tag) (tag - DT_SUSE_LO)
+#define DT_SUSENUM 1
/* Values used in DT_FEATURE .dynamic entry. */
#define DTF_1_PARINIT 0x00000001
diff -u -r -x '*~' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-binutils-2.17.50/ld/scripttempl/elf.sc binutils-2.17.50/ld/scripttempl/elf.sc
--- pristine-binutils-2.17.50/ld/scripttempl/elf.sc 2008-01-09 16:45:22.000000000 +0000
+++ binutils-2.17.50/ld/scripttempl/elf.sc 2008-01-23 16:48:46.000000000 +0000
@@ -285,6 +285,7 @@
eval $COMBRELOCCAT <<EOF
.rel.init ${RELOCATING-0} : { *(.rel.init) }
.rela.init ${RELOCATING-0} : { *(.rela.init) }
+ .rel.suse.vtrelocs ${RELOCATING-0} : { *(.rel.suse.vtrelocs) }
.rel.text ${RELOCATING-0} : { *(.rel.text${RELOCATING+ .rel.text.* .rel.gnu.linkonce.t.*}) }
.rela.text ${RELOCATING-0} : { *(.rela.text${RELOCATING+ .rela.text.* .rela.gnu.linkonce.t.*}) }
.rel.fini ${RELOCATING-0} : { *(.rel.fini) }
@@ -410,6 +411,13 @@
${SMALL_DATA_DTOR-${RELOCATING+${DTOR}}}
.jcr ${RELOCATING-0} : { KEEP (*(.jcr)) }
+ /* Virtual table copy relocation tables */
+ .suse.vtrelocs :
+ {
+ KEEP (*(SORT(.vtrelocs.*)))
+ QUAD(0)
+ }
+
${RELOCATING+${DATARELRO}}
${OTHER_RELRO_SECTIONS}
${TEXT_DYNAMIC-${DYNAMIC}}
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-gcc-4.2.1-simple/gcc/collect2.c gcc-4.2.1-simple/gcc/collect2.c
--- pristine-gcc-4.2.1-simple/gcc/collect2.c 2006-12-11 12:18:13.000000000 +0000
+++ gcc-4.2.1-simple/gcc/collect2.c 2008-01-21 19:50:44.000000000 +0000
@@ -175,7 +175,7 @@
static int aixrtl_flag; /* true if -brtl */
#endif
-int debug; /* true if -debug */
+int debug = 1; /* true if -debug */
static int shared_obj; /* true if -shared */
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-gcc-4.2.1-simple/gcc/cp/class.c gcc-4.2.1-simple/gcc/cp/class.c
--- pristine-gcc-4.2.1-simple/gcc/cp/class.c 2007-07-05 10:02:39.000000000 +0100
+++ gcc-4.2.1-simple/gcc/cp/class.c 2008-01-31 12:09:33.000000000 +0000
@@ -181,8 +181,7 @@
static tree end_of_class (tree, int);
static bool layout_empty_base (tree, tree, splay_tree);
static void accumulate_vtbl_inits (tree, tree, tree, tree, tree);
-static tree dfs_accumulate_vtbl_inits (tree, tree, tree, tree,
- tree);
+static tree dfs_accumulate_vtbl_inits (tree, tree, tree, tree, tree);
static void build_rtti_vtbl_entries (tree, vtbl_init_data *);
static void build_vcall_and_vbase_vtbl_entries (tree, vtbl_init_data *);
static void clone_constructors_and_destructors (tree);
@@ -6355,6 +6354,58 @@
return decl;
}
+/* Returns the VAR_DECL for the vtable copy relocation entries associated
+ with BINFO. */
+
+static tree
+get_vtreloc_decl (tree binfo, tree t, tree inits)
+{
+ tree name, d;
+
+ name = mangle_vtreloc_for_type (binfo, t);
+ d = IDENTIFIER_GLOBAL_VALUE (name);
+
+ if (!d)
+ {
+ int nslots = list_length (inits);
+ tree atype = build_cplus_array_type (vtbl_slot_copy_type_node,
+ build_index_type (size_int (nslots - 1)));
+ layout_type (atype);
+ TYPE_ALIGN (atype) = BITS_PER_UNIT * 4;
+
+ d = build_lang_decl (VAR_DECL, name, atype);
+ DECL_ALIGN(d) = 1;
+ DECL_USER_ALIGN(d) = 1;
+ DECL_SECTION_NAME(d) = mangle_vtreloc_section_for_type (binfo, t);
+ SET_DECL_ASSEMBLER_NAME (d, name);
+ /* Remember the type it is for. */
+ TREE_TYPE (name) = t;
+ DECL_ARTIFICIAL (d) = 1;
+ DECL_IGNORED_P (d) = 1;
+ TREE_READONLY (d) = 1;
+ TREE_STATIC (d) = 1;
+ TREE_PUBLIC (d) = 0;
+ DECL_COMDAT (d) = 1;
+ /* Mark the variable as undefined -- but remember that we can
+ define it later if we need to do so. */
+ DECL_EXTERNAL (d) = 0;
+ DECL_NOT_REALLY_EXTERN (d) = 1;
+ set_linkage_according_to_type (t, d);
+ pushdecl_top_level_and_finish (d, NULL_TREE);
+
+ /* TESTME: imported from decl2.c ... */
+ {
+ tree ctor;
+ import_export_decl (d);
+ comdat_linkage (d);
+ DECL_COMDAT (d) = 1;
+ ctor = build_constructor_from_list (TREE_TYPE (d), inits);
+ initialize_artificial_var (d, ctor);
+ }
+ }
+
+ return d;
+}
/* Returns the binfo for the primary base of BINFO. If the resulting
BINFO is a virtual base, and it is inherited elsewhere in the
@@ -6438,7 +6489,7 @@
if (indented)
fprintf (stream, "\n");
- if (!(flags & TDF_SLIM))
+ if (1) /* !(flags & TDF_SLIM)) */
{
int indented = 0;
@@ -6637,12 +6688,74 @@
dump_thunk (stderr, 0, fn);
}
+static tree
+build_addr_offset (tree decl, int offset)
+{
+ tree index, addr;
+
+ index = build_int_cst (NULL_TREE, offset);
+ addr = build1 (ADDR_EXPR, ptr_type_node, build_array_ref (decl, index));
+
+ return addr;
+}
+
+static tree
+get_vtbl_decl_for (tree binfo, tree t)
+{
+ tree decl, name;
+ if (t && BINFO_TYPE (binfo) != t) /* test: construction vtable */
+ {
+ name = mangle_ctor_vtbl_for_type (t, binfo);
+ decl = IDENTIFIER_GLOBAL_VALUE (name);
+ }
+ else
+ decl = get_vtbl_decl_for_binfo (binfo);
+
+ return decl;
+}
+
+/* Ideal .rodata output format: */
+/* dest_symbol, |dest_offset|src_bitmap_blocks, src_symbol, <bitmap> */
+/* Pragmatic 1st cut output format: */
+/* dest_addr, src_addr, <bitmap> */
+static tree
+build_vtable_copy_slot (tree dest_binfo, tree t, int dest_offset,
+ tree src_binfo, int src_offset,
+ int bitmap, tree chain)
+{
+ tree src_decl, dest_decl;
+ tree elem = NULL_TREE, init;
+
+ /* Either a padding entry or nothing to do */
+ if (!dest_binfo || !bitmap)
+ return chain;
+
+ /* fprintf (stderr, "Copy %s + %d => ",
+ type_as_string (src_binfo, TFF_PLAIN_IDENTIFIER),
+ src_offset);
+ fprintf (stderr, " %s + %d mask 0x%x\n",
+ type_as_string (dest_binfo, TFF_PLAIN_IDENTIFIER),
+ dest_offset, bitmap); */
+
+ elem = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, bitmap), elem);
+
+ dest_decl = get_vtbl_decl_for (dest_binfo, t);
+ elem = tree_cons (NULL_TREE, build_addr_offset (dest_decl, dest_offset), elem);
+
+ src_decl = get_vtable_decl (BINFO_TYPE (src_binfo), 1);
+ elem = tree_cons (NULL_TREE, build_addr_offset (src_decl, src_offset), elem);
+
+ init = build_constructor_from_list (vtbl_slot_copy_type_node, elem);
+
+ return tree_cons (NULL_TREE, init, chain);
+}
+
/* Virtual function table initialization. */
/* Create all the necessary vtables for T and its base classes. */
-static void
-finish_vtbls (tree t)
+static tree
+vtbl_get_inits (tree t)
{
tree list;
tree vbase;
@@ -6662,8 +6775,442 @@
accumulate_vtbl_inits (vbase, vbase, TYPE_BINFO (t), t, list);
}
+ return TREE_VALUE (list);
+}
+
+/* List of un-altered vtable inits */
+/*
+ * list of: purpose - type
+ * value - [constructor]
+ */
+tree vtable_copy_types;
+
+/* FIXME: rather a lame search */
+static VEC(constructor_elt,gc) *
+get_vtinit_for_binfo (tree binfo, tree t, int list_only)
+{
+ tree k;
+ for (k = vtable_copy_types; k; k = TREE_CHAIN(k))
+ {
+ if (TREE_PURPOSE(k) == binfo)
+ return CONSTRUCTOR_ELTS (TREE_VALUE(k));
+ }
+ if (list_only)
+ return NULL;
+
+ /* Index ... in the constructor ! ;-) */
+
+ k = get_vtbl_decl_for (binfo, t);
+ if (k)
+ return CONSTRUCTOR_ELTS (DECL_INITIAL (k));
+ else
+ return NULL;
+}
+
+static void
+set_vtinit_for_binfo (tree binfo, tree t, VEC(constructor_elt,gc) *vtinits)
+{
+ tree constr = build_constructor (/* binfo */NULL_TREE, vtinits);
+ vtable_copy_types = tree_cons (binfo, constr, vtable_copy_types);
+}
+
+static void
+debug_vtable (tree binfo, tree t)
+{
+ tree value;
+ unsigned HOST_WIDE_INT ix;
+ VEC(constructor_elt,gc) *vtable;
+
+ if (t != NULL && BINFO_TYPE(t) != binfo)
+ {
+ fprintf (stderr, "Constr VTable for %s-in-",
+ type_as_string (BINFO_TYPE (binfo), TFF_PLAIN_IDENTIFIER));
+ fprintf (stderr, "%s\n",
+ type_as_string (t, TFF_PLAIN_IDENTIFIER));
+ }
+ else
+ {
+ fprintf (stderr, "VTable for %s\n",
+ type_as_string (BINFO_TYPE (binfo), TFF_PLAIN_IDENTIFIER));
+ }
+
+ vtable = get_vtinit_for_binfo (binfo, t, 0);
+ if (!vtable)
+ {
+ fprintf (stderr, "<none>\n");
+ return;
+ }
+
+ FOR_EACH_CONSTRUCTOR_VALUE (vtable, ix, value)
+ {
+ fprintf (stderr, "\t%-4ld %s\n", (long)ix,
+ expr_as_string (value, TFF_PLAIN_IDENTIFIER));
+ }
+}
+
+/* to track a segment of vtable initializer */
+typedef struct vt_fragment_d GTY(()) {
+ tree binfo;
+
+ /* ptr into the vec decl */
+ unsigned int offset;
+ unsigned int size;
+ VEC(constructor_elt,gc) *vec;
+} vt_fragment;
+
+typedef struct vt_copy_record_d GTY(()) {
+ vt_fragment *src;
+ vt_fragment *dest;
+ unsigned int bitmap;
+ unsigned int offset;
+} vt_copy_record;
+
+DEF_VEC_O(vt_fragment);
+DEF_VEC_O(vt_copy_record);
+DEF_VEC_ALLOC_O(vt_fragment, heap);
+DEF_VEC_ALLOC_O(vt_copy_record, heap);
+
+static void
+vtdecompose_frags (tree binfo, tree t, VEC(vt_fragment,heap) **frags)
+{
+ unsigned int seek_fn = 1, i;
+ vt_fragment *frag = NULL;
+ VEC(constructor_elt,gc) *vtable;
+
+ vtable = get_vtinit_for_binfo (binfo, t, 0);
+ if (!vtable)
+ return;
+
+ for (i = 0; i < VEC_length(constructor_elt,vtable); i++)
+ {
+ tree fn = VEC_index (constructor_elt, vtable, i)->value;
+ int is_fn = TREE_CODE (fn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL;
+
+ if (is_fn && seek_fn)
+ {
+ frag = VEC_safe_push (vt_fragment, heap, *frags, NULL);
+ frag->binfo = binfo;
+ frag->offset = i;
+ frag->size = VEC_length (constructor_elt, vtable) - i;
+ frag->vec = vtable;
+ seek_fn = 0;
+ }
+ if (!is_fn && !seek_fn)
+ {
+ frag->size = i - frag->offset;
+ seek_fn = 1;
+ }
+ }
+}
+
+static void
+debug_fragments (VEC(vt_fragment,heap) *frags)
+{
+ unsigned int i;
+ for (i = 0; i < VEC_length(vt_fragment,frags); i++)
+ {
+ vt_fragment *frag = VEC_index (vt_fragment, frags, i);
+ fprintf (stderr, "fragment %d: '%s' offset %d, size %d\n",
+ i, type_as_string (BINFO_TYPE (frag->binfo), TFF_PLAIN_IDENTIFIER),
+ frag->offset, frag->size);
+ }
+}
+
+static void
+push_vtfrag (VEC(vt_copy_record,heap) **vt_copies,
+ vt_fragment *src, vt_fragment *dest,
+ unsigned int bitmap, unsigned int offset)
+{
+ vt_copy_record *rec;
+
+ /* FIXME: we need to be able to compare these */
+ /* that is not easy, sadly - so punt for now (?), and hope we don't get too
+ * many duplicate / overlapping hits */
+ rec = VEC_safe_push (vt_copy_record, heap, *vt_copies, NULL);
+ rec->src = src;
+ rec->dest = dest;
+ rec->bitmap = bitmap;
+ rec->offset = offset;
+ if (getenv ("MOREDEBUG"))
+ fprintf (stderr, "Push frag 0x%x %d\n", bitmap, offset);
+}
+
+static void
+debug_vt_copies (VEC(vt_copy_record,heap) *vt_copies)
+{
+ unsigned int i;
+
+ if (!getenv ("MOREDEBUG"))
+ return;
+
+ fprintf (stderr, "vtcopies: %d records\n", VEC_length(vt_copy_record, vt_copies));
+ for (i = 0; i < VEC_length(vt_copy_record, vt_copies); i++)
+ {
+ vt_copy_record *cpy = VEC_index (vt_copy_record, vt_copies, i);
+ fprintf (stderr, "\tcopy from %s+%d to ",
+ type_as_string (BINFO_TYPE (cpy->src->binfo), TFF_PLAIN_IDENTIFIER),
+ cpy->src->offset + cpy->offset);
+ fprintf (stderr, "%s+%d mask 0x%x\n",
+ type_as_string (BINFO_TYPE (cpy->dest->binfo), TFF_PLAIN_IDENTIFIER),
+ cpy->dest->offset + cpy->offset,
+ cpy->bitmap);
+ }
+}
+
+/*
+ * Compare all src & dest fragments for the best match ...
+ */
+static tree
+compare_build_vtrelocs (tree binfo, tree t, VEC(constructor_elt,gc) *vinits,
+ VEC(vt_fragment,heap) *dest_frags,
+ VEC(vt_fragment,heap) *src_frags)
+{
+ unsigned int i;
+ tree cgraph_clobber = NULL_TREE;
+ VEC(vt_copy_record,heap) *vt_copies;
+ int verbose_debug = getenv ("MOREDEBUG") != NULL;
+
+ vt_copies = VEC_alloc(vt_copy_record, heap, VEC_length(vt_fragment, dest_frags));
+
+ for (i = 0; i < VEC_length(vt_fragment, dest_frags); i++)
+ {
+ unsigned int j;
+ vt_fragment *dest = VEC_index (vt_fragment, dest_frags, i);
+
+ for (j = 0; j < VEC_length(vt_fragment, src_frags); j++)
+ {
+ unsigned int cmp;
+ unsigned int k, bits_set;
+ unsigned int bitmap;
+ int elide_leading_zeros = 1;
+ vt_fragment *src = VEC_index (vt_fragment, src_frags, j);
+
+ /* new virtual methods arrive only in the 1st dest fragment */
+ if (i > 0 && dest->size != src->size)
+ continue;
+
+ cmp = src->size;
+ if (cmp > dest->size)
+ cmp = dest->size;
+
+ /* FIXME: bin elide_leading_zeros until we have better
+ * comparison logic ? */
+ for (bitmap = bits_set = k = 0; k < cmp; k++)
+ {
+ tree src_fn = VEC_index (constructor_elt, src->vec, src->offset + k)->value;
+ tree dest_fn = VEC_index (constructor_elt, dest->vec, dest->offset + k)->value;
+ src_fn = TREE_OPERAND (src_fn, 0);
+ dest_fn = TREE_OPERAND (dest_fn, 0);
+
+ if (src_fn == dest_fn && src_fn != abort_fndecl)
+ {
+ bitmap |= (1 << bits_set);
+ elide_leading_zeros = 0;
+ }
+
+ if (verbose_debug)
+ {
+ fprintf (stderr, "compare: %s %s ",
+ expr_as_string (src_fn, TFF_PLAIN_IDENTIFIER),
+ src_fn == dest_fn ? "==" : "!=");
+ fprintf (stderr, "%s (0x%x) [%s]\n",
+ expr_as_string (dest_fn, TFF_PLAIN_IDENTIFIER),
+ bitmap,
+ src_fn == abort_fndecl ? "pure-virt" : "non-pure virt");
+ }
+
+ if (!elide_leading_zeros)
+ bits_set++;
+
+ if (bits_set == (sizeof (long) * 8)) /* FIXME: arch size etc. urgh ... */
+ {
+ push_vtfrag (&vt_copies, src, dest, bitmap, k - bits_set + 1);
+ bits_set = bitmap = 0;
+ elide_leading_zeros = 1;
+ }
+ }
+ if (bitmap != 0)
+ push_vtfrag (&vt_copies, src, dest, bitmap, k - bits_set);
+ }
+ }
+
+ if (VEC_length(vt_copy_record, vt_copies) > 0)
+ {
+ VEC(constructor_elt,gc) *vtable;
+ unsigned int i;
+ tree vtreloc_inits = NULL_TREE;
+
+ debug_vt_copies (vt_copies);
+
+ /*
+ * Re-write the intializers to remove references in the vtable...
+ */
+ vtable = VEC_copy(constructor_elt,gc,vinits);
+
+ if (verbose_debug)
+ fprintf (stderr, "re-writing vtable:\n");
+ for (i = 0; i < VEC_length(vt_copy_record, vt_copies); i++)
+ {
+ unsigned int j, bitmap;
+ vt_copy_record *vtc = VEC_index(vt_copy_record, vt_copies, i);
+
+ /* re-write the existing vtable intializer */
+ bitmap = vtc->bitmap;
+ if (verbose_debug)
+ fprintf (stderr, "\tclobber from off %d + %d, bitmap 0x%x\n",
+ vtc->dest->offset, vtc->offset, bitmap);
+ for (j = vtc->dest->offset + vtc->offset; bitmap; j++, (bitmap>>=1))
+ {
+ if (bitmap & 1)
+ {
+ constructor_elt *elt = VEC_index (constructor_elt, vtable, j);
+ if (verbose_debug)
+ fprintf (stderr, "\tclobber '%s' (0x%x)\n",
+ expr_as_string (elt->value, TFF_PLAIN_IDENTIFIER),
+ bitmap);
+
+ { /* Lengthy Assertion */
+ constructor_elt *src_elt = VEC_index (constructor_elt, vtc->src->vec,
+ vtc->src->offset + j - vtc->dest->offset);
+ gcc_assert (TREE_CODE (elt->value) == INTEGER_CST /* FIXME: strange, but sometimes we overlap */
+ || TREE_OPERAND (elt->value, 0) == TREE_OPERAND (src_elt->value, 0));
+ }
+ elt->value = fold_build1 (NOP_EXPR,
+ vtable_entry_type,
+ build_int_cst (build_pointer_type (void_type_node),
+ 0xdeadbeef));
+ }
+ }
+
+ /* build vtreloc decls */
+ vtreloc_inits = build_vtable_copy_slot (vtc->dest->binfo, t, vtc->dest->offset + vtc->offset,
+ vtc->src->binfo, vtc->src->offset + vtc->offset,
+ vtc->bitmap, vtreloc_inits);
+ }
+
+ /* re-build as chain for constructor ... hmm */
+ for (i = 0; i < VEC_length(constructor_elt, vtable); i++)
+ {
+ constructor_elt *elt = VEC_index (constructor_elt, vtable, i);
+ cgraph_clobber = tree_cons (elt->index, elt->value, cgraph_clobber);
+ }
+
+ /* Append a reference to the parent vtable
+ * to encourage cgraph not to clobber the vt-reloc decl */
+ cgraph_clobber = tree_cons (NULL_TREE,
+ build_nop (vfunc_ptr_type_node,
+ build_address (get_vtreloc_decl (binfo, t, vtreloc_inits))),
+ cgraph_clobber);
+ cgraph_clobber = nreverse (cgraph_clobber);
+ }
+
+ vec_heap_free (vt_copies);
+ return cgraph_clobber;
+}
+
+static VEC(constructor_elt,gc) *
+build_init_vec (tree inits)
+{
+ tree t;
+ VEC(constructor_elt,gc) *v = NULL;
+
+ if (inits)
+ {
+ v = VEC_alloc (constructor_elt, gc, list_length (inits));
+ for (t = inits; t; t = TREE_CHAIN (t))
+ {
+ constructor_elt *elt = VEC_quick_push (constructor_elt, v, NULL);
+ elt->index = TREE_PURPOSE (t);
+ elt->value = TREE_VALUE (t);
+ }
+ }
+
+ return v;
+}
+
+/*
+ * Create vtreloc data for type t, or type cstr_binfo in hierarchy
+ * t if a construction vtable.
+ */
+static tree
+create_vtrelocs (tree binfo, tree t, tree inits)
+{
+ /* Fixme - cstr_binfo ! */
+
+ int i;
+ tree base_binfo;
+ VEC(vt_fragment,heap) *dest_frags;
+ VEC(vt_fragment,heap) *src_frags;
+ VEC(constructor_elt,gc) *vinits = NULL;
+
+ if (!inits)
+ return NULL_TREE;
+ if (!getenv ("VT_SHRINK"))
+ return inits;
+
+ vinits = build_init_vec (inits);
+ if (!get_vtinit_for_binfo (binfo, t, 1))
+ set_vtinit_for_binfo (binfo, t, vinits);
+ else
+ fprintf (stderr, "Error: already set!\n");
+
+ if (getenv ("MOREDEBUG"))
+ {
+ debug_vtable (binfo, t);
+
+ fprintf (stderr, "Inherited from:\n");
+ if (TYPE_BINFO (t) != binfo)
+ {
+ debug_vtable (binfo, NULL_TREE);
+ }
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree btype = BINFO_TYPE (base_binfo);
+ debug_vtable (TYPE_BINFO (btype), NULL_TREE);
+ }
+ }
+
+ src_frags = VEC_alloc(vt_fragment,heap,4);
+ dest_frags = VEC_alloc(vt_fragment,heap,4);
+ vtdecompose_frags (binfo, t, &dest_frags);
+ if (TYPE_BINFO (t) != binfo)
+ vtdecompose_frags (binfo, NULL_TREE, &src_frags);
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ vtdecompose_frags (TYPE_BINFO (BINFO_TYPE (base_binfo)), NULL_TREE, &src_frags);
+ /* FIXME: do we want virtual bases here too ? */
+
+ if (getenv ("MOREDEBUG"))
+ {
+ fprintf (stderr, "dest:\n");
+ debug_fragments (dest_frags);
+ fprintf (stderr, "src:\n");
+ debug_fragments (src_frags);
+ }
+
+ if (inits) {
+ tree new_inits = compare_build_vtrelocs (binfo, t, vinits, dest_frags,
+ src_frags);
+ if (new_inits)
+ inits = new_inits;
+ }
+
+ vec_heap_free (dest_frags);
+ vec_heap_free (src_frags);
+
+ return inits;
+}
+
+static void
+finish_vtbls (tree t)
+{
+ tree inits;
+
+ inits = vtbl_get_inits (t);
+ inits = create_vtrelocs (TYPE_BINFO (t), t, inits);
+
if (BINFO_VTABLE (TYPE_BINFO (t)))
- initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));
+ initialize_vtable (TYPE_BINFO (t), inits);
}
/* Initialize the vtable for BINFO with the INITS. */
@@ -6984,6 +7531,17 @@
/* Initialize the construction vtable. */
CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
+
+ SET_IDENTIFIER_GLOBAL_VALUE (id, vtbl); /* we need this later */
+ inits = create_vtrelocs (binfo, t, inits);
+ /* potentially correct the array size type - URGH cut/paste ... */
+ {
+ /* Figure out the type of the construction vtable. */
+ type = build_index_type (size_int (list_length (inits) - 1));
+ type = build_cplus_array_type (vtable_entry_type, type);
+ TREE_TYPE (vtbl) = type;
+ }
+
initialize_artificial_var (vtbl, inits);
dump_vtable (t, binfo, vtbl);
}
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-gcc-4.2.1-simple/gcc/cp/cp-tree.h gcc-4.2.1-simple/gcc/cp/cp-tree.h
--- pristine-gcc-4.2.1-simple/gcc/cp/cp-tree.h 2007-07-24 09:14:47.000000000 +0100
+++ gcc-4.2.1-simple/gcc/cp/cp-tree.h 2008-01-30 16:58:08.000000000 +0000
@@ -498,6 +498,7 @@
CPTI_UNKNOWN_TYPE,
CPTI_VTBL_TYPE,
CPTI_VTBL_PTR_TYPE,
+ CPTI_VTBL_SLOT_COPY_TYPE,
CPTI_STD,
CPTI_ABI,
CPTI_CONST_TYPE_INFO_TYPE,
@@ -562,6 +563,7 @@
#define unknown_type_node cp_global_trees[CPTI_UNKNOWN_TYPE]
#define vtbl_type_node cp_global_trees[CPTI_VTBL_TYPE]
#define vtbl_ptr_type_node cp_global_trees[CPTI_VTBL_PTR_TYPE]
+#define vtbl_slot_copy_type_node cp_global_trees[CPTI_VTBL_SLOT_COPY_TYPE]
#define std_node cp_global_trees[CPTI_STD]
#define abi_node cp_global_trees[CPTI_ABI]
#define const_type_info_type_node cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE]
@@ -3392,6 +3394,9 @@
TREE_PURPOSE slot. */
extern GTY(()) tree static_aggregates;
+/* A type mapping of types to un-altered type tables */
+extern GTY(()) tree vtable_copy_types;
+
/* Functions called along with real static constructors and destructors. */
extern GTY(()) tree static_ctors;
@@ -3847,6 +3852,7 @@
extern void maybe_note_name_used_in_class (tree, tree);
extern void note_name_declared_in_class (tree, tree);
extern tree get_vtbl_decl_for_binfo (tree);
+/* extern tree get_vtreloc_decl (tree, tree); */
extern void debug_class (tree);
extern void debug_thunks (tree);
extern tree cp_fold_obj_type_ref (tree, tree);
@@ -4533,6 +4539,9 @@
extern tree mangle_typeinfo_for_type (tree);
extern tree mangle_typeinfo_string_for_type (tree);
extern tree mangle_vtbl_for_type (tree);
+extern tree mangle_vtbl_for_type_local (tree);
+extern tree mangle_vtreloc_for_type (tree, tree);
+extern tree mangle_vtreloc_section_for_type (tree, tree);
extern tree mangle_vtt_for_type (tree);
extern tree mangle_ctor_vtbl_for_type (tree, tree);
extern tree mangle_thunk (tree, int, tree, tree);
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-gcc-4.2.1-simple/gcc/cp/decl.c gcc-4.2.1-simple/gcc/cp/decl.c
--- pristine-gcc-4.2.1-simple/gcc/cp/decl.c 2007-07-24 09:14:45.000000000 +0100
+++ gcc-4.2.1-simple/gcc/cp/decl.c 2008-01-21 19:50:44.000000000 +0000
@@ -124,6 +124,10 @@
tree vtbl_type_node;
tree vtbl_ptr_type_node;
+ Array slot copy type info:
+
+ tree vtbl_slot_copy_type_node;
+
Namespaces,
tree std_node;
@@ -3117,6 +3121,13 @@
}
}
+static tree
+append_struct_field (const char *name, tree type, tree chain)
+{
+ return chainon (chain, build_decl (FIELD_DECL,
+ get_identifier (name), type));
+}
+
/* Create the predefined scalar types of C,
and some nodes representing standard constants (0, 1, (void *)0).
Initialize the global binding level.
@@ -3243,6 +3254,19 @@
layout_type (vtbl_ptr_type_node);
record_builtin_type (RID_MAX, NULL, vtbl_ptr_type_node);
+ {
+ tree elem_fields = NULL;
+
+ vtbl_slot_copy_type_node = make_aggr_type (RECORD_TYPE);
+ elem_fields = append_struct_field ("vt_src_addr", ptr_type_node, elem_fields);
+ elem_fields = append_struct_field ("vt_dest_addr", ptr_type_node, elem_fields);
+ elem_fields = append_struct_field ("vt_copy_bitmap", size_type_node, elem_fields);
+ finish_builtin_struct (vtbl_slot_copy_type_node, "__vt_copy_slot_relocs",
+ elem_fields, NULL_TREE);
+ layout_type (vtbl_slot_copy_type_node);
+ record_builtin_type (RID_MAX, NULL, vtbl_slot_copy_type_node);
+ }
+
push_namespace (get_identifier ("__cxxabiv1"));
abi_node = current_namespace;
pop_namespace ();
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-gcc-4.2.1-simple/gcc/cp/mangle.c gcc-4.2.1-simple/gcc/cp/mangle.c
--- pristine-gcc-4.2.1-simple/gcc/cp/mangle.c 2006-12-11 12:16:19.000000000 +0000
+++ gcc-4.2.1-simple/gcc/cp/mangle.c 2008-01-31 12:05:37.000000000 +0000
@@ -2670,6 +2670,112 @@
return mangle_special_for_type (type, "TV");
}
+tree
+mangle_vtbl_for_type_local (const tree type)
+{
+ const char *result;
+
+ /* We don't have an actual decl here for the special component, so
+ we can't just process the <encoded-name>. Instead, fake it. */
+ start_mangling (type, /*ident_p=*/true);
+
+ /* Start the mangling. */
+ write_string ("_Z");
+ write_string ("VT");
+
+ /* Add the type. */
+ write_type (type);
+ write_string ("_local");
+ result = finish_mangling (/*warn=*/false);
+
+ return get_identifier_nocopy (result);
+}
+
+/* FIXME: as should be obvious I have no idea what I'm doing here */
+static int calc_max_depth (const tree binfo)
+{
+ int i, max = 0;
+ tree base;
+
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base); ++i) {
+ int depth = calc_max_depth (base);
+ if (depth > max)
+ max = depth;
+ }
+ return max + 1;
+}
+
+static void write_order_complexity_for_type (const tree type)
+{
+ int max_depth = 0;
+ int virts;
+ tree binfo;
+ char buffer[128]; /* hack */
+
+ binfo = TYPE_BINFO (type);
+
+ max_depth = calc_max_depth (binfo);
+
+ /* FIXME: virtual bases ?
+ {
+ tree vbase;
+ for (vbase = binfo; vbase; vbase = TREE_CHAIN (vbase))
+ virts++;
+ }
+ */
+ virts = 0;
+
+ sprintf (buffer, "_%.8i_", max_depth + virts);
+ write_string (buffer);
+}
+
+/*
+ * In order to get initialization order right, use a metric of
+ * the maximum 'inheritedness' of a class, ie. a vtable that
+ * inherits from 5 others, should be initialized after those
+ * that inherit from 4
+ */
+static const char *mangle_vtreloc (const tree binfo,
+ const tree t,
+ const char *prefix)
+{
+ int constr = TYPE_BINFO (t) != binfo; /* test: one */
+ const char *name;
+
+ start_mangling (t, /*ident_p=*/true);
+ write_string (prefix);
+ write_string ("_ZVTR");
+ write_order_complexity_for_type (t);
+ if (constr)
+ write_string ("C");
+ write_type (t);
+ if (constr)
+ {
+ write_integer_cst (BINFO_OFFSET (binfo));
+ write_char ('_');
+ write_type (BINFO_TYPE (binfo));
+ }
+
+ name = finish_mangling (/*warn=*/false);
+
+ return name;
+}
+
+/* Create an identifier for the mangled name of the vt relocs for TYPE. */
+
+tree mangle_vtreloc_for_type (const tree binfo, const tree t)
+{
+ return get_identifier_nocopy (mangle_vtreloc (binfo, t, ""));
+}
+
+/* Create an identifier for the section name of the vt relocs for TYPE. */
+
+tree mangle_vtreloc_section_for_type (const tree binfo, const tree t)
+{
+ const char *name = mangle_vtreloc (binfo, t, ".vtrelocs.");
+ return build_string (strlen (name), name);
+}
+
/* Returns an identifier for the mangled name of the VTT for TYPE. */
tree
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-gcc-4.2.1-simple/gcc/cp/method.c gcc-4.2.1-simple/gcc/cp/method.c
--- pristine-gcc-4.2.1-simple/gcc/cp/method.c 2006-12-11 12:16:19.000000000 +0000
+++ gcc-4.2.1-simple/gcc/cp/method.c 2008-01-28 21:55:50.000000000 +0000
@@ -165,6 +165,12 @@
DECL_USE_TEMPLATE (thunk) = 0;
DECL_TEMPLATE_INFO (thunk) = NULL;
+ if (getenv ("VT_SHRINK"))
+ {
+ DECL_VISIBILITY (thunk) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (thunk) = 1;
+ }
+
/* Add it to the list of thunks associated with FUNCTION. */
TREE_CHAIN (thunk) = DECL_THUNKS (function);
DECL_THUNKS (function) = thunk;
@@ -384,6 +390,14 @@
= DECL_VISIBILITY_SPECIFIED (function);
if (DECL_ONE_ONLY (function))
make_decl_one_only (thunk_fndecl);
+ if (getenv ("VT_SHRINK"))
+ {
+ if (getenv ("MOREDEBUG"))
+ fprintf (stderr, "make thunk '%s' hidden\n",
+ decl_as_string (thunk_fndecl, TFF_PLAIN_IDENTIFIER));
+ DECL_VISIBILITY (thunk_fndecl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (thunk_fndecl) = 1;
+ }
if (flag_syntax_only)
{
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-glibc-2.6.1/elf/dl-init.c glibc-2.6.1/elf/dl-init.c
--- pristine-glibc-2.6.1/elf/dl-init.c 2005-01-06 22:40:26.000000000 +0000
+++ glibc-2.6.1/elf/dl-init.c 2008-01-22 16:09:03.000000000 +0000
@@ -30,6 +30,79 @@
extern int _dl_starting_up_internal attribute_hidden;
#endif
+#define SUSEIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + \
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM + DT_SUSE_TAGIDX (sym))
+
+/* process vtable / block copy relocations */
+
+static void
+_dl_perform_vtrelocs (struct link_map *map)
+{
+ ElfW(VtReloc) *rel;
+ int debug_output = GLRO(dl_debug_mask) & DL_DEBUG_RELOC;
+ int i;
+
+ if (debug_output)
+ _dl_debug_printf ("new vtcopy-reloc processing on '%s' offset 0x%x map 0x%x\n",
+ map->l_name[0] ? map->l_name : rtld_progname,
+ map->l_addr, map->l_map_start);
+
+ /* any vtrelocs ? */
+ if (map->l_info[SUSEIDX(DT_SUSE_VTRELOC)] == NULL)
+ {
+ if (debug_output)
+ _dl_debug_printf ("no vtreloc section in '%s'\n", map->l_name);
+ return;
+ }
+ rel = (ElfW(VtReloc) *)(D_PTR (map, l_info[SUSEIDX(DT_SUSE_VTRELOC)]));
+ if (debug_output)
+ _dl_debug_printf ("vtreloc section found in '%s' at 0x%x (0x%x) mapped at 0x%x\n",
+ map->l_name, rel, ((ElfW(Addr))rel - map->l_addr),
+ map->l_addr);
+ while (rel->r_src != 0)
+ {
+ ElfW(Addr) **src, **dest;
+ ElfW(Word) mask;
+
+ src = (void *)rel->r_src;
+ dest = (void *)rel->r_dest;
+ if (debug_output)
+ _dl_debug_printf ("copy from 0x%x to 0x%x mask 0x%x\n", src, dest, rel->r_mask);
+#ifdef DONT_TOUCH_EXTERNAL
+ if (dest < map->l_map_start || dest >= map->l_map_end)
+ { /* weak symbol defined in another dso - thus already fixed up, and readonly */
+ if (debug_output)
+ _dl_debug_printf (" skip, defined elsewhere\n");
+ }
+ else
+#endif
+ {
+ for (mask = rel->r_mask; mask; mask >>= 1)
+ {
+ /* _dl_debug_printf ("%s copy [&0x%x -> &0x%x]\n",
+ mask & 1 ? "do" : "no", src, dest); */
+ if (mask & 1)
+ {
+ if (debug_output || !(*src == *dest || *dest == (ElfW(Addr) *)0xdeadbeef))
+ {
+ _dl_debug_printf ("do copy 0x%x to 0x%x %s [&0x%x -> &0x%x]\n",
+ *src, *dest,
+ *src == *dest || *dest == (ElfW(Addr) *)0xdeadbeef ? "match" : "Bug",
+ src, dest);
+ }
+ *dest = *src;
+ }
+ else if (debug_output)
+ _dl_debug_printf ("no copy 0x%x to 0x%x %s\n",
+ *src, *dest, *src == *dest && (int)*src > 0x100 ? "Bug" : "skip");
+ dest++; src++;
+ }
+ }
+ if (debug_output)
+ _dl_debug_printf ("move to next vtrel entry\n");
+ rel++;
+ }
+}
static void
call_init (struct link_map *l, int argc, char **argv, char **env)
@@ -42,6 +115,8 @@
dependency. */
l->l_init_called = 1;
+ _dl_perform_vtrelocs (l);
+
/* Check for object which constructors we do not run here. */
if (__builtin_expect (l->l_name[0], 'a') == '\0'
&& l->l_type == lt_executable)
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-glibc-2.6.1/elf/dl-load.c glibc-2.6.1/elf/dl-load.c
--- pristine-glibc-2.6.1/elf/dl-load.c 2008-01-08 20:45:11.000000000 +0000
+++ glibc-2.6.1/elf/dl-load.c 2008-01-11 15:23:16.000000000 +0000
@@ -1200,9 +1200,13 @@
/* Remember which part of the address space this object uses. */
l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength,
- c->prot,
+ c->prot | PROT_WRITE,
MAP_COPY|MAP_FILE,
fd, c->mapoff);
+ if (GLRO(dl_debug_mask) & DL_DEBUG_RELOC)
+ _dl_debug_printf ("map '%s' at 0x%x prot 0x%x\n", l->l_name,
+ l->l_map_start, c->prot);
+
if (__builtin_expect ((void *) l->l_map_start == MAP_FAILED, 0))
{
map_error:
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-glibc-2.6.1/elf/dl-reloc.c glibc-2.6.1/elf/dl-reloc.c
--- pristine-glibc-2.6.1/elf/dl-reloc.c 2007-05-18 09:37:39.000000000 +0100
+++ glibc-2.6.1/elf/dl-reloc.c 2008-01-22 15:54:46.000000000 +0000
@@ -133,7 +133,6 @@
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
}
-
void
_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
int lazy, int consider_profiling)
@@ -174,11 +173,15 @@
/* DT_TEXTREL is now in level 2 and might phase out at some time.
But we rewrite the DT_FLAGS entry to a DT_TEXTREL entry to make
testing easier and therefore it will be available at all time. */
- if (__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0))
+ if (1) //__builtin_expect (l->l_info[DT_TEXTREL] != NULL, 0))
{
/* Bletch. We must make read-only segments writable
long enough to relocate them. */
const ElfW(Phdr) *ph;
+
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0))
+ _dl_debug_printf ("un-protecting foo\n");
+
for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph)
if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
{
@@ -296,6 +299,7 @@
/* Mark the object so we know this work has been done. */
l->l_relocated = 1;
+#if 0
/* Undo the segment protection changes. */
while (__builtin_expect (textrels != NULL, 0))
{
@@ -312,6 +316,7 @@
done, do it. */
if (l->l_relro_size != 0)
_dl_protect_relro (l);
+#endif
}
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-glibc-2.6.1/elf/dynamic-link.h glibc-2.6.1/elf/dynamic-link.h
--- pristine-glibc-2.6.1/elf/dynamic-link.h 2006-07-10 22:52:18.000000000 +0100
+++ glibc-2.6.1/elf/dynamic-link.h 2008-01-10 18:08:21.000000000 +0000
@@ -65,6 +65,10 @@
#ifndef VERSYMIDX
# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
#endif
+#ifndef SUSEIDX
+# define SUSEIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + \
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM + DT_SUSE_TAGIDX (sym))
+#endif
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
@@ -88,6 +92,9 @@
while (dyn->d_tag != DT_NULL)
{
+ if (dyn->d_tag >= DT_SUSE_LO &&
+ dyn->d_tag < DT_SUSE_LO + DT_SUSENUM)
+ info[SUSEIDX(dyn->d_tag)] = dyn;
if (dyn->d_tag < DT_NUM)
info[dyn->d_tag] = dyn;
else if (dyn->d_tag >= DT_LOPROC &&
@@ -143,6 +150,7 @@
# endif
ADJUST_DYN_INFO (DT_JMPREL);
ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
+ ADJUST_DYN_INFO (SUSEIDX(DT_SUSE_VTRELOC));
ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
+ DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
# undef ADJUST_DYN_INFO
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-glibc-2.6.1/elf/elf.h glibc-2.6.1/elf/elf.h
--- pristine-glibc-2.6.1/elf/elf.h 2007-05-18 09:37:39.000000000 +0100
+++ glibc-2.6.1/elf/elf.h 2008-01-09 16:43:02.000000000 +0000
@@ -518,6 +518,22 @@
Elf64_Sxword r_addend; /* Addend */
} Elf64_Rela;
+/* VTable relocation entry */
+
+typedef struct
+{
+ Elf32_Addr r_src; /* source address */
+ Elf32_Addr r_dest; /* destination address */
+ Elf32_Word r_mask; /* copy bit-mask */
+} Elf32_VtReloc;
+
+typedef struct
+{
+ Elf64_Addr r_src; /* source address */
+ Elf64_Addr r_dest; /* destination address */
+ Elf64_Word r_mask; /* copy bit-mask */
+} Elf64_VtReloc;
+
/* How to extract and insert information held in the r_info field. */
#define ELF32_R_SYM(val) ((val) >> 8)
@@ -734,6 +750,14 @@
#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
#define DT_VERSIONTAGNUM 16
+/* SUSE specific pieces - at a random OS specific address, after
+ previous 2 (direct/hashvals) development sections */
+#define DT_SUSE_LO (0x6cbdd030 + 2)
+#define DT_SUSE_VTRELOC DT_SUSE_LO
+#define DT_SUSE_HI 0x6cbdd040
+#define DT_SUSE_TAGIDX(tag) (tag - DT_SUSE_LO)
+#define DT_SUSENUM 1
+
/* Sun added these machine-independent extensions in the "processor-specific"
range. Be compatible. */
#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
diff -u -r -x '*~' -x '*.rej' -x testsuite -x libjava -x cc-nptl -x build-dir -x '*.orig' -x obj-i586-suse-linux -x texis -x Makeconfig -x version.h -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' pristine-glibc-2.6.1/include/link.h glibc-2.6.1/include/link.h
--- pristine-glibc-2.6.1/include/link.h 2007-08-03 14:57:06.000000000 +0100
+++ glibc-2.6.1/include/link.h 2008-01-09 16:43:02.000000000 +0000
@@ -121,7 +121,7 @@
are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>. */
ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
- + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
+ + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM + DT_SUSENUM];
const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */
ElfW(Addr) l_entry; /* Entry point location. */
ElfW(Half) l_phnum; /* Number of program header entries. */