    + stub functions
	-> either to PLT or to ... (?) [ clever assembler ... ]

   + class count
	+ vfuncs per class
	+ number of virtual functions
		+ implemented by that class
		+ implemented by a parent
		+ implemented externally
	+ interesting, all virtual destructors duplicated eg.
	    + ~ImplDelData - 3 destructor relocations ...

    + Linkage to parent classes: 1 symbol + @got offset
      per class (?) => cheap.
	+ generate in-lined code to do the vtable setup ?
	    + need symbol-lookup logic hooks ? - too big ?


** How do the virtual thunk goodies work out ?
	+ do we need 1 extra fixup foostub per sub/shared
	  -class ?
	+ would they benefit from the index pointer ?

	+ Very interesting paper:
	    http://gcc.fyxm.net/summit/2003/Getting%20the%20Best%20from%20G++.pdf
	+ nowadays:
	    + no per-virtual base cost for objects, store
	      adjustment data in the vtable instead.
	+ Th, Tv, Tc - fixed, variant, covariant thunk
	+ virtual vs. direct call (?)

	+ do thunks affect anything in fact ?
	+ [ how large is the vtable description data going
	    to be, necessary to do the full relocation ? ]

** Interesting questions
    + *why* is it that (or even is it!?) that we export
      VTables stuffed full of relocations even when we're using
      a 'hidden' visiblity ?


    + we do 1 relocation, per virtual method, per class/sub-class
	+ ... fun ...
    + do we do -lots- of relocations for 'weak' / vtables that we
      can *know* will not be used ever (?)
	+ COMDAT support should eliminate them anyay (?)
	+ how many relocations take place inside (weak) objects ?
	+ what is the average size of a weak object ...
        + eg. the _ZTV15SvxCheckListBox is only defined in 1 place
	  ie. we prolly don't have tons of duplicate/redundant
	  vtables inc. relocations. vtable emitted as 1st virtual is
	  defined (?).

    + I remember [!] - the reason why we analyse only .rel.dyn
	+ it is processed immediately
	      + .rel.plt is lazily processed ...

    + interesting KDE related paper:
	+ http://www.suse.de/~bastian/Export/linking.txt
		+ everything called 'kdeinit' - linked & then forks
		  => still relocated etc. => upgrade libraries & no
		     change until kdeinit is restarted
		+ ... interesting solution ...

gcc IRC:
    + #gcc on oftc.net, or oftc.org
	
    + Possible approaches:
	+ prelink
	    + similar to SGI's IRIX 'rebase' tool
	    + very fast, very ugly - slows system updates
	    + works for C, C++, system startup etc.
	+ shmem handshake with 'link-daemon': do the dlink in
	  another process via shared memory. - ie. system-wide
	  pre-linking / caching...
	    + all but 1st time very fast - demand built cache
	    + 1st time somewhat slower - to reduce handshaking
	      would want to do LD_BIND_NOW or equiv.
	    + works for C, C++, system startup etc.
	+ re-work gcc to ensure 
	+ add link hooks for 'idle-linkage' slots (?)
	    + can we get virtual methods into the plt ?
	    + instead of a vtable: a 'code-table'
		+ ie. jump edx + <shim-size>*foo
		+ that shim would be ? a ton of plt references ...
		+ ie. jump into the vtable itself - rather than 
		  the code
		    => bloat ? what is the size of a PLT entry ?
		+ [ compatibility ]:
		    + can keep the existing code & absolute offset ? -
		      have a non-symbol-driven pathetic relocation,
		      pointing to the end of the vtable ?
		    + at the end => no vicious vtable offset
		      calculation problems (?!)
	    + works only for C++
	    * elaboration *
		+ a re-linker that would add these slots post-compile
	+ fix g++/binutils to add 'export' (ie. -Bsymbolic) style
	  markup to all (non-weak?) symbols exported from a visibility
	  annotated class.
	    + partial solution - normally kills < 50% of the relocs
	    + works only for C++
	+ a new / PLT-like approach
	    + we do *maths* to calculate the offset into the vtable
	      anyway - before a virtual call, surely that logic must
	      consume a register or two we can rely on (?)
	    + can we not call a shim / dlink helper instead
		+ classes can have a table of PLT-like slots chained
		  from the vtable to build the table with.
		+ (or a single, initial relocation per vtable)
		+ => can relocate lazily ...
	    + ... PLT entry into the vtable ...



    + Tool to dump '.data' and '.got' sections (?)
	+ and unwind which relocations are in which symbols/elements
	  there precisely....
	+ tool to calculate how many vtables, their size, average
	  number of slots etc.
	    + Problem is:
		+ relocs for internal (hidden visibility)
		  *mostly* resolve internally - except for inherited
		  methods (from publicly exposed things)
		+ eg. SvXML

Gcc hack:
    + output location of PLT function instead of address
      of function - (easy?)
	#pragma push relocating_vtables
	#pragma pop relocating_vtables (?)
	+ -fvtable-via-plt
	    + no need to put code in the foo anyway [?]
	+ optimise parent/chain calls:
	    + switch to vtable usage (?) => relocation (?)
    + Can we use the 'call *(%eax)' instruction
	+ how bad is that wrt. stalling data fetch etc. ?

Interesting:
    + if we know what the type is; we do a 'direct' function call
	+ instead of the vtable lookup [wow]
	    + => in fact ~always slower than a vtable
	      lookup (surely)
	
    + work out how large a plt entry is & how many vtable
      entries we have.



    + analysing libsvx:
	+ objdump -R libsvx680li.so | grep -v '\*ABS\*' \
	          | cut -c 28-100 | sort | uniq -c | sort -n
    + result:
	+ 17k unique symbol 

    + questions:
	+ what are these symbols ?
	    + internal vs. external
	    + weak vs. strong
	    + & a better understanding of why we need
	      so - so many relocs.

    + Analysis of internal{weak/strong}/external gives:(relocstat)
	+ libsvx680li.so total relocs 17483 external 5204, internal weak 2888, internal strong 9391: saving 54%

    + KDE has a -far- smaller relocation count: why ? - deep/virtual trees ?

+ Random analysis of 20 relocs:

SvxRTFParser::CalcValue()	_ZN12SvxRTFParser9CalcValueEv
	+ svx/inc/svxrtf.hxx:
	    + virtual void CalcValue() - an internally resolvable / global symbol
		+ cost: 1 symbol, 1 relocation, etc.

SvTreeListBox::MakeVisible(SvLBoxEntry*)	_ZN13SvTreeListBox11MakeVisibleEP11SvLBoxEntry
    + checklbx.hxx:class SVX_DLLPUBLIC SvxCheckListBox : public SvTreeListBox
autocdlg.o
000000e0 R_386_32          _ZN13SvTreeListBox11MakeVisibleEP11SvLBoxEntry
cfg.o
000000e0 R_386_32          _ZN13SvTreeListBox11MakeVisibleEP11SvLBoxEntry
000000e0 R_386_32          _ZN13SvTreeListBox11MakeVisibleEP11SvLBoxEntry
    + ** fascinating ** - to see the vtable laid out, in all it's glory:
eg.
        .hidden _ZTV14MenuSaveInData
        .weak   _ZTV14MenuSaveInData
        .section        .gnu.linkonce.d._ZTV14MenuSaveInData,"awG",@progbits,_ZTV14MenuSaveInData,comdat
        .align 32
        .type   _ZTV14MenuSaveInData, @object
        .size   _ZTV14MenuSaveInData, 36
_ZTV14MenuSaveInData:
        .long   0
        .long   _ZTI14MenuSaveInData
        .long   _ZN10SaveInData8GetImageERKN3rtl8OUStringE
        .long   _ZN14MenuSaveInData6HasURLERKN3rtl8OUStringE
        .long   _ZN14MenuSaveInData11HasSettingsEv
        .long   _ZN14MenuSaveInData10GetEntriesEv
        .long   _ZN14MenuSaveInData10SetEntriesEPN4_STL6vectorIP14SvxConfigEntryNS0_9allocatorIS3_EEEE
        .long   _ZN14MenuSaveInData5ResetEv
        .long   _ZN14MenuSaveInData5ApplyEv

checklbx.o
000000e0 R_386_32          _ZN13SvTreeListBox11MakeVisibleEP11SvLBoxEntry
    + implements SvxCheckListBox
	+ inherits from SvTreeListBox
	+ which implements:
		virtual void	MakeVisible( SvLBoxEntry* );
... tons of other SvxCheckListBox relocations ...
        .weak   _ZTV15SvxCheckListBox
        .section        .gnu.linkonce.d._ZTV15SvxCheckListBox,"awG",@progbits,_ZTV15SvxCheckListBox,comdat
        .align 32
        .type   _ZTV15SvxCheckListBox, @object
        .size   _ZTV15SvxCheckListBox, 540
    _ZTV15SvxCheckListBox:
        .long   0
        .long   _ZTI15SvxCheckListBox
        .long   _ZN15SvxCheckListBoxD1Ev
        .long   _ZN15SvxCheckListBoxD0Ev
        .long   _ZN13SvTreeListBox9MouseMoveERK10MouseEvent
        .long   _ZN15SvxCheckListBox15MouseButtonDownERK10MouseEvent
	...
        .long   _ZN13SvTreeListBox11MakeVisibleEP11SvLBoxEntry



non-virtual thunk to E3dView::~E3dView()        _ZThn16_N7E3dViewD1Ev
svt::EditBrowseBox::ResizeController(svt::CellControllerRef&, Rectangle const&) _ZN3svt13EditBrowseBox16ResizeControllerERNS_17CellControllerRefERK9Rectangle
non-virtual thunk to FmXGridPeer::disposing(com::sun::star::lang::EventObject const&)   _ZThn384_N11FmXGridPeer9disposingERKN3com3sun4star4lang11EventObjectE
SvxCaseMapItem::Store(SvStream&, unsigned short) const  _ZNK14SvxCaseMapItem5StoreER8SvStreamt
non-virtual thunk to SvxUnoText::~SvxUnoText()  _ZThn76_N10SvxUnoTextD0Ev
non-virtual thunk to accessibility::AccessibleShape::queryInterface(com::sun::star::uno::Type const&)   _ZThn36_N13accessibility15AccessibleShape14queryInterfaceERKN3com3sun4star3uno4TypeE
SdrModel::SetReadOnly(int)      _ZN8SdrModel11SetReadOnlyEi
SdrObject::NbcSetLogicRect(Rectangle const&)    _ZN9SdrObject15NbcSetLogicRectERK9Rectangle
Edit::LoseFocus()       _ZN4Edit9LoseFocusEv
typeinfo for sdr::contact::ViewContact  _ZTIN3sdr7contact11ViewContactE
non-virtual thunk to accessibility::AccessibleShape::queryInterface(com::sun::star::uno::Type const&)   _ZThn44_N13accessibility15AccessibleShape14queryInterfaceERKN3com3sun4star3uno4TypeE
svx::FormatPaintBrushToolBoxControl::Select(unsigned char)      _ZN3svx30FormatPaintBrushToolBoxControl6SelectEh
SvxUnoTextRangeBase::compareRegionStarts(com::sun::star::uno::Reference<com::sun::star::text::XTextRange> const&, com::sun::star::uno::Reference<com::sun::star::text::XTextRange> const&)  _ZN19SvxUnoTextRangeBase19compareRegionStartsERKN3com3sun4star3uno9ReferenceINS2_4text10XTextRangeEEES9_
SdrCircObj::CheckHit(Point const&, unsigned short, SetOfByte const*) const      _ZNK10SdrCircObj8CheckHitERK5PointtPK9SetOfByte
SvxRTFParser::UnknownAttrToken(int, SfxItemSet*)        _ZN12SvxRTFParser16UnknownAttrTokenEiP10SfxItemSet
non-virtual thunk to SvxShape::removePropertiesChangeListener(com::sun::star::uno::Reference<com::sun::star::beans::XPropertiesChangeListener> const&)      _ZThn40_N8SvxShape30removePropertiesChangeListenerERKN3com3sun4star3uno9ReferenceINS2_5beans25XPropertiesChangeListenerEEE
typeinfo for SvxFontMenuControl _ZTI18SvxFontMenuControl
SvxShadowItem::HasMetrics() const       _ZNK13SvxShadowItem10HasMetricsEv
non-virtual thunk to SvxFmDrawPage::~SvxFmDrawPage()    _ZThn48_N13SvxFmDrawPageD1Ev
typeinfo for XLineDashItem      _ZTI13XLineDashItem


+ Random selection of high hit-count symbols 8 or more (1170) ...
      8 _ZThn172_N12SvxShapeText14queryInterfaceERKN3com3sun4star3uno4TypeE
     54 _ZThn20_N17SfxToolBoxControl14queryInterfaceERKN3com3sun4star3uno4TypeE
    199 _ZN6Window8ActivateEv
     11 _ZN9E3dObject10NbcRotateZEd
      9 _ZN18TransferableHelper8dragOverERKN3com3sun4star12datatransfer3dnd19Drag
     14 _ZN9SdrObject9NbcMirrorERK5PointS2_
     11 _ZNK13SdrDragMethod7DrawXorER13XOutputDevicei
     10 _ZNK13SfxStringItem6CreateER8SvStreamt
     45 _ZNK11CntBoolItem17GetValueTextByValEh
     15 _ZTI12SvxColorItem


+ notes on layout foo:
	+ layout_decl (vtable) ? - call to the backend for layout ?
		+ stor-layout.c (layout_decl) - allocates storage.
		+ sets rtl - if known
  /* Make the rtl for any new vtables we have created, and unmark
     the base types we marked.  */
	+ class.c (finish_vtbls):

    + class.c (layout_class_type): interesting stuff...

    + class.c (create_vtable_ptr): interesting ...
	+ The initial code creates the TREE_LIST nodes for
	  the virtual functions:

  /* Collect the virtual functions declared in T.  */
  for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
    if (DECL_VINDEX (fn) && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)
	&& TREE_CODE (DECL_VINDEX (fn)) != INTEGER_CST)
      {
	tree new_virtual = make_node (TREE_LIST);

//	cp_warning_at ("create_vtable_ptr for method: %qD", fn);
	
	BV_FN (new_virtual) = fn;
	BV_DELTA (new_virtual) = integer_zero_node;
	BV_VCALL_INDEX (new_virtual) = NULL_TREE;

	TREE_CHAIN (new_virtual) = *virtuals_p;
	*virtuals_p = new_virtual;
      }

-> build_vtbl_initializer ...  
   + calls: 
	init = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
vs
	init = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);

tree.h:#define build1(c,t1,t2) build1_stat (c,t1,t2 MEM_STAT_INFO)
cp-tree.h:#define vfunc_ptr_type_node  vtable_entry_type

decl.c (cxx_init_decl_processing):
  {
    /* Make sure we get a unique function type, so we can give
       its pointer type a name.  (This wins for gdb.) */
    tree vfunc_type = make_node (FUNCTION_TYPE);
    TREE_TYPE (vfunc_type) = integer_type_node;
    TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
    layout_type (vfunc_type);

    vtable_entry_type = build_pointer_type (vfunc_type);
  }
  record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type);
#define VTBL_PTR_TYPE		"__vtbl_ptr_type"



tree.c (build_pointer_type):
  return build_pointer_type_for_mode (to_type, ptr_mode, false);

emit-rtl.c:
enum machine_mode ptr_mode;	/* Mode whose width is POINTER_SIZE.  */

'enum machine_mode' - never declared (apparently)

* Pointing to the PLT works well at the assembler level.

gcc/config/i386/i386.c:

static void
output_pic_addr_const (FILE *file, rtx x, int code)
    case SYMBOL_REF:
     /* Mark the decl as referenced so that cgraph will output the function.  */
     if (SYMBOL_REF_DECL (x))
       mark_decl_referenced (SYMBOL_REF_DECL (x));

      assemble_name (file, XSTR (x, 0));
      if (!TARGET_MACHO && code == 'P' && ! SYMBOL_REF_LOCAL_P (x))
	fputs ("@PLT", file);
      break;

from i386:print_operand():
/* Meaning of CODE:
...
   P -- if PIC, print an @PLT suffix.
 */

called from gcc/final.c (output_operand):

or config/i386/sol2.h:
#define ASM_OUTPUT_CALL(FILE, FN)				\
  do								\
    {								\
      fprintf (FILE, "\tcall\t");				\
      print_operand (FILE, XEXP (DECL_RTL (FN), 0), 'P');	\
      fprintf (FILE, "\n");					\
    }								\
  while (0)

These magic names come from some highly magic
printf style output macros; cf. final.c (output_asm_insn):

eg. config/i386/i386.md:

(define_insn "*call_pop_0"
  [(call (mem:QI (match_operand:SI 0 "constant_call_address_operand" ""))
	 (match_operand:SI 1 "" ""))
   (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG)
			    (match_operand:SI 2 "immediate_operand" "")))]
  "!TARGET_64BIT"
{
  if (SIBLING_CALL_P (insn))
    return "jmp\t%P0";
  else
    return "call\t%P0";
}

(define_insn "*call_1_rex64"
  [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rsm"))
	 (match_operand 1 "" ""))]
  "!SIBLING_CALL_P (insn) && TARGET_64BIT"
{
  if (constant_call_address_operand (operands[0], Pmode))
    return "call\t%P0";
  return "call\t%A0";
}

is an '@PLT' reloc machine-specific ? - yes prolly; the 'P' has to
come from i386/ somewhere ...

** No current relocations use %P - so ... no use grepping for it **

* Interestingly builtins.c (build_function_call_expr)
    + Seems to have an 'ADDR_EXPR' as it's argument to 'CALL_EXPR'
    + PLT selection must be lower down ...

varasm.c (compute_reloc_for_constant) ?

varasm.c (assemble_variable): called for:
    assemble variable 'BaseClass::_ZTV9BaseClass'
    value of compute_reloc_for_constant 'BaseClass::_ZTV9BaseClass' is 2

    -> varasm.c (output_constant):

      if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
					   EXPAND_INITIALIZER),
			      MIN (size, thissize), align, 0))
	error ("initializer for integer value is too complicated");

expr.c (expand_expr) ->
	    (expand_expr_addr_expr) -> most likely 'default:' path.

Perhaps can hook via cp/expr.c (cxx_expand_expr): ?
    cf. langhooks-def.h -> cp/cp-lang.c (lang_hooks)

varasm.c:

bool
assemble_integer (rtx x, unsigned int size, unsigned int align, int force)
{
  int aligned_p;

  aligned_p = (align >= MIN (size * BITS_PER_UNIT, BIGGEST_ALIGNMENT));

  /* See if the target hook can handle this kind of object.  */
  if (targetm.asm_out.integer (x, size, aligned_p))
    ** most likely down this path **

    -> varasm.c (default_assemble_integer):
	-> varasm.c (assemble_integer_with_op)
	    -> final.c (output_addr_const)

eg. vtable method:
varasm.c (assemble_integer) -> expand_expr_addr_expr_1 ->
    -> default_assemble_integer '      .long   '
    -> OutputAddrConst (SYMBOL_REF)
	-> assemble_name (file, XSTR (x, 0));
	    ** This is where our label is generated that
	       needs an appended '@PLT' **

** So - (perhaps) don't want to poke 'assemble_integer'
   unless we absolutely have to **

/* Used in VAR_DECLs to indicate that the variable is a vtable.
   Used in FIELD_DECLs for vtable pointers.
   Used in FUNCTION_DECLs to indicate that the function is virtual.  */
#define DECL_VIRTUAL_P(NODE) (DECL_CHECK (NODE)->decl.virtual_flag)


varasm.c(output_constant):
    at edge of assemble_integer call we have:
	exp == ADDR_EXPR
	    TREE_OPERAND(exp, 0) == FUNCTION_DECL 
	code == POINTER_TYPE
    

** Have patch to output PLT relocs for these...
    + But ... - PLT is not populated by linker (somehow).

    + The linker -appears- to fixup the @PLT relocation
      to point to something totally bogus ... ;-)
	+ should be an internal fixup + a non-symbol driven reloc ?

    + try calling across libraries ...

We end up with:
   + objdump -R app.o:

RELOCATION RECORDS FOR [.gnu.linkonce.d._ZTV8SubClass]:
OFFSET   TYPE              VALUE 
00000008 R_386_PLT32       _ZN9BaseClass5doFooEv
0000000c R_386_32          _ZN8SubClass10doFooOtherEv

With just an appended '@PLT' the vtable then holds:
    8049cc8: ff ff ea 38 [doFooEv] (broken)
    8049ccd: 08 04 87 d4 [doFooOtherEv] (correct)

suitable for a call <foo@plt> - but we want an absolute
label reference there.

bfd_howto_type -> (bfd/bfd.h) reloc_howto_struct:
cf. 
  HOWTO(R_386_PLT32, 0, 2, 32, TRUE /* pc_relative */, 0, complain_overflow_bitfield,
	bfd_elf_generic_reloc, "R_386_PLT32",
	TRUE, 0xffffffff, 0xffffffff, TRUE),
  HOWTO(R_386_JUMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
	bfd_elf_generic_reloc, "R_386_JUMP_SLOT",
	TRUE, 0xffffffff, 0xffffffff, FALSE),

  HOWTO(R_386_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
	bfd_elf_generic_reloc, "R_386_32",
	TRUE, 0xffffffff, 0xffffffff, FALSE),

** We want to generate an R_386_JUMP_SLOT instead of R_386_PLT ...
    + how to do that ?

     RELOC_NUMBER (R_386_PLT32,	    4)	/* 32 bit PLT address */
     RELOC_NUMBER (R_386_JUMP_SLOT, 7)	/* Create PLT entry */

** Unfortunately - we can't do it ... - need a new suffix: @FOO ?
    + 

cf. binutils/gas/config/tc-i386.c (lex_got):
    + fixups.


So - somehow the @PLTABS relocation is getting clobbered
    + also there are 'extended' '-fvtable-gc' relocation types:

    + Can we piggy-back off this code ?:

`-fvtable-gc'
     Emit special relocations for vtables and virtual function
     references so that the linker can identify unused virtual
     functions and zero out vtable slots that refer to them.  This is
     most useful with `-ffunction-sections' and `-Wl,--gc-sections', in
     order to also discard the functions themselves.

     This optimization requires GNU as and GNU ld.  Not all systems
     support this option.  `-Wl,--gc-sections' is ignored without
     `-static'.


** So - patch works well for this case:

    + VTable & PLT slot in main app object, (method already had
      plt entry (?))
    + we should be generating a non-symbol-driven relocation
      *per* PLT slot (surely) - since these are not relative
      jumps at all - but absolute fixups.
	    + ... Hmm ...

** Function pointer equality -
    + already an issue with the PLT -> eg elf32-i386.c:

elf_i386_finish_dynamic_symbol:
      if (!h->def_regular)
	{
	  /* Mark the symbol as undefined, rather than as defined in
	     the .plt section.  Leave the value if there were any
	     relocations where pointer equality matters (this is a clue
	     for the dynamic linker, to make function pointer
	     comparisons work between an application and shared
	     library), otherwise set it to zero.  If a function is only
	     called from a binary, there is no need to slow down
	     shared libraries because of that.  */
	  sym->st_shndx = SHN_UNDEF;
	  if (!h->pointer_equality_needed)
	    sym->st_value = 0;
	}


** Fuzzy understanding:

	+ What is a 'JUMP_SLOT' relocation we have 3 things:
		+ a plt entry
		+ a relocation pointing to it (should be relative)
	+ Does the runtime fix up use the .dyn.plt relocation data
	  to do the fixup ?: most likely ...
		+ ie. we need to output 2 relocations: 1 JUMP_SLOT
		  (done per-symbol)
		  and also 1 RELATIVE relocation - per vtable entry.
	+ we must already output 1 fixup per PLT entry - to
	  point at that PLT entry - but this is not a relocation
	  but an immediate link-time fixup (?)
		

* elf32-i386.c (elf_i386_relocate_section):
	+ looks interesting - PLT code very light.

	+ bfd_elf32_swap_reloc_out -> (bfd/elflink.h)

/* Translate an ELF reloc from internal format to external format.  */
void
elf_swap_reloc_out (bfd *abfd,
		    const Elf_Internal_Rela *src,
		    bfd_byte *d)
{
  Elf_External_Rel *dst = (Elf_External_Rel *) d;
  H_PUT_WORD (abfd, src->r_offset, dst->r_offset);
  H_PUT_WORD (abfd, src->r_info, dst->r_info);
}

void
elf_swap_reloca_out (bfd *abfd,
		     const Elf_Internal_Rela *src,
		     bfd_byte *d)
{
  Elf_External_Rela *dst = (Elf_External_Rela *) d;
  H_PUT_WORD (abfd, src->r_offset, dst->r_offset);
  H_PUT_WORD (abfd, src->r_info, dst->r_info);
  H_PUT_SIGNED_WORD (abfd, src->r_addend, dst->r_addend);
}


* JUMP_SLOT relocation:
	+ offset points into .got.plt
		+ allows that to be fixed up idly.
		+ .rel.plt - contains symbol index to do fixup
	+ contents of <.got.plt> is
		+ <raw address> -> jump back into
		  equivalent PLT code

    ** creating a jump-slot (PLT) reloc **
	+ write reloc itself to /.rel.plt/
		-> /.got.plt/
		+ the reloc allows .got.plt to be relocated
		  with the library.
	+ create /.plt/ record
		+ assign index -> /.got.plt/ etc.
	+ write /.got.plt/ record
		+ initially points into relevant /.plt/ record
	+ <foreach referrer to symbol>
		+ create relative address to that code
		+ ie. call 790 <fprintf@plt> (pc-relative)

    ** normal PLT code: 

** The input code has:

RELOCATION RECORDS FOR [.gnu.linkonce.d._ZTV9BaseClass]:
OFFSET   TYPE              VALUE 
00000008 R_386_PLT32ABS    _ZN9BaseClass5doFooEv
0000000c R_386_PLT32ABS    _ZN9BaseClass5countEv
00000010 R_386_PLT32ABS    _ZN9BaseClassixEi
	 ie. the .d._ZTV9BaseClass is a section.
	 each of these is a location we want to add an
	 R_386_RELATIVE to.

** Dynamic linker:
   glibc/elf/do-rel.h: (elf_machine_lazy_rel)
   cf. glibc/sysdeps/i386/dl-machine.h
	+ a JUMP_SLOT reloc has:

__attribute__ ((always_inline))
elf_machine_lazy_rel (struct link_map *map,
		      Elf32_Addr l_addr, const Elf32_Rel *reloc)
{
  Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
  /* Check for unexpected PLT reloc type.  */
  if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
    {
      if (__builtin_expect (map->l_mach.plt, 0) == 0)
	*reloc_addr += l_addr;
      else
	*reloc_addr = (map->l_mach.plt
		       + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4);
    }
  else
    _dl_reloc_bad_type (map, r_type, 1);
}
	This fixup occurs on the GOT reference.
called from dynamic-link.h: ELF_DYNAMIC_DO_REL,
and ELF_DYNAMIC_RELOCATE from glibc/elf/dl-reloc.c (_dl_relocate_object)

	'lazy' is only set for DT_PLTREL sections,
	not DT_RELOC ones.

	Otherwise (glibc/elf/do-rel.h):
	  for (; relative < r; ++relative)
	    DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);

	+ The runtime dylinker is very simple.


** The fixup of the original PLT32ABS address must be in
   elf32-i386.c [ or outside using the reloc_howto_type data ]

via: ?

** Callers of elf_i386_reloc_type_lookup:

	static reloc_howto_type *
	elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
				    bfd_reloc_code_real_type code)
	#define bfd_elf32_bfd_reloc_type_lookup	      elf_i386_reloc_type_lookup
		called via:
	reloc_howto_type *bfd_reloc_type_lookup
	   (bfd *abfd, bfd_reloc_code_real_type code);

bfd/elf.c (_bfd_elf_validate_reloc) calls this ...
	( just for convert non elf to elf relocs ? )

bfd/linker.c:
	/* Create a relocation.  */
	bfd_boolean
	_bfd_generic_reloc_link_order (bfd *abfd,
			       struct bfd_link_info *info,
			       asection *sec,
			       struct bfd_link_order *link_order)
bfd/reloc.c:
	+ (bfd_reloc_type_lookup): implemented - jump via vtable.

	* The hooks themselves point to:
		bfd_elf_generic_reloc

* TLS docs: (not useful): http://people.redhat.com/drepper/tls.pdf

linker.c: has some great docs at the top:

	+ it seems reloc processing all happens in the final
	  stage. (_bfd_generic_final_link)

	+ need to bump up bfd_get_reloc_upper_bound ...

** TODO:
   + the elf_i386_relocate_section method needs the fixup:
	+ iterates over the input_section relocs ...
	    + foo ! :-)
	+ this must do the in-line fixups for each source
	  PLT32ABS - get it right ...
	+ just need to output the R_386_RELATIVE here (?)
	  (need allocated space for it though (?))

*** ARGH - too much pain ...

A new approach ?
    + output: yet more inefficiency & brokenness:
	.long _Z.....Slot
    + later:
	.long _Z.....Slot attribute 'hidden' etc.
		jmp foo@plt
    + nasty: whacks a NULL in the vtable but does
             insert a relocation of the right type.

	.section        .text.stubs
	.align 2
_ZN8SubClass5doFooEvStub:
	jmp		_ZN8SubClass5doFooEv@plt

Wow - adds even, even more inefficiency ;-)

    * But trivial - requires no linker changes & => worthwhile.


* gennorm investigation:
    * re-building the library with -O0 - doesn't make it work.
    * 
    * running 'gennorm' in icu fails with '-O' - but not if built with -O0

    + re-building just the .cpp with -O0 - fails ...

Breakpoint 1, uset_contains_2_6 (set=0x822d2a8, c=136499880) at uset.cpp:152
152         return ((const UnicodeSet*) set)->contains(c);
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb) bt
#0  0x00000000 in ?? ()
#1  0x400a2076 in uset_contains_2_6 (set=0x822d2a8, c=193) at uset.cpp:152
#2  0x0804b5a6 in postParseFn (context=0x0, code=193, norm=0x4033666c) at store.c:1110

    ** Seems clear that the vtable entry there is NULL ...

So - the call is correct:

ends up in:

00099451 <_ZNK7icu_2_610UnicodeSet8containsEiiSlot>:
   99451:	e9 5e fc f8 ff       	jmp    290b4 <_ZNK7icu_2_610UnicodeSet8containsEii@plt>
Disassembly of section text._ZNK7icu_2_610UnicodeSet11containsAllERKS0_:

goes to:

000290b4 <_ZNK7icu_2_610UnicodeSet8containsEii@plt>:
   290b4:	ff a3 30 09 00 00    	jmp    *0x930(%ebx)
   290ba:	68 48 12 00 00       	push   $0x1248
   290bf:	e9 50 db ff ff       	jmp    26c14 <_init+0x18>

** Most probable **:
    + %ebx adjustment/assignment is not working ...

0008292e <uset_contains_2_6>:
   8292e:	55                   	push   %ebp
   8292f:	89 e5                	mov    %esp,%ebp
   82931:	83 ec 08             	sub    $0x8,%esp
   82934:	8b 55 08             	mov    0x8(%ebp),%edx
   82937:	8b 0a                	mov    (%edx),%ecx
   82939:	8b 45 0c             	mov    0xc(%ebp),%eax
   8293c:	89 44 24 04          	mov    %eax,0x4(%esp)
   82940:	89 14 24             	mov    %edx,(%esp)
   82943:	ff 51 1c             	call   *0x1c(%ecx)
   82946:	0f be c0             	movsbl %al,%eax
   82949:	c9                   	leave  
   8294a:	c3                   	ret    
   8294b:	90                   	nop    

    * As is the case ! ...

    (doh) ...

gcc/config/i386/i386.c (output_set_got) 
    + sets up %ebx 

    (ix86_expand_prologue): calls (gen_set_got) - looks hopeful.

gcc/config/i386/i386.c (ix86_expand_prologue):
  pic_reg_used = false;
  if (pic_offset_table_rtx
      && (regs_ever_live[REAL_PIC_OFFSET_TABLE_REGNUM]
	  || current_function_profile))

** What are:
    + current_function_profile
	+ profiling hard-core goodness ...
    + pic_offset_table_rtx
	+ seems to be set if -fPIC is enabled otherwise not.
    + regs_ever_live ?

ix86_expand_prolog (nil) 0
ix86_expand_prolog (nil) 0
ix86_expand_prolog 0x4017f3f0 1
ix86_expand_prolog 0x4017f3f0 1
ix86_expand_prolog (nil) 1

    

gcc/function.h:
    + 'unsigned int uses_pic_offset_table : 1'
	+ used while generating the code - did this fn.
	  use the pic offset ?
    + ie. red-herring - only set in the config/ backends.

  /* If we are doing position-independent code generation, now
     is the time to output special prologues and epilogues.
     We do not want to do this earlier, because it just clutters
     up inline functions with meaningless insns.  */
read FINALIZE_PIC ...

*** URGH ......
    + We have no idea what library the vtable is in:
	=> there is no way we can setup the got properly ...
	=> we have to generate different code ...

We need to emit something like:

_ZN8SubClass5doFooEvSlot:
    push    %ebx
    subl    $4, %esp
    call    __i686.get_pc_thunk.bx
    addl    $_GLOBAL_OFFSET_TABLE_, %ebx
    call    _ZN8SubClass5doFooEv@plt
    addl    $4, %esp
    pop	%ebx
    ret

    ie. a proper stub function ...

    Unfortunately the %esp adjustment necessary to read / calc the
base-ptr offset is arg. list length dependant => we need some more
heavy lifting; furthermore - we want to pass our arguments on
un-changed [ => can't screw with the stack ... ] (without a highly
painful copy in / out).

    Read up on how the PLT works ... - must have the same problems ...

    it does a jmp absolute(0x...)-> got -> push <immediate-idx>,
jmp <foo>, push <immediate>, jmp GOT+1

00000868 <plt0>:
 868:	ff b3 04 00 00 00    	pushl  0x4(%ebx)
 86e:	ff a3 08 00 00 00    	jmp    *0x8(%ebx)
 874:	00 00                	add    %al,(%eax)
 876:	00 00                	add    %al,(%eax)


    Calls (via trampoline) into
    'glibc/dl-runtime.c (fixup)'

glibc/sysdeps/i386/dl-machine.h
    #  define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
	.text\n\
	.globl _dl_runtime_resolve\n\
	.type _dl_runtime_resolve, @function\n\
	" CFI_STARTPROC "\n\
	.align 16\n\
_dl_runtime_resolve:\n\
	" CFI_ADJUST_CFA_OFFSET (8) "\n\
	pushl %eax		# Preserve registers otherwise clobbered.\n\
	" CFI_ADJUST_CFA_OFFSET (4) "\n\
	pushl %ecx\n\
	" CFI_ADJUST_CFA_OFFSET (4) "\n\
	pushl %edx\n\
	" CFI_ADJUST_CFA_OFFSET (4) "\n\
	movl 16(%esp), %edx	# Copy args pushed by PLT in register.  Note\n\
	movl 12(%esp), %eax	# that `fixup' takes its parameters in regs.\n\
	call fixup		# Call resolver.\n\
	popl %edx		# Get register content back.\n\
	" CFI_ADJUST_CFA_OFFSET (-4) "\n\
	popl %ecx\n\
	" CFI_ADJUST_CFA_OFFSET (-4) "\n\
	xchgl %eax, (%esp)	# Get %eax contents end store function address.\n\
	ret $8			# Jump to function address.\n\
	" CFI_ENDPROC "\n\

	ret $8 - cunning trick to return from the fn -> but
really call another fn. / peel back the stack ...

* Question - how does the get_pc_thunk.bx method work:

	.section	.gnu.linkonce.t.__i686.get_pc_thunk.bx,"axG",@progbits,__i686.get_pc_thunk.bx,comdat
.globl __i686.get_pc_thunk.bx
	.hidden	__i686.get_pc_thunk.bx
	.type	__i686.get_pc_thunk.bx, @function
__i686.get_pc_thunk.bx:
	movl	(%esp), %ebx
	ret

	* Seems to fetch from stack 
	    * AH! - we 'call' (%esp) => pushes current PC -> stack

    + Quandry:
	+ we can't store %ebx on the stack
	    + need to have %ebx setup right - but can't ...
	+ can we call fixup ourselves & then chain ?
	    + compare vs NULL first ?
	    + [ ugly but ... ]

	+ ie. duplicate the PLT entry for that symbol [tough]
	    + can we use the instruction pointer in some addressing mode ?
	+ can we jump straight into the GOT ?
	    + nope plt0 requires %ebx.


    + Output:
	+ have to have a symbol index per symbol -
	  tough wrt. linker changes (?) - done for PLT
	  currently though.


* Good news:
  fprintf (stderr, "Vfunc ptr %p\n", &(pClass->doFoo));
  app.cxx:35: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&BaseClass::doFoo'

* So we can fiddle with that pointer value as much as we like.


** Fuller design **:

    *** development-gcc@suse.de ***
	+ -foo-

    + .rel.plt contains symbol indexes to do the fixup ...
    + .got.foo: target for relocations when done ...

    + Finding the index into the vtable:
	+ we only call this once => it can be extremely slow ... *
	+ the tail part of the PLT foo:
	    + push $<plt-offset>
	    + jmp <rel> _ZTV...<Init>
	+ [ would prefer to have it in a register ]
	    + [ but then unused in the common case ? ]

    + Can we do the fixup & then 
	+ We need an entirely new relocation type / more sections:
	    + PLT fixup's relocations have 1 offset: index into table.
	+ .got
	    .long 00
	    .long 00
	    .long 00 <will be vlt fixup fn.>
	+ .data
	    + _ZTV3Foo:
		.long _doFoo@vlt
		.long _doBaa@vlt
	+ .rel.vlt
	    + JUMP_SLOT 'doFoo'
	    + JUMP_SLOT 'doBaa' ...
	+ .vlt (ronly?)
	    _fixup@vlt: [ slot 0 ]
		pushl %ebx
		call __i686.get_pc_thunk.bx:
		jmp *0x12(%ebx) // another magic GOT slot ?
		
	    _doFoo@vlt:	    
		pushl $<index into rel.vlt of JUMP_SLOT relocation>
		pushl $<address-of-vtable-slot> [ needs fixup but ... ]
		// better to push just the slot offset ? we have
		// this->_vtable_ptr of course.
		jmp _fixup@vlt
		
		

// potential optimisations:
    + build whole vtable at once on 1st method call ...
    + copy parent
    + emit only JUMP_SLOTs for overridden methods ...


** 2 approaches:

    + emit a 'vtable_construction' function per method...
	+ have static/ro data in that ?
	+ and 1 symbol ... (?)

    + have a 'ClassInit' symbol:
_ZN9BaseClassC2Ev:
.LFB30:
	.file 1 "lib.cxx"
	.loc 1 5 0
	pushl	%ebp
.LCFI0:
	movl	%esp, %ebp
.LCFI1:
	call	.L2
.L2:
	popl	%ecx
	addl	$_GLOBAL_OFFSET_TABLE_+[.-.L2], %ecx
	.loc 1 5 0
.LBB2:
	movl	8(%ebp), %eax
	movl	_ZTV9BaseClass@GOT(%ecx), %edx
	leal	8(%edx), %edx
	movl	%edx, (%eax)
	.loc 1 6 0
	movl	8(%ebp), %eax
	movl	$3, 4(%eax)
	.loc 1 7 0
	popl	%ebp
	ret

	call 'SetupVTable'

    + how can we hook that ?

        gcc/cp/class.c (build_vtbl_initializer)
	    + builds the _ZTV vtable init
	    + needs re-working/cut/pasting to output
	      something else.
	    + (build_vtbl_ref) - looks interesting.
	    + (set_linkage_according_to_type) - also interesting.

	+ clearly (?) - the copy-constructor doesn't
	  need this fixup ...
    + Nice feature:
	+ we can do this optimisation for -only- the simplest
	  cases & leave the relocations in-place for more
	  complex cases. VTTs etc

    + gcc/cp/init.c (build_vtbl_address):
	+ builds address reference for vtable ptr.
	+ (expand_virtual_init): bingo wrt. vtable ptr setup.
	    + 

    + gcc macro unwinding help: eg.
	http://theoryx5.uwinnipeg.ca/gnu/gcc/gxxint_5.html

    + gcc compiled with --enable-checking ...
	+ lots of nice error checking.

    + init.c (expand_virtual_init) - called once per vtable base ptr.
	<- (dfs_initialize_vtbl_ptrs): list callback
	    <- (initialize_vtbl_ptrs)
		<- [ called from decl.c: destructor emission  ]
		<- (emit_mem_initializers)
		    <- semantics.c (finish_mem_initializers)

    + semantics.c (finish_mem_initializers)
	<- method.c (do_build_copy_constructor, synthesize_method)
	<- parser.c (cp_parser_ctor_initializer_opt),
	<- parser.c (cp_parser_mem_initializer_list)
	<- pt.c (tsubst_expr) - case CTOR_INITIALIZER

    + How is the existing vtable data built ?
	+ class.c (build_vtbl_initializer) - build inits.
	    <- (dfs_accumulate_vtbl_inits) - iterator callback ...
		<- (accumulate_vtbl_inits) 
		    <- (finish_vtbls)
		    <- (build_ctor_vtbl_group)

    + class.c (finish_vtbls) [ <- (finish_struct_1) ]
	+ seems to call (initialize_vtable) to do the
	  actual output.
	+ can we generate what we want from the existing
	  list ?
	+ (intialize_artificial_var) ...
	    + sets up the decl itself variously ...
	    + seems to expose via BINFO_VTABLE member
	    + Appending to: 
		+ TREE_CHAIN (decl) = TREE_CHAIN (CLASSTYPE_VTABLES (type));
		+ seems to cause bits to get generated ...

    + The real output of all this foo is in:
	decl2.c (maybe_emit_vtables)
	    + walks the CLASSTYPE_VTABLES chain ...
    + TODO: work out where the rtti data gets output ...
	/mangle_typeinfo_for_type/

	+ poke at all CLASSTYPE_VTABLES hits
	    + update with CLASSTYPE_VTABLE_DESCRS ...
		+ foo ...

    + GCC debug / warning output
	: '%q' == 'quote'
	    : <installable format translators ...>
	    : c-objc-common.c: (c_tree_printer)
		'%D' : a general decl
		'%E' : an identifier or expr.
		'%F' : a function decl.
		'%T' : a type
	    : cp/error.c (cp_printer):
		%A   function argument-list.
		%C	tree code.
		%D   declaration.
		%E   expression.
		%F   function declaration.
		%L	language as used in extern "lang".
		%O	binary operator.
		%P   function parameter whose position is indicated by an integer.
		%Q	assignment operator.
		%T   type.
		%V   cv-qualifier.
  

    + need a pointer from vtable -> description
        + append it to the Type Info ?
	    + [ need to force TI generation too ...]
	+ slowish search ?
	+ ...
    + need to deal with internal relocs too [via TI?]
	+ how do we nagivate the TI ?
	    [before?]
	+ The TI pointer - has all the base-class information
	    [ wrt. copying etc. ]
	    + [ understand it's layout ]
	    + [ must have size info too - to walk it ]
	    + can we append stuff ?

    + can we clobber .got.plt ?
	+ [ or are those mangled in some way ? ]
    + where is .rel.dyn created ?

* Where is .rel.dyn created ?
  ld/eelf_i386.c:
  .rel.dyn        :\n\
    {\n\
      *(.rel.init)\n\
      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)\n\
      *(.rel.fini)\n\
      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)\n"
"      *(.rel.data.rel.ro*)\n\
      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)\n\
      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)\n\
      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)\n\
      *(.rel.ctors)\n\
      *(.rel.dtors)\n\
      *(.rel.got)\n\
      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)\n\
    }\n\

    + looks like all those rel. sections get merged ...
        => add to rel.got like a swine ... (check special cases?)=======

** Type info pieces:
    http://www.codesourcery.com/cxx-abi/abi.html#rtti

Every virtual table shall contain one entry that is a pointer to an
object derived from std::type_info. This entry is located at the word
preceding the location pointed to by the virtual pointer (i.e., entry
"-1"). The entry is allocated in all virtual tables; for classes
having virtual bases but no virtual functions, the entry is zero.

We add one pointer to the std::type_info class in addition to the
virtual table pointer implied by its virtual destructor:


Hence we see:

_ZTI11AnotherBase:
        .long   _ZTVN10__cxxabiv117__class_type_infoE+8
        .long   _ZTS11AnotherBase

_ZTI8SubClass:
	.long	_ZTVN10__cxxabiv121__vmi_class_type_infoE+8
	.long	_ZTS8SubClass
	.long	0
	.long	2
	.long	_ZTI9BaseClass
	.long	2
	.long	_ZTI11AnotherBase
	.long	2050

1 inheriting from __class_type_info and
1 from __vmi_class_type_info


** Look at obj-prelink some more ...
    + do we really need to hook the TI ?
	+ can we not do something more interesting ?


** Switch to binutils hackage
    + can we use the obj-prelink approach here to
      get a quick prototype ?


0x90 - nop ...

static char stub0[] = 
{
  0x68, 0, 0, 0, 0,                     /* push $junk */
  0x68, 0, 0, 0, 0                      /* push $junk */
};

static char stub[] = 
{
  0xe9, 0xfc, 0xff, 0xff, 0xff,         /* jmp xxx@PC */
  0x68, 0, 0, 0, 0                      /* push $junk */
};

** bfd_put32 - doesn't output a reloc [!]
    + also - it needs space ...

elfcode.h (elf_swap_reloc_out):
void
elf_swap_reloc_out (bfd *abfd,
		    const Elf_Internal_Rela *src,
		    bfd_byte *d)
{
  Elf_External_Rel *dst = (Elf_External_Rel *) d;
  H_PUT_WORD (abfd, src->r_offset, dst->r_offset);
  H_PUT_WORD (abfd, src->r_info, dst->r_info);
}

H_PUT_WORD -> H_PUT_32 -> bfd.h (bfd_h_put_32)
#define bfd_h_put_32(abfd, val, ptr) \
  BFD_SEND (abfd, bfd_h_putx32, (val, ptr))

=> do need section address ...

    + Where do we swap this reloc to !?
    + elf_i386_check_relocs:
	+ allocates more space: ->count += 2;
	+ [ in struct elf_i386_dyn_relocs *p; ]

    + Understand how we can allocate those relocs
	+ somewhere there must be the section with
	  them in it [!] (?)
	+ are they contiguous or scattered ?
	+ how does sorting fit into that ?

** Questions:
    + what does the p->count++ increase the size of ?
    + allocate_dynrelocs (?)
	+ eventually does:
	  /* Finally, allocate space.  */
	  for (p = eh->dyn_relocs; p != NULL; p = p->next)
	  {
	    asection *sreloc = elf_section_data (p->sec)->sreloc;
	    sreloc->size += p->count * sizeof (Elf32_External_Rel);
	  }
	+ So - we need to know what section our reloc is in (?)
	    + all from the same section ?
	    + how then to calculate the offset ?
	    + can we piggy back on some other section ?

** State of the art is:
    + gcc-vtplt.diff + binutils-objprel.diff:
	+ missing relocs for .plt[0] though.

    + problems:
	+ - we only need 1 RELATIVE reloc per PLT entry ...
	    + or do we ?
	+ relocs to wrong address ?
	    + no reloc for base plt entry ...
	+ jmp $08(%esp) ?
	    + after a push / stack-adjust ?
	    + or ... [contents of ...]

	+ Asm syntax:
	    + absolute (vs. PC relative) jumps prefixed by '*'
	    + 

    + Install older bfd tools & build a
      working objprelink2
	+ compare output ...


+ Comparison:
	+ fn pointer comparison problems (still)
	+ extra pages written - extra unshared data
		+ [size of plts]
			+ [ with symbol visibility ?]
	+ relocation counts:
		+ before/after

	+ Mathematics:
		+ not every vtable slot is looked up 
			+ [cache]
		+ assume perfect symbol/visibility markup
			=> every external symbol is used somewhere
				[ very unlikely ]
			=> distorts scaling ... (?)
		+ partition every N vtable symbols into a discrete library ...

		+ N = vtable_methods
		+ k = methods-per-library
		+ num_libs = N/k

		+ symbol lookup complexity = N * num_libs * log (N)
		+ R - number of times class is re-used outside library ...
			+ R ~= log (num_libs)

		+ difference between proportion overridden &
		  proportion new V slots - 60% -> 80% ?

		+ so - each of N vtable methods is looked up R * 80% times each
			+ ie. 0.8 * N log (N/k)
			

		+ => total cost = lookup_cost * num_lookups
			        = N/k * log (N) * N * (1 + log (N/k) )




