This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

vtrelocs: large/modular C++ app speedup ...


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.  */

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