Performance: + create a small test library + find some genuinely weak / duplicate symbols in OO.o ... + add annotation etc. to that + checkout vtable instantation etc. We are still doing too much work with symbol lookup + most of it highly avoidable. + ~95% is relocation processing ... + fn relocations ... + populating vtable: + looking up global / weak symbols [ why ? ] + [ can they not be -Bsymbolic or something ? ] + if 'dllexport' or the visibility attribute are used - we should/could hide local vtable lookup bits ? + we want the symbols to be 'protected' so they are exported - by are resolved internally to symbol-freea relocations + The whole thing is crazy: + we need only 1 'get-vtable' method per class ... + Mark all 'virtual' methods of (SPECIFIED && DEFAULT) linkage as 'protected' - ditto for generated thunks (?) + Understand the weak symbol issue [!?] + add a throw/catch ... fprintf (file, " %c%c%c%c%c%c%c", ((type & BSF_LOCAL) ? (type & BSF_GLOBAL) ? '!' : 'l' : (type & BSF_GLOBAL) ? 'g' : ' '), (type & BSF_WEAK) ? 'w' : ' ', (type & BSF_CONSTRUCTOR) ? 'C' : ' ', (type & BSF_WARNING) ? 'W' : ' ', (type & BSF_INDIRECT) ? 'I' : ' ', (type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ', ((type & BSF_FUNCTION) ? 'F' : ((type & BSF_FILE) ? 'f' : ((type & BSF_OBJECT) ? 'O' : ' ')))); + Weak symbols generated by: + Templates ... + Reference type stuff ... + non-virtual thunks + type info (_ZTI) + vtables (_ZTV) + [all to do with typeinfo behavior] + re-read: http://www.nedprod.com/programs/gccvisibility.html very carefully ... + Can we annotate the source with 'protected' for most methods ? + parent chaining ? + doesn't go via vtable - but direct fn. call ... + Looks like we do all those bindings (relocs?) + at dlopen time [!?] [ 10k relocations building vtables ? ] + need to check vs. gcc-4.x ... [ should be able to prune ... ] Thoughts: (problem/soln/problem/...) + the deep / vcl OutputDevice -> Window -> Control -> ... vtable building issue is bad, bad news. + why can't we get/copy the parent's vtable with 'memcpy' ? instead of lots of lookups ? + can we parallelise the linker ? + this problem is easily partitionable, surely ... + [ no thread support in the linker ... ] + a 'thunk' fn does: + adjust 'this' pointer & call method [ and MI feature ] + Things to check: + anonymous namespaces ... - file path mangled in ? ** Parent / Copy VTables ... ** + Use: options to dump tree data to aid debugging. -fdump-class-hierarchy[-N] + With this we get: cp/class.c (dump_vtable): eg. Vtable for SubClass SubClass::_ZTV8SubClass: 9u entries 0 (int (*)(...))0 4 (int (*)(...))(& _ZTI8SubClass) 8 SubClass::doFoo 12 BaseClass::count 16 BaseClass::operator[] 20 SubClass::doAnother 24 (int (*)(...))-0x000000008 28 (int (*)(...))(& _ZTI8SubClass) 32 SubClass::_ZThn8_N8SubClass9doAnotherEi Called from: + cp/class.c (initialize_vtable) + We need to identify simple cases somewhere here & eliminate sillies. /* Make BINFO's vtable have N entries, including RTTI entries, vbase and vcall offsets, etc. Set its type and call the backend to lay it out. */ static void layout_vtable_decl (tree binfo, int n) /* Virtual function table initialization. */ /* Create all the necessary vtables for T and its base classes. */ static void finish_vtbls (tree t) Calls: /* Initialize the vtable for BINFO with the INITS. */ static void initialize_vtable (tree binfo, tree inits) * It seems initializer ordering is unpredictable: works: extern ParamFoo aBaa; ParamFoo aBaa; StaticInit aStatic(aBaa); doesn't work: extern ParamFoo aBaa; StaticInit aStatic(aBaa); ParamFoo aBaa; * Initialization etc. bits: http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gccint/Initialization.html .ctors section. + find something that puts code in the .ctors section (?) Emit a fn. that will do the construction (?) + make it a .ctor (?) */ static void finish_vtbls (tree t) Calls: /* Initialize the vtable for BINFO with the INITS. */ static void initialize_vtable (tree binfo, tree inits) * It seems initializer ordering is unpredictable: works: extern ParamFoo aBaa; ParamFoo aBaa; StaticInit aStatic(aBaa); doesn't work: extern ParamFoo aBaa; StaticInit aStatic(aBaa); ParamFoo aBaa; * Initialization etc. bits: http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gccint/Initialization.html .ctors section. + find something that puts code in the .ctors section (?) Emit a fn. that will do the construction (?) * Avoid duplicate VTable construction: + need to hook the vague linkage constructs: http://m68hc11.serveftp.org/doc/gcc_6.html + but for methods [ ie. same as 'inline' methods ?! ;-] + 1st step: + get gcc to emit a constructor call to a custom fn ... + 2nd step + generate bit-masks & impl. that function to do a copy + 3rd step + generate that fn. internally ** Ordering: + absolutely critical ... + to make it efficient: + have to copy from direct parents only => have to ensure the parent is initialized (copied) itself first ... + have to copy only once + Linker support ... ** Assumption: + it will ~always be more compact and efficient to do vtable copies ourself (in shared libraries) + we can make this dependent on -fPIC ... ** Minimality + is it possible to do the ordering without binutils support ? + we could call a 'weak' parent 'copyVTable' method (if present) + each constructor: + initVTable + emit a constructor call to that + let initialization sort it out (?) + [ would that break stuff ?] + how bad would that be ? + can we add support to elide duplicate constructors in binutils ? + could we do (idle) vtable construction on 1st class instance use ? + might be somewhat bloating & evil. + OTOH currently ~valid - since no parent use without foo ? + With binutils support: + can call a minimal number of fn's ... + but more difficult (?) ... + the 'sort' is easy + need code walk-through; + where are vtables emitted (by the backend) [!?] + can be made more succinct + can be made .rodata (?) + then needs glibc support [?] + [ for symbol lookup ? ] ** Questions: + what forms of symbol / invocation ellision can we use ? + I -like- the idea of an 'initVTable' method being called (with ~weak stuff?) + isolates the fix in g++ itself, with no binutils/glibc pain. + in gcc: where is the vtable building code ? + class.c: initialize_vtable + [ initialize_artificial_var (...) + class.c: (build_vtbl_initializer) + sets up BINFO_VTABLE - (an expression that points at an offset into the vtable ]. + class.c ( + in gcc: where is the vtable emission code ? + + helpful blurb: Define accessor macros for information about type inheritance and basetypes. A "basetype" means a particular usage of a data type for inheritance in another type. Each such basetype usage has its own "binfo" object to describe it. The binfo object is a TREE_VEC node. Inheritance is represented by the binfo nodes allocated for a given type. For example, given types C and D, such that D is inherited by C, 3 binfo nodes will be allocated: one for describing the binfo properties of C, similarly one for D, and one for describing the binfo properties of D as a base type for C. Thus, given a pointer to class C, one can get a pointer to the binfo of D acting as a basetype for C by looking at C's binfo's basetypes. */ * Considerations: + Information + Representaiton + Data sharing + Space efficiency M-x set-variable\ntab-width 8 What I implemented until then was just some dumping routines in the frontend to see how and where it put together the member method decls, and if it were a overrider, or something inherited. Then I thought about it, and thought the whole complicateness is not needed anymore anyway, then we spoke about it, then I thought again that it's needed, but never returned to do something on it. But the patch for getting a feel in cp/class.c is somewhere ... ~matz/copy-vtable/diff What's left is a multitude of stuff: 1) remembering in lists-per-class, where the overriders were, 2) emitting a decl for that list, which could be interpreted at runtime, 3) writing the runtime support to interpret all these lists, 4) make ld.so call that runtime support before everything else (also before other static ctors) * So + we can (I think correctly) identify the slots we want to copy * Next: + generating a new section: + read the constructor code ... + decl2.c - remember ? - RTL generation etc. ? :-) ./gcc/cp/decl2.c:#define SSDF_IDENTIFIER "__static_initialization_and_destruction" ./gcc/cp/decl2.c: char id[sizeof (SSDF_IDENTIFIER) + 1 /* '\0' */ + 32]; ./gcc/cp/decl2.c: SSDF_IDENTIFIER_. */ ./gcc/cp/decl2.c: sprintf (id, "%s_%u", SSDF_IDENTIFIER, count); ./gcc/cp/cp-tree.h:extern GTY(()) tree static_aggregates; static_aggregates = tree_cons (init, decl, static_aggregates); while (*var) { tree t = *var; tree decl = TREE_VALUE (t); tree init = TREE_PURPOSE (t); *var = TREE_CHAIN (t); TREE_CHAIN (t) = result; } ** We need an intermediate representation (!?) + trees of what ? + 2 tree pairs ? + source & dest ? + source == ptr to vtable + offset ... + [ can we make an offset expression ? - perhaps ... ] + dest == ptr to vtable + offset ... + can we use DECL_VINDEX instead ? [ then we have it all ] + just store the fn ptr ? + do we duplicate the fn. decls per vtable ? + Then sort/crunch these on output ... + + cp_finish_decl builds 'static_aggregates' + Question: + is there a different fn. decl per vtable slot assignment ? - with a different DECL_VINDEX ? + since we assign DECL_VINDEX on a BV_FN(fn): + it must be ... for (vindex = 0, fn = BINFO_VIRTUALS (TYPE_BINFO (t)); { tree fndecl = BV_FN (fn); ... DECL_VINDEX (fndecl) = build_int_cst (NULL_TREE, vindex); } + in vtbl_initialize - 'fn' - is the BV_FN ... + Is there already a list of vtables we can come back to & operate on later (at emission time ?) ... + why not build one ? & operate on it later ? + First build simple list: + then re-consider: can we post-generate this ? + can we just sort binutils to ensure that no source address is read before a dest is written (?) + then sort read/writes etc. ** Global vars etc. & sorting + interestingly a compile emits: .globl __gxx_personality_v0 Foo aGlobal; Baa aBaa; compiles to: .type _Z41__static_initialization_and_destruction_0ii, @function _Z41__static_initialization_and_destruction_0ii: .text .align 2 .type _Z41__static_initialization_and_destruction_0ii, @function _Z41__static_initialization_and_destruction_0ii: .LFB9: pushl %ebp .LCFI14: movl %esp, %ebp .LCFI15: subl $24, %esp .LCFI16: movl %eax, -4(%ebp) movl %edx, -8(%ebp) cmpl $1, -4(%ebp) jne .L13 cmpl $65535, -8(%ebp) jne .L13 movl $aGlobal, (%esp) call _ZN3FooC1Ev movl $aBaa, (%esp) call _ZN3BaaC1Ev .L13: leave ret .LFE9: .size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii .align 2 .type _GLOBAL__I_aGlobal, @function _GLOBAL__I_aGlobal: .LFB10: pushl %ebp .LCFI17: movl %esp, %ebp .LCFI18: subl $8, %esp .LCFI19: movl $65535, %edx movl $1, %eax call _Z41__static_initialization_and_destruction_0ii leave ret .LFE10: .size _GLOBAL__I_aGlobal, .-_GLOBAL__I_aGlobal binutils/ld/ldctor.c (ctor_prio): + gets the priority of a g++ global constructor (or destructor) from the symbol name + [ gets an integer prio. from the symbol name ] + these functions are sorted (somehow) + ldctor_build_sets: + this is what builds the constructor_list ... + [ linker script 'CONSTRUCTORS' command (?) ] + FIXME: what good are linker scripts ? + what function do they serve ? binutils: http://www.gnu.org/software/binutils/manual/ld-2.9.1/html_chapter/ld_3.html gcc/collect2.c: /* Collect static initialization info into data structures that can be traversed by C++ initialization and finalization routines. */ + Interesting [!] ** Generate at least some data out ... & a _GLOBAL_ thing ... * Debugging: eg. gdb /data/opt/gcc/bin/../libexec/gcc/i686-pc-linux-gnu/4.1.0/cc1plus * COMDAT linkage /* With weak symbols, we simply make the variable COMDAT; that will cause copies in multiple translations units to be merged. */ comdat_linkage (decl); + Question: is this an overlaying merge or can it be more complex ? [ appending eg. ] * Assertion failed: 4079 if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE) 4080 { 4081 /* An automatic variable with an incomplete type: that is an error. 4082 Don't talk about array types here, since we took care of that 4083 message in grokdeclarator. */ 4084 error ("storage size of %qD isn't known", decl); ** We initialize the artificial var + but ... how is it output ? ** Have we got the initialization for this thing right ?! ** TODO: + emit a '_GLOBAL_...?' fixup function - with a 'magic' priority ? so it gets sorted first-of-all (!?) + terminate the copy constructor foo ... + run a simple test with a single constructor ? + create a .ctors section ? ** binutils/ld/ldctor.c: + ldctor_add_set_entry is called a lot ... + can we trigger the binutils feature on the presence of compiler emitted 'magic' symbols ? [ fun ... ] (nicer for sure !) + Can we re-arrange the sections ? + or is this information lost by this time ? + can we extract & move stuff ? + what is possible at link time ? crtbegin.c: /* Specialized bits of code needed to support construction and destruction of file-scope objects in C++ code. Copyright (C) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Ron Guilmette (rfg@monkeys.com). ** Wow - gcc/crtstuff.c + looks like an ideal place to put this stuff ... eg.: STATIC func_ptr __CTOR_END__[1] __attribute__((section(".ctors"), aligned(sizeof(func_ptr)))) = { (func_ptr) 0 }; ** Generating our own section: + gcc/except.c (default_exception_section) + named_section_flags (".gcc_except_table", flags); + -> TARGET_ASM_EXCEPTION_SECTION -> target-def.h ( We get std. decls into other sections (somehow) with: surely ? TARGET_ASM_CONSTRUCTOR, \ TARGET_ASM_DESTRUCTOR, \ gcc/c-decl.c: c_expand_body ... varasm.c: hmm ... /* Switch to section for variable DECL. RELOC is the same as the argument to SELECT_SECTION. */ void variable_section (tree decl, int reloc) { if (IN_NAMED_SECTION (decl)) named_section (decl, NULL, reloc); else targetm.asm_out.select_section (decl, reloc, DECL_ALIGN (decl)); elflink.c: + check elf_gc_propagate_vtable_entries_used also + elf_gc_smash_unused_vtentry_relocs Can we hook into: bfd_boolean bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) /* Called from check_relocs to record the existence of a VTINHERIT reloc. */ .vtable_inherit & .vtable_entry - pseudo-ops from old 'gas' http://sources.redhat.com/ml/binutils/2001-02/msg00485.html gas/config/obj-elf.c: /* These are GNU extensions to aid in garbage collecting C++ vtables. */ {"vtable_inherit", (void (*) (int)) &obj_elf_vtable_inherit, 0}, {"vtable_entry", (void (*) (int)) &obj_elf_vtable_entry, 0}, * Interesting ! :-) * + [ ... neato ...] * To understand the linker: read binutils/include/bfdlink.h You just have to make sure, that it's called before static ctors. So either before __do_global_ctors, or before the call to frame_dummy (which in turn calls __register_frame_info). So it's perhaps enough if you put that call to fixup_inheritance (or the like) in crtstuff.c right before here: #ifdef INIT_SECTION_ASM_OP CRT_CALL_STATIC_FUNCTION (INIT_SECTION_ASM_OP, frame_dummy) #else /* defined(INIT_SECTION_ASM_OP) */ static func_ptr __frame_dummy_init_array_entry[] __attribute__ ((__unused__, section(".init_array"))) = { frame_dummy }; #endif /* !defined(INIT_SECTION_ASM_OP) */ #endif /* USE_EH_FRAME_REGISTRY || JCR_SECTION_NAME */ Perhaps outside the USE_EH_FRAME_REGISTRY || JCR_SECTION_NAME ifdef hokay :-) Looking at: + ld/eelf_i386.c ... (interesting) assigns: ld_elf_i386_emulation = -> ldemul-list.h EMULATION_LIST /* Do the final step of an ELF link. */ bfd_boolean bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) binutils overview: + ldmain.c:469 + yyparse (); [ on linker script ] Most of the action is here: + lang_process [ldlang.c] + open_input_bfds: + load_symbols [ end ] + ... -> elflink.c + "bfd_elf_link_add_symbols" + all symbols end up in: + elf_link_add_object_symbols ** hack here ! ** + ldemul_after_open + ldctor_build_sets [ .ctor handling ? ] + ldemul_before_allocation + by this stage we -know- all the sizes + including relocation count etc. ? [!] -> ldwrite.c:577 ** elf_link_add_object: + we can detect & start to accumulate information on relocs + but we need all symbols in-place first (surely) ? + bfdlink.h (bfd_link_info) + input_bfds -> link_next list ... + we have to 'size' sections later (surely) + bfd_elf_size_dynamic_sections ... + Need to do the calcl here + while walking over the input_bfds ... [! :-] ** TODO: + remove vtreloc cmdline ... + Can we set SEC_MERGE on the gcc version section ? [!?] (.comment?) + the data we need to do the relocs - is fetched with (?) elfcode.h (elf_slurp_reloc_table) + nah - our relocs are somewhere else ... Interesting fn: for generating linker sourced relocs: static bfd_boolean elf_reloc_link_order (bfd *output_bfd, struct bfd_link_info *info, asection *output_section, struct bfd_link_order *link_order) ** Where are the relocations ? + how do we get at them ? ** FIXME: + what about re-writing these tables when they are in-use [!] + inevitably some of the symbols will be 'vague' (?) + [ we can easily check the value of the relocs vs. our own section address / size [ if we're in glibc ... ] ] ** FIXME: + problem 1: emitting our own reloc + problem 2: removing existing relocs ! ;-) ** Strategy: + generate a new / bogus section in the Input (!?) + pack it full of relocs (?) + copy it to the output (?) * look at linker maps [!] * consider other sections ? + .rel.plt ? - how does it get built ? + .dynsym + copy relocs from in -> out (?) + _bfd_elf_link_output_relocs [ Called from Where !? ] + from elflink.c (elf_link_input_bfd) called via (elf_backend_emit_relocs) + this is just building the binary rel section... + can we just do this ourselves for our custom section at the end ? + just call bed->swap_reloc_out [ a lot ourselves ] + have some custom logic ... [ and a custom offset ] + that will let us build a .vtrelocs section ourselves. + input_section->output_section ... + rels ? + then we just need to start killing relocations in other sections :-) ... [ easier ? ] swap_in/out etc. * Keep track of external & internal relocs [!?] + [hmm] asection->output_section + _bfd_elf_link_size_reloc_section ... + pad them out ? [...] + [ symbols? ] ** FIXME: + how does the init_list stuff get relocated !? + how does it get NULL terminated ? + can we use a similar mechanism ? + can we just update the linker file & let it copy / aggregate the sections in ? + [ No ? ] we have to re-write the relocations (?) - dupliate inits ? [ same problem ? ] + Where do we calculate how many external relocations we need ? + we must calculate this for all modules [!] + eelf_i386.c - Very complicated linker scripts ... (?) Right normally relocations are only created by the assembler. Well, not only, though. Also by the ELF link editor of course. But that directly generates ELF relocations, not BFD relocs. , I'll have competency one-2-ones with my team in 10 minutes, must prepare ... + .got.plt : has a -load- of custom relocations ? + or are they done by glibc automagically ? [ Micha ] I tried this since some hours now (adding relocations), and nearly succeeded... Couple things: 1) the c++ patch outputs the three entries in the opposite order (the list you build for initialization will be walked from the back, because there is somewhere an nreverse() call on that list), I've changed the binutils part for me, instead of correction the C++ part to the documented format 2) there were a couple mixups in naming the sections .suse.vtrelocs section (sometimes missing the plural 's') Anyway, as you can see in the patch (attached) I was trying hard to not only add the new section (no problem), but also generating relocations for it. Getting the storage for those relocs (I tried to only emit ELF relocs directly, not going over the generic BFD routines) is no problem, filling it with relocs is also not so much a problem (on has to adjust the symbol indices from the incoming relocs to the final symbol indices of the output). So, with that being merely work, I tried to simply add _one_ hard coded relocation into a clean .suse.vtrelocs section. For that one has to first set the ->relocs member (of the elf specific section data) to an array of ELF relocs. But then it's not yet used, one has to remove the ~SEC_LINKER_CREATED flag too (and set SEC_RELOC). Otherwise elf_link_input_bfd() will ignore that section. [A note: all those artificial sections generated by the linker will conceptually be generated as if coming from the first input file BFD, _not_ directly in the output_bfd, and by that then also be linked into the output file. That object file (the first with certain properties) is stored elf_hash_table (info)->dynobj all the time.] Unfortunately the above is not enough. Such input section containing relocation entries will be processed by elf_xxx_relocate_section(). The relocs of such section which have to be copied to the output file (in possibly mangled form) will be stored in another artificial section (i.e. hanging off of ->dynobj). But these sections also have to be created first, normally done in check_relocs (goes over a whole section plus relocs and decides if such output section holding reloc copies needs to be created). Unfortunately check_relocs is not prepared to handle generated sections, only sections really coming from an input file. First problem is already with the name. As ".suse.vtrelocs" was not in the original input file (crti.o in most cases) it will have no corresponding ELF section header, and also no name in the ELF string table. That already prevents generation of a ".rel.suse.vtrelocs" section (see elf32-i386.c:...check_relocs, the handinling of 'sreloc'). With a hack I can generate that section anyway, but then the next problem surfaces. Because, if such section then is generated, it won't have any output section corresponding to it. All other such "fake" .rel.* sections (generated for copying over dynamic relocs) will have .rel.dyn as output section assigned. That assignment unfortunately seems to be done in generic linker code, right after reading in the input files, hence sections generated afterwards (at least not these .rel section, which seem to be special somehow). So, we can also generate that ".rel.suse.vtrelocs" section in parallel to the .suse.vtrelocs section itself. That it will get stored into the output file as separate .rel.suse.vtrelocs section (i.e. not joined with .rel.dyn, one can fix that with an entry in the linker script). And so, finally, we have a new section .suse.vtrelocs, with relocations against it. Something doesn't yet seem to be right with the contents of thsoe relocs, but it's a start. I'm too tired to continue poking for today, though :) [ /Micha ] ... Foo ... Crash with section name !? == '-2' ... + [hmm]: + need it to be something else ? 'elf_fake_sections' ? ... Paste of my log: [17:46:26] >micha< my testcase was just two files of the same content: [17:46:52] >micha< struct A { [17:46:52] >micha< virtual void f(void); [17:46:52] >micha< virtual void g(void); [17:46:53] >micha< virtual void h(void); [17:46:53] >micha< }; [17:46:54] >micha< struct B : public A { [17:46:54] >micha< virtual void g(void); [17:46:55] >micha< }; [17:47:10] [michael_] ah ok :-) [17:47:26] [michael_] so - I don't see the section getting output; [17:47:36] >micha< Compiled without -fPIC to asm, copied the asm file, changed the __vtbl_something symbol (as it's global to not clash), and linking with -shared -o -t.so. [17:47:50] [michael_] ah - ok ;_) [17:47:59] >micha< Relevant details of readelf -e t.so: [17:48:03] michael_ is linking to an unshared binary - perhaps that is the problem. [17:48:07] >micha< [ 6] .rel.dyn REL 000003d4 0003d4 000050 08 A 2 0 4 [17:48:07] >micha< [ 7] .rel.plt REL 00000424 000424 000010 08 A 2 9 4 [17:48:13] >micha< [12] .suse.vtrelocs PROGBITS 000005a0 0005a0 000030 00 A 0 0 4 [17:48:25] >micha< And readelf -r: [17:48:31] >micha< 000016d8 00000008 R_386_RELATIVE [17:48:31] >micha< 000016dc 00000008 R_386_RELATIVE [17:48:31] >micha< 00000b40 00001701 R_386_32 00000000 __gmon_start__ [17:48:32] >micha< 000016c0 00001706 R_386_GLOB_DAT 00000000 __gmon_start__ [17:48:44] >micha< The relocation to 00000b40 is the new one. output_section ? - creation ? + 1 assignment: _bfd_elf_link_just_syms ... ... elflink.c: /* Set the output_section field so that lang_add_section does not create a lang_input_section structure for this section. Since there might be a symbol in the section being discarded, we must retain a pointer to the section which we are really going to use. */ sec->output_section = bfd_abs_section_ptr; sec->kept_section = l->sec; ** To setup sh_name correctly: + we need to call 'elf_fake_sections' earlier ... + [ when we know we will need the section ? ] #0 elf_fake_sections (abfd=0x810f160, asect=0x8110620, failedptrarg=0xbfae99c4) at elf.c:2657 #1 0x080702e9 in bfd_map_over_sections (abfd=0x810f160, operation=0x8086b70 , user_storage=0xbfae99c4) at section.c:1226 #2 0x08089408 in _bfd_elf_compute_section_file_positions (abfd=0x810f160, link_info=0x8103e60) at elf.c:3464 #3 0x08092ce2 in bfd_elf_final_link (abfd=0x810f160, info=0x8103e60) at elflink.c:8392 #4 0x0805d07a in ldwrite () at ldwrite.c:557 #5 0x0805c6df in main (argc=0, argv=0x19) at .././ld/ldmain.c:469 ** Looking up the string name - just doesn't work ... + crashes: no string table etc. #0 _bfd_elf_strtab_add (tab=0x0, str=0x80f6446 ".rel.suse.vtrelocs", copy=0) at elf-strtab.c:155 #1 0x08086bbc in elf_fake_sections (abfd=0x8117510, asect=0x8119c44, failedptrarg=0xbfed8718) at elf.c:2675 #2 0x0809dea4 in _bfd_elf_vtreloc_accumulate (output_bfd=0x810f160, info=0x8103e20) at elf-vtreloc.c:322 #3 0x0809769e in bfd_elf_size_dynamic_sections (output_bfd=0x810f160, soname=0x0, rpath=0x0, filter_shlib=0x0, auxiliary_filters=0x0, info=0x8103e20, sinterpptr=0xbfed8868, verdefs=0x0) at elflink.c:5231 #4 0x0806343c in gldelf_i386_before_allocation () at eelf_i386.c:1030 #5 0x080587b1 in lang_process () at ldlang.c:5474 #6 0x0805c6c3 in main (argc=0, argv=0x19) at .././ld/ldmain.c:460 ** So - where does: this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), asect->name, FALSE); #define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) + start working ? /* prep headers will not be called for a bit - this defeats a section naming assertion in the backend code, that is not experienced with faked sections */ { struct elf_strtab_hash *orig_ptr; orig_ptr = elf_shstrtab (dynobj); elf_shstrtab (dynobj) = _bfd_elf_strtab_init (); elf_section_data (vtreloc_sec)->rel_hdr.sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (dynobj), ".rel.suse.vtrelocs", FALSE); { const char *check; unsigned int strndx = elf_elfheader (dynobj)->e_shstrndx; unsigned int shnam = elf_section_data (vtreloc_sec)->rel_hdr.sh_name; check = bfd_elf_string_from_elf_section (dynobj, strndx, shnam); fprintf (stderr, "Check '%s'\n", check); } #endif elflink.c: link_add_symbols -> calls check_relocs ... ** If we do this ourself: + have to manage the dynsym table ourselves. + have to manage the reloc table sizes ourself etc. ... + £"$"£$"£4ing all done in the backend specific code. Longer term: + re-write to use glibc ... [ nurgh - so, so bad ... ] + no hackish mprotect nasties (etc.) + move VTables from .got -> .data [!?] + re-write sorting algorithm to be: a) fast, b) sort by address, to ensure linear src/dest walks. TODO: + 64bit testing + bitmasks: 32 vs. 64bit (etc.) + patch review + catch & eliminate fixups of remote vtables: need to do a range/bound check on all of .data [! :-] (useful for the mprotect too (?) ...) + read the glibc mprotect code + *Or* - emit each one as R_386_RELATIVE [etc.] + is this a 'BFD_RELOC_.._PCREL ? + also need a RELOC_32 and RELOC_64 [!] ... + fix detection of incoming things ... To test size savings: + need to be able to turn off vtable relocation :-) [!] .... + insert 0xdeadbeef instead ? + Send patches to the Matzster ... + 'static' storage definition ... + gets GC'd by the compiler [somehow] + most of the size savings - ephemeral ... + swallowed - since symbols are still emitted [!] + (gack) Call some methods in the tests: do some arithmetic to validate the result etc. ... TODO: + undo some of the cunning that makes it call virtual functions directly in many cases (!?) - gives excessive symbol churn. + Test size savings with 'tests' ... + mail Micha ... + http://go-oo.org/~michael/tests.tar.bz2 real-world: VCL: Copy: 0xb7f5376c -> 0xb5e66bec, (0x3) Copy: 0xb7f53a0c -> 0xb5e66b8c, (0x33ff9) Copy: 0xb7f5b908 -> 0xb5e66b28, (0x67ffb) Copy: 0xb7f56430 -> 0xb5e671b0, (0x7ffffff) Copy: 0xb7f563b0 -> 0xb5e67130, (0xffffffff) Copy: 0xb5e671b0 -> 0xb5e67090, (0x7ffffff) Copy: 0xb5e67130 -> 0xb5e67010, (0xffbfffff) * Strongly suspect copies of data: 08094348 w DO .bss 000000f8 _ZTV8OKButton ** URGH - this is in .bss + it is *copied* wholesale from elsewhere + *before* the linker has a go & => + we're screwed, we have to do this in glibc ... [!] + ugh ... + or are we (!?) ;-) + 'COPY' relocs ... [!?] ** HAH! + we can install a signal handler (perhaps) + take a fault ... + then (somehow)? + process relocations [hmm] ** Interaction between: + glibc-2.4/sysdeps/i386/dl-machine.h from + dl-reloc.c (_dl_relocate_object) from + rtld.c - hmm ... ** Create a test that we know fails: + copying vtable foo ... into main object ...