123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566(*Generated by Lem from linkable_list.lem.*)openLem_basic_classesopenLem_functionopenLem_stringopenLem_string_extraopenLem_tupleopenLem_boolopenLem_listopenLem_list_extraopenLem_setopenLem_set_extra(*import Map*)openLem_sortingopenLem_numopenLem_maybeopenLem_assert_extraopenByte_sequenceopenDefault_printingopenErroropenMissing_pervasivesopenShowopenElf_types_native_uintopenElf_memory_imageopenElf_headeropenElf_fileopenMemory_imageopenElf_memory_imageopenElf_section_header_tableopenElf_symbol_tableopenString_tableopenInput_listopenElf_memory_imageopenElf_memory_image_of_elf64_filetypescript=byte_sequence0(* FIXME *)typelinkable_object=RelocELFofelf_memory_image(* memory image without address assignments *)|SharedELFofelf_memory_image(* memory image with address assignments *)|ScriptASTofscript(* FIXME: should be elaborated away *)|ControlScriptDefs(*val string_of_linkable_object : linkable_object -> string*)letstring_of_linkable_objectl:string=((matchlwithRelocELF(_)->"a relocatable file (...)"|SharedELF(_)->"a shared library (...)"|ScriptAST(_)->"a linker script (...)"|ControlScriptDefs->"the control script"))(* We keep the original input item around, hence the filename and byte sequence
* and options. *)typelinkable_item=linkable_object*input_item*input_options(*val short_string_of_linkable_item : linkable_item -> string*)letshort_string_of_linkable_itemitem:string=(let(obj,inp,opts)=iteminshort_string_of_input_iteminp)letinstance_Show_Show_Linkable_list_linkable_object_dict:(linkable_object)show_class=({show_method=string_of_linkable_object})typelinkable_list=linkable_itemlisttypesymbol_resolution_oracle=linkable_list->int->string->intlisttypebinding=(Nat_big_num.num*symbol_reference*linkable_item)*(Nat_big_num.num*symbol_definition*linkable_item)optiontypebinding_list=bindinglisttypebinding_map=(string,((Nat_big_num.num*binding)list))Pmap.mapletimage_of_linkable_itemitem:(Abis.any_abi_feature)annotated_memory_image=((matchitemwith(RelocELF(image),_,_)->image|(SharedELF(image),_,_)->image|_->failwith"no image"))(*val linkable_item_of_input_item_and_options : forall 'abifeature. abi 'abifeature -> input_item -> input_options -> linkable_item*)letlinkable_item_of_input_item_and_optionsaitopts:linkable_object*(string*input_blob*(Command_line.input_unit*(origin_coord)list))*input_options=((match((matchitwith(fname1,Reloc(seq),origin)->let_=(prerr_endline("Considering relocatable file "^fname1))inbind(Elf_file.read_elf64_fileseq)(fune->return(RelocELF(elf_memory_image_of_elf64_fileafname1e),it,opts))|(fname1,Shared(seq),origin)->(*let _ = Missing_pervasives.errln ("Skipping shared object " ^ fname) in *)fail"unsupported input item"|(fname1,Script(seq),origin)->(*let _ = Missing_pervasives.errln ("Skipping linker script " ^ fname) in*)fail"unsupported input item"))withSuccess(item)->item|Fail(str)->failwith(str^": non-ELF or non-relocatable input file")))(*val string_of_linkable : linkable_item -> string*)letstring_of_linkablel:string=((matchlwith(_,item,_)->string_of_tripleinstance_Show_Show_string_dictinstance_Show_Show_Input_list_input_blob_dict(instance_Show_Show_tup2_dictCommand_line.instance_Show_Show_Command_line_input_unit_dict(instance_Show_Show_list_dictinstance_Show_Show_Input_list_origin_coord_dict))item))(* How do we signal "multiple definitions"?
* This is part of the policy baked into the particular oracle:
* are multiple definitions okay, or do we fail?
*
* NOTE that multiple definitions *globally* is not the same as
* multiple definitions as candidates for a given binding. We
* can get the former even if we don't have the latter, in some
* weird group/archive arrangements. The right place to detect
* this condition is probably when generating the output symtab.
*)(*val add_definition_to_map : (natural * symbol_definition * linkable_item) -> Map.map string (list (natural * symbol_definition * linkable_item))
-> Map.map string (list (natural * symbol_definition * linkable_item))*)letadd_definition_to_mapdef_idx_and_def_and_linkablem:((string),((Nat_big_num.num*symbol_definition*(linkable_object*input_item*input_options))list))Pmap.map=(let(def_idx,def,def_linkable)=def_idx_and_def_and_linkablein(matchPmap.lookupdef.def_symnamemwithSomecurlist->Pmap.adddef.def_symname((def_idx,def,def_linkable)::curlist)m|None->Pmap.adddef.def_symname[(def_idx,def,def_linkable)]m))(*val all_definitions_by_name : linkable_list -> Map.map string (list (natural * symbol_definition * linkable_item))*)letall_definitions_by_namelinkables:((string),((Nat_big_num.num*symbol_definition*linkable_item)list))Pmap.map=((* Now that linkables are ELF memory images, we can make the
* list of definitions much more easily. *)letlist_of_deflists=(Lem_list.mapi(fun(idx1:int)->(fun(item:linkable_item)->letimg2=(image_of_linkable_itemitem)inlet(all_def_tags,all_def_ranges)=(List.split(Multimap.lookupBy0(Memory_image_orderings.instance_Basic_classes_Ord_Memory_image_range_tag_dictAbis.instance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictinstance_Basic_classes_Ord_string_dict(instance_Basic_classes_Ord_tup2_dictinstance_Basic_classes_Ord_Num_natural_dictinstance_Basic_classes_Ord_Num_natural_dict)))instance_Basic_classes_SetType_var_dict(instance_Basic_classes_SetType_Maybe_maybe_dict(instance_Basic_classes_SetType_tup2_dictinstance_Basic_classes_SetType_var_dict(instance_Basic_classes_SetType_tup2_dictinstance_Basic_classes_SetType_Num_natural_dictinstance_Basic_classes_SetType_Num_natural_dict)))(Memory_image_orderings.tagEquivAbis.instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(SymbolDef(null_symbol_definition))img2.by_tag))inletall_defs=(Lem_list.map(funtag->(matchtagwithSymbolDef(def)->(def,item)|_->failwith"matched tag not a symbol definition"))all_def_tags)inletx2=([])inList.fold_right(fun(def,def_linkable)x2->iftruethen(Nat_big_num.of_intidx1,def,def_linkable)::x2elsex2)all_defsx2))linkables)inList.fold_left(funaccum->(fundeflist->List.fold_left(funm->(fun(def_idx,def,def_linkable)->add_definition_to_map(def_idx,def,def_linkable)m))accumdeflist))(Pmap.emptycompare)list_of_deflists)typebinding_oracle=linkable_list->(string,((Nat_big_num.num*symbol_definition*linkable_item)list))Pmap.map->(Nat_big_num.num*symbol_reference*linkable_item)->(Nat_big_num.num*symbol_definition*linkable_item)option(*val resolve_one_reference_default : forall 'abifeature. abi 'abifeature -> binding_oracle*)letresolve_one_reference_defaultalinkablesdefmapref_idx_and_ref_and_linkable:(Nat_big_num.num*symbol_definition*(linkable_object*(string*input_blob*(Command_line.input_unit*(origin_coord)list))*input_options))option=(let(ref_idx,ref1,ref_linkable)=ref_idx_and_ref_and_linkablein(* Get the list of all definitions whose name matches.
* Don't match empty names.
* How should we handle common symbols here?
* A common symbol is a potential definition, so it goes in the def list.
*)let(defs_and_linkables_with_matching_name:(Nat_big_num.num*symbol_definition*linkable_item)list)=((matchPmap.lookupref1.ref_symnamedefmapwithSome(l:((Nat_big_num.num*symbol_definition*linkable_item)list))->l|None->[]))in(* Filter the list by eligibility rules.
* Normally,
*
* - any .o file can supply any other .o file on the command line
* - any .a file supplies only files appearing to its left
* i.e. "it is searched once for definitions"
* - does a .o file supply a .a file? to both its right and left? Experimentally, YES.
*
* So the restrictions are
* - archives may not supply weak references
* - archives may only supply to the left, or to themselves, or to objects in the same group
*)let(ref_obj,(ref_fname,ref_blob,(ref_u,ref_coords)),ref_options)=ref_linkableinletref_is_weak=(Nat_big_num.equal(get_elf64_symbol_bindingref1.ref_syment)stb_weak)inletdef_is_eligible=(fun(def_idx,def,def_linkable)->letref_is_unnamed=(ref1.ref_symname="")inletref_is_to_defined_or_common_symbol=(not(Nat_big_num.equal(Uint32_wrapper.to_bigintref1.ref_syment.elf64_st_shndx)stn_undef))inletdef_sym_is_ref_sym=(Nat_big_num.equalref_idxdef_idx&&(Nat_big_num.equalref1.ref_sym_scndef.def_sym_scn&&Nat_big_num.equalref1.ref_sym_idxdef.def_sym_idx))inlet(def_obj,(def_fname,def_blob,def_origin),def_options)=def_linkableinlet(def_u,def_coords)=def_origininlet(def_in_group,def_in_archive)=((matchdef_coordswithInArchive(aid,aidx,_,_)::InGroup(gid1,gidx)::[_]->(Somegid1,Someaid)|InArchive(aid,aidx,_,_)::[_]->(None,Someaid)|InGroup(gid1,gidx)::[_]->(Somegid1,None)|[_]->(None,None)|_->failwith"internal error: didn't understand origin coordinates of definition"))inletref_is_leftmore=(Nat_big_num.less_equalref_idxdef_idx)in(* For simplicity we include the case of "same archive" in "in group with". *)letref_is_in_group_with_def=((matchdef_in_groupwithNone->false|Somedef_gid->(matchref_coordswithInArchive(_,_,_,_)::InGroup(gid1,_)::[_]->Nat_big_num.equalgid1def_gid|InGroup(gid1,_)::[_]->Nat_big_num.equalgid1def_gid|_->false)))in(* but maybe same archive? *)(* DEBUGGING: print some stuff out if we care about this symbol. *)let_=(if(ref_fname="backtrace.o")&&(def.def_symname="_Unwind_GetCFA")then(*Missing_pervasives.errln ("saw backtrace.o referencing _Unwind_GetCFA; coords are "
^ "def: " ^ (show def_coords) ^ ", ref: " ^ (show ref_coords) ^ "; ref_is_in_group_with_def: "
^ (show ref_is_in_group_with_def) ^ "; def_in_group: " ^ (show def_in_group))*)()else())inletref_and_def_are_in_same_archive=((match(def_coords,ref_coords)with(InArchive(x1,_,_,_)::_,InArchive(x2,_,_,_)::_)->Nat_big_num.equalx1x2|_->false))inletdef_is_in_archive=((matchdef_in_archivewithSome_->true|None->false))inifref_is_to_defined_or_common_symbolthendef_sym_is_ref_symelseifref_is_unnamedthenfalseelseifdef_is_in_archivethen(* Weak references *can* be resolved to archive members...
* if the reference itself is also in the archive. *)((notref_is_weak)||ref_and_def_are_in_same_archive)&&(ref_is_leftmore||(ref_and_def_are_in_same_archive||ref_is_in_group_with_def))elsetrue)inleteligible_defs=(List.filterdef_is_eligibledefs_and_linkables_with_matching_name)inlet(maybe_target_def_idx,maybe_target_def,maybe_target_def_linkable)=((matcheligible_defswith[]->(None,None,None)|[(def_idx,def,def_linkable)]->(Somedef_idx,Somedef,Somedef_linkable)|(d_idx,d,d_l)::more_pairs->(* Break ties by
* - putting defs in relocs (or --defsym or linker script, a.k.a. command line) ahead of defs in archives;
* - else whichever definition appeared first in the left-to-right order.
*)letsorted=(insertSortBy(fun(d_idx1,d1,(_,(_,_,(_,d_l1_coords)),_))->(fun(d_idx2,d2,(_,(_,_,(_,d_l2_coords)),_))->(match(d_l1_coords,d_l2_coords)with(InCommandLine(_)::_,InCommandLine(_)::_)->Nat_big_num.lessd_idx1d_idx2|(InCommandLine(_)::_,_)->(* command-line wins *)true|(_,InCommandLine(_)::_)->(* command-line wins *)false|(_,_)->Nat_big_num.lessd_idx1d_idx2)))eligible_defs)in(matchsortedwith(first_d_idx,first_d,first_d_l)::_->(Somefirst_d_idx,Somefirst_d,Somefirst_d_l)|_->failwith"impossible: sorted list is shorter than original")))inletrefstr=("`"^(ref1.ref_symname^("' ("^((ifNat_big_num.equal(Uint32_wrapper.to_bigintref1.ref_syment.elf64_st_shndx)shn_undefthen"UND"else"defined")^(" symbol at index "^((Nat_big_num.to_stringref1.ref_sym_idx)^(" in symtab "^((Nat_big_num.to_stringref1.ref_sym_scn)^(" in "^(ref_fname^")"))))))))))in(*let _ = Missing_pervasives.errs ("Bound a reference from " ^ refstr ^ " to ")
in*)(match(maybe_target_def_idx,maybe_target_def,maybe_target_def_linkable)with(Sometarget_def_idx,Sometarget_def,Sometarget_def_linkable)->(*let _ = Missing_pervasives.errln (" a definition in "^ (show (target_def_linkable)))
in*)Some(target_def_idx,target_def,target_def_linkable)|(None,None,None)->(*let _ = Missing_pervasives.errln " no definition"
in*)ifref_is_weak(* || a.symbol_is_generated_by_linker ref.ref_symname *)thenNoneelse(* failwith ("undefined symbol: " ^ refstr) *)None(* FIXME: do a check, *after* the linker script has been interpreted,
* that all remaining undefined symbols are permitted by the ABI/policy. *)|_->failwith"impossible: non-matching maybes for target_def_idx and target_def"))(*val resolve_all :
linkable_list
-> Map.map string (list (natural * symbol_definition * linkable_item)) (* all definitions *)
-> binding_oracle
-> list (natural * symbol_reference * linkable_item)
-> list ((natural * symbol_reference * linkable_item) * maybe (natural * symbol_definition * linkable_item))*)letresolve_alllinkablesall_defsoraclerefs:((Nat_big_num.num*symbol_reference*(linkable_object*input_item*input_options))*(Nat_big_num.num*symbol_definition*linkable_item)option)list=(Lem_list.map(fun(ref_idx,ref1,ref_linkable)->((ref_idx,ref1,ref_linkable),(oraclelinkablesall_defs(ref_idx,ref1,ref_linkable))))refs)(* To accumulate which inputs are needed, we work with a list of undefineds, starting with those
* in the forced-output objects. We then iteratively build a list of all needed symbol definitions,
* pulling in the objects that contain them, until we reach a fixed point. *)(*val resolve_undefs_in_one_object :
linkable_list
-> Map.map string (list (natural * symbol_definition * linkable_item)) (* all definitions *)
-> binding_oracle
-> natural
-> list ((natural * symbol_reference * linkable_item) * maybe (natural * symbol_definition * linkable_item))*)letresolve_undefs_in_one_objectlinkablesall_defsoracleidx1:((Nat_big_num.num*symbol_reference*linkable_item)*(Nat_big_num.num*symbol_definition*linkable_item)option)list=((* Get this object's list of references *)letitem=((matchLem_list.list_indexlinkables(Nat_big_num.to_intidx1)withSomeit->it|None->failwith"impossible: linkable not in list of linkables"))inletimg2=(image_of_linkable_itemitem)inlet(all_ref_tags,all_ref_ranges)=(List.split(Multimap.lookupBy0(Memory_image_orderings.instance_Basic_classes_Ord_Memory_image_range_tag_dictAbis.instance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictinstance_Basic_classes_Ord_string_dict(instance_Basic_classes_Ord_tup2_dictinstance_Basic_classes_Ord_Num_natural_dictinstance_Basic_classes_Ord_Num_natural_dict)))instance_Basic_classes_SetType_var_dict(instance_Basic_classes_SetType_Maybe_maybe_dict(instance_Basic_classes_SetType_tup2_dictinstance_Basic_classes_SetType_var_dict(instance_Basic_classes_SetType_tup2_dictinstance_Basic_classes_SetType_Num_natural_dictinstance_Basic_classes_SetType_Num_natural_dict)))(Memory_image_orderings.tagEquivAbis.instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(SymbolRef(null_symbol_reference_and_reloc_site))img2.by_tag))in(* By using SymbolRef, we are extracting and binding each relocation site individually.
* since there might be more than one relocation site referencing the same symbol name,
* in a given object.
*
* We are also binding SymbolRefs that have no relocation, which occur when there's
* an UND symbol which is not actually used by a relocation site, but is nevertheless
* in need of being resolved.
*
* We don't (for the moment) want to make different decisions for different reloc sites
* in the same object referencing the same symbol. So we dedup from a list to a set.
*)letall_refs=(Pset.from_listcompare(Lem_list.map(funtag->(matchtagwithSymbolRef(r)->r.ref|_->failwith"matched tag not a relocation site"))all_ref_tags))inletref_triples=(letx2=(Pset.from_list(tripleCompareNat_big_num.comparecompare(tripleComparecompare(tripleComparecomparecompare(pairComparecompare(lexicographic_comparecompare)))compare))[])inPset.fold(funref1x2->iftruethenPset.add(idx1,ref1,item)x2elsex2)all_refsx2)in(*let _ = Missing_pervasives.errln ("object " ^ (show item) ^ " has " ^
(show (Set.size ref_triples)) ^ " reloc references (symname, sym_scn, sym_idx, st_shndx) (" ^
(show (List.map (fun x -> ("\"" ^ x.ref_symname ^ "\"", x.ref_sym_scn, x.ref_sym_idx, natural_of_elf64_half x.ref_syment.elf64_st_shndx)) (Set_extra.toList all_refs))) ^ ")")
in*)letund_ref_triples=(letx2=(Pset.from_list(tripleCompareNat_big_num.comparecompare(tripleComparecompare(tripleComparecomparecompare(pairComparecompare(lexicographic_comparecompare)))compare))[])inPset.fold(fun(idx1,ref1,ref_item)x2->ifNat_big_num.equal(Uint32_wrapper.to_bigintref1.ref_syment.elf64_st_shndx)shn_undefthenPset.add(idx1,ref1,ref_item)x2elsex2)ref_triplesx2)in(*let _ = Missing_pervasives.errln ("... of which " ^
(show (Set.size und_ref_triples)) ^ " are to undefined symbols: (symname, sym_scn, sym_idx, st_shndx) (" ^
(show (List.map (fun (idx, x, _) -> ("\"" ^ x.ref_symname ^ "\"", x.ref_sym_scn, x.ref_sym_idx, natural_of_elf64_half x.ref_syment.elf64_st_shndx)) (Set_extra.toList und_ref_triples))) ^ ")")
in*)resolve_alllinkablesall_defsoracle(Pset.elementsref_triples))(*val accumulate_bindings_bf : forall 'abifeature.
abi 'abifeature
-> linkable_list
-> Map.map string (list (natural * symbol_definition * linkable_item)) (* all definitions *)
-> set natural (* inputs fully-bound so far *)
-> list natural (* ordered list of inputs to bind next *)
-> list ((natural * symbol_reference * linkable_item) * maybe (natural * symbol_definition * linkable_item)) (* bindings made so far *)
-> list ((natural * symbol_reference * linkable_item) * maybe (natural * symbol_definition * linkable_item))*)(* all accumulated bindings bindings *)letrecaccumulate_bindings_bfalinkablesall_defsfully_boundto_bindbindings_accum:((Nat_big_num.num*symbol_reference*linkable_item)*(Nat_big_num.num*symbol_definition*linkable_item)option)list=((* This is like foldl, except that each stage
* can add stuff to the work list *)(matchto_bindwith[]->bindings_accum(* termination *)|l_idx::more_idx->(* Get the new bindings for this object *)letnew_bindings=(resolve_undefs_in_one_objectlinkablesall_defs(resolve_one_reference_defaulta)l_idx)inletnew_fully_bound=(Pset.addl_idxfully_bound)in(* Which of the new bindings are to objects
* not yet fully bound or not yet in the to-bind list? *)letnew_bindings_def_idx=(list_concat_map(fun(ref1,maybe_def_and_idx_and_linkable)->(matchmaybe_def_and_idx_and_linkablewithSome(def_idx,def,def_linkable)->[def_idx]|None->[]))new_bindings)inletnew_bindings_def_idx_set=(Pset.from_listNat_big_num.comparenew_bindings_def_idx)inletincluded_linkables_idx=(Pset.(union)fully_bound((Pset.from_listNat_big_num.compareto_bind)))inletnew_l_idx=(Pset.diffnew_bindings_def_idx_setincluded_linkables_idx)inletnew_l_idx_list=(Pset.elementsnew_l_idx)in(*let _ = Missing_pervasives.errln (
if List.null new_l_idx_list
then
"Fully bound references in " ^ (show (List.index linkables (natFromNatural l_idx)))
^ " using only already-included linkables ("
^ (show (List.map (fun i -> List.index linkables (natFromNatural i)) (Set_extra.toList included_linkables_idx)))
else
"Including additional linkables "
^ (show (List.mapMaybe (fun i -> List.index linkables (natFromNatural i)) new_l_idx_list))
)
in*)accumulate_bindings_bfalinkablesall_defsnew_fully_bound(List.rev_append(List.revmore_idx)new_l_idx_list)(List.rev_append(List.revbindings_accum)new_bindings)))(* We need a generalised kind of depth-first search in which there are multiple start points.
* Also, we always work one object at a time, not one edge at a time; when we pull in an object,
* we resolve *all* the references therein.
*)(*val accumulate_bindings_objectwise_df : forall 'abifeature.
abi 'abifeature
-> linkable_list
-> Map.map string (list (natural * symbol_definition * linkable_item)) (* all definitions *)
-> list ((natural * symbol_reference * linkable_item) * maybe (natural * symbol_definition * linkable_item)) (* bindings made so far *)
-> set natural (* inputs fully-bound so far -- these are "black" *)
-> list natural (* inputs scheduled for binding -- these include
any "grey" (in-progress) nodes *and*
any nodes that we have committed to exploring
(the "start nodes").
Because we're depth-first, we prepend our adjacent
nodes to this list, making them grey, then we
recurse by taking from the head. We must always
filter out the prepended nodes from the existing list,
to ensure we don't recurse infinitely. *)
-> list ((natural * symbol_reference * linkable_item) * maybe (natural * symbol_definition * linkable_item))*)(* all accumulated bindings bindings *)letrecaccumulate_bindings_objectwise_dfalinkablesall_defsbindings_accumblacksgreys:((Nat_big_num.num*symbol_reference*linkable_item)*(Nat_big_num.num*symbol_definition*linkable_item)option)list=((matchgreyswith[]->bindings_accum(* termination *)|l_idx::more_idx->(* Get the new bindings for this object *)letnew_bindings=(resolve_undefs_in_one_objectlinkablesall_defs(resolve_one_reference_defaulta)l_idx)in(* We pull in the whole object at a time ("objectwise"), so by definition,
* we have created bindings for everything in this object; it's now black. *)letnew_fully_bound=(Pset.addl_idxblacks)in(* Which of the new bindings are to objects
* not yet fully bound or not yet in the to-bind list? *)letnew_bindings_def_idx=(list_concat_map(fun(ref1,maybe_def_and_idx_and_linkable)->(matchmaybe_def_and_idx_and_linkablewithSome(def_idx,def,def_linkable)->[def_idx]|None->[]))new_bindings)inletnew_bindings_def_idx_set=(Pset.from_listNat_big_num.comparenew_bindings_def_idx)in(* this is the "black or grey" set. *)letincluded_linkables_idx=(Pset.(union)blacks((Pset.from_listNat_big_num.comparegreys)))in(* these are the white ones that we're adjacent to *)letnew_l_idx=(Pset.diffnew_bindings_def_idx_setincluded_linkables_idx)inletnew_l_idx_list=(Pset.elementsnew_l_idx)in(* What is the new grey-alike list? (This is the list we tail-recurse down.)
* It's
* - the existing grey-alike list
* - with any new (were-white) objects prepended
* - ... and filtered to *remove* these from the existing list (avoid duplication).
*)letnew_grey_list=(List.rev_append(List.revnew_l_idx_list)(List.filter(funx->not(Pset.memxnew_l_idx))more_idx))in(* whether or not we've not uncovered any new white nodes, we tail-recurse *)(*let _ = (if List.null new_l_idx_list then
Missing_pervasives.errln ("Fully bound references in " ^ (show (List.index linkables (natFromNatural l_idx)))
^ " using only already-included linkables ("
^ (show (List.map (fun i -> List.index linkables (natFromNatural i)) (Set_extra.toList included_linkables_idx)))
) else Missing_pervasives.errln ("Including additional linkables "
^ (show (List.mapMaybe (fun i -> List.index linkables (natFromNatural i)) new_l_idx_list))))
in*)accumulate_bindings_objectwise_dfalinkablesall_defs(List.rev_append(List.revbindings_accum)new_bindings)(new_fully_bound:Nat_big_num.numPset.set)(new_grey_list:Nat_big_num.numlist)))(* Rather than recursively expanding the link by searching for definitions of undefs,
* the GNU linker works by recursing/looping along the list of *linkables*, testing whether
* any of the defs satisfies a currently-undef'd thing. On adding a new undef'd thing,
* we re-search only from the current archive, not from the beginning (i.e. the
* "def_is_leftmore or def_in_same_archive" logic).
*
* Why is this not the same as depth-first? One example is if we pull in a new object
* which happens to have two undefs: one satisfied by the *first* element in the current archive,
* and one satisfied by the last.
*
* In the GNU algorithm, we'll pull in the first archive element immediately afterwards, because
* we'll re-traverse the archive and find it's needed.
*
* In the depth-first algorithm, it depends entirely on the ordering of the new bindings, i.e.
* the symtab ordering of the two undefs. If the later-in-archive def was bound *first*, we'll
* recurse down *that* object's dependencies first.
*
* So if we sort the new grey list
* so that bindings formed in order of *current archive def pos*,
* will we get the same behaviour?
* We can't really do this, because we have no "current archive".
*
* Need to rewrite the algorithm to fold along the list of linkables.
*)