12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514(*Generated by Lem from abis/abis.lem.*)(** The [abis] module is the top-level module for all ABI related code, including
* some generic functionality that works across all ABIs, and a primitive attempt
* at abstracting over ABIs for purposes of linking.
*)openLem_basic_classesopenLem_boolopenLem_numopenLem_maybeopenLem_listopenLem_set(*import Map*)openLem_stringopenShowopenLem_assert_extraopenErroropenMissing_pervasivesopenElf_fileopenElf_headeropenElf_interpreted_sectionopenElf_relocationopenElf_symbol_tableopenElf_program_header_tableopenElf_section_header_tableopenMemory_imageopenAbi_amd64openAbi_amd64_relocationopenAbi_aarch64_leopenAbi_aarch64_relocationopenAbi_power64openAbi_power64_relocationopenAbi_mips64openAbi_mips64_elf_headeropenAbi_mips64_relocationopenAbi_cheri_mips64openAbi_cheri_mips64_elf_headeropenAbi_cheri_mips64_relocationopenGnu_ext_abiopenAbi_classesopenAbi_utilitiesopenElf_types_native_uintopenMemory_image_orderings(** Relocation operators and their validity on a given platform *)(*val is_valid_abi_aarch64_relocation_operator : relocation_operator -> bool*)letis_valid_abi_aarch64_relocation_operatorop:bool=((matchopwith|Page->true|G->true|GDat->true|GLDM->true|DTPRel->true|GTPRel->true|TPRel->true|GTLSDesc->true|Delta->true|LDM->true|TLSDesc->true|Indirect->true|_->false))(*val is_valid_abi_aarch64_relocation_operator2 : relocation_operator2 -> bool*)letis_valid_abi_aarch64_relocation_operator2op:bool=((matchopwith|GTLSIdx->true))(*val is_valid_abi_amd64_relocation_operator : relocation_operator -> bool*)letis_valid_abi_amd64_relocation_operatorop:bool=((matchopwith|Indirect->true|_->false(* XXX: not sure about this? *)))(*val is_valid_abi_amd64_relocation_operator2 : relocation_operator2 -> bool*)letis_valid_abi_amd64_relocation_operator2op:bool=((matchopwith|_->false))(*val is_valid_abi_power64_relocation_operator : relocation_operator -> bool*)letis_valid_abi_power64_relocation_operatorop:bool=false(* TODO *)(*val is_valid_abi_power64_relocation_operator2 : relocation_operator2 -> bool*)letis_valid_abi_power64_relocation_operator2op:bool=((matchopwith|_->false))(** Misc. ABI related stuff *)typeany_abi_feature=Amd64AbiFeatureofany_abi_featureamd64_abi_feature|Aarch64LeAbiFeatureofaarch64_le_abi_feature(*val anyAbiFeatureCompare : any_abi_feature -> any_abi_feature -> Basic_classes.ordering*)letanyAbiFeatureComparef1f2:int=((match(f1,f2)with(Amd64AbiFeature(af1),Amd64AbiFeature(af2))->Abi_amd64.abiFeatureCompare0af1af2|(Amd64AbiFeature(_),_)->(-1)|(Aarch64LeAbiFeature(af1),Amd64AbiFeature(af2))->1|(Aarch64LeAbiFeature(af1),Aarch64LeAbiFeature(af2))->Abi_aarch64_le.abiFeatureCompareaf1af2))(*val anyAbiFeatureTagEquiv : any_abi_feature -> any_abi_feature -> bool*)letanyAbiFeatureTagEquivf1f2:bool=((match(f1,f2)with(Amd64AbiFeature(af1),Amd64AbiFeature(af2))->Abi_amd64.abiFeatureTagEq0af1af2|(Amd64AbiFeature(_),_)->false|(Aarch64LeAbiFeature(af1),Amd64AbiFeature(af2))->false|(Aarch64LeAbiFeature(af1),Aarch64LeAbiFeature(af2))->Abi_aarch64_le.abiFeatureTagEqaf1af2))letinstance_Basic_classes_Ord_Abis_any_abi_feature_dict:(any_abi_feature)ord_class=({compare_method=anyAbiFeatureCompare;isLess_method=(funf1->(funf2->(Lem.orderingEqual(anyAbiFeatureComparef1f2)(-1))));isLessEqual_method=(funf1->(funf2->Pset.mem(anyAbiFeatureComparef1f2)(Pset.from_listcompare[(-1);0])));isGreater_method=(funf1->(funf2->(Lem.orderingEqual(anyAbiFeatureComparef1f2)1)));isGreaterEqual_method=(funf1->(funf2->Pset.mem(anyAbiFeatureComparef1f2)(Pset.from_listcompare[1;0])))})letinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict:(any_abi_feature)abiFeatureTagEquiv_class=({abiFeatureTagEquiv_method=anyAbiFeatureTagEquiv})letmake_elf64_headerdataosabiabivmatentryshoffphoffphnumshnumshstrndx:elf64_header=({elf64_ident=([elf_mn_mag0;elf_mn_mag1;elf_mn_mag2;elf_mn_mag3;Uint32_wrapper.of_bigintelf_class_64;Uint32_wrapper.of_bigintdata;Uint32_wrapper.of_bigintelf_ev_current;Uint32_wrapper.of_bigintosabi;Uint32_wrapper.of_bigintabiv;Uint32_wrapper.of_bigint((Nat_big_num.of_int0));Uint32_wrapper.of_bigint((Nat_big_num.of_int0));Uint32_wrapper.of_bigint((Nat_big_num.of_int0));Uint32_wrapper.of_bigint((Nat_big_num.of_int0));Uint32_wrapper.of_bigint((Nat_big_num.of_int0));Uint32_wrapper.of_bigint((Nat_big_num.of_int0));Uint32_wrapper.of_bigint((Nat_big_num.of_int0))]);elf64_type=(Uint32_wrapper.of_bigintt);elf64_machine=(Uint32_wrapper.of_bigintma);elf64_version=(Uint32_wrapper.of_bigintelf_ev_current);elf64_entry=(Uint64_wrapper.of_bigintentry);elf64_phoff=(Uint64_wrapper.of_bigintphoff);elf64_shoff=(Uint64_wrapper.of_bigintshoff);elf64_flags=(Uint32_wrapper.of_bigint((Nat_big_num.of_int0)));elf64_ehsize=(Uint32_wrapper.of_bigint((Nat_big_num.of_int64)));elf64_phentsize=(Uint32_wrapper.of_bigint((Nat_big_num.of_int56)));elf64_phnum=(Uint32_wrapper.of_bigintphnum);elf64_shentsize=(Uint32_wrapper.of_bigint((Nat_big_num.of_int64)));elf64_shnum=(Uint32_wrapper.of_bigintshnum);elf64_shstrndx=(Uint32_wrapper.of_bigintshstrndx)})(*val phdr_flags_from_section_flags : natural -> string -> natural*)letphdr_flags_from_section_flagssection_flagssec_name:Nat_big_num.num=(letflags=(Nat_big_num.bitwise_orelf_pf_r(Nat_big_num.bitwise_or(ifflag_is_setshf_writesection_flagsthenelf_pf_welse(Nat_big_num.of_int0))(ifflag_is_setshf_execinstrsection_flagsthenelf_pf_xelse(Nat_big_num.of_int0))))in(*let _ = errln ("Phdr flags of section " ^ sec_name ^ "(ELF section flags 0x " ^
(hex_string_of_natural section_flags) ^ ") are 0x" ^ (hex_string_of_natural flags))
in*)flags)(*val phdr_is_writable : natural -> bool*)letphdr_is_writableflags:bool=(Nat_big_num.equal(Nat_big_num.bitwise_andflagself_pf_w)elf_pf_w)typecan_combine_flags_fn=Nat_big_num.numPset.set->Nat_big_num.numoption(* FIXME: lift this to a personality function of the GNU linker?
* Not sure really... need to try some other linkers. *)(*val load_can_combine_flags : can_combine_flags_fn*)letload_can_combine_flagsflagsets:(Nat_big_num.num)option=((* The GNU linker happily adds a .rodata section to a RX segment,
* but not to a RW segment. So the only clear rule is: if any is writable,
* all must be writable. *)letflagslist=(Pset.elementsflagsets)inletunion_flags=(List.fold_leftNat_big_num.bitwise_or((Nat_big_num.of_int0))flagslist)inifList.existsphdr_is_writableflagslistthenifList.for_allphdr_is_writableflagslistthenSomeunion_flagselseNoneelseSomeunion_flags)(*val tls_can_combine_flags : can_combine_flags_fn*)lettls_can_combine_flagsflagsets:(Nat_big_num.num)option=(Some(List.fold_leftNat_big_num.bitwise_or((Nat_big_num.of_int0))(Pset.elementsflagsets)))letmaybe_extend_phdrphdrisec1can_combine_flags:(elf64_program_header_table_entry)option=(letnew_p_type=(Uint32_wrapper.to_bigintphdr.elf64_p_type)inletthis_section_phdr_flags=(phdr_flags_from_section_flagsisec1.elf64_section_flagsisec1.elf64_section_name_as_string)inletmaybe_extended_flags=(can_combine_flags(Pset.from_listNat_big_num.compare[this_section_phdr_flags;Uint32_wrapper.to_bigintphdr.elf64_p_flags]))inif(Lem.option_equalNat_big_num.equalmaybe_extended_flagsNone)then(*let _ = errln "flag mismatch" in*)Noneelseletnew_p_flags=((matchmaybe_extended_flagswithSomeflags->flags|_->failwith"impossible"))in(* The new filesz is the file end offset of this section,
* minus the existing file start offset of the phdr.
* Check that the new section begins after the old offset+filesz. *)ifNat_big_num.lessisec1.elf64_section_offset(Nat_big_num.add(Uint64_wrapper.to_bigintphdr.elf64_p_offset)(Ml_bindings.nat_big_num_of_uint64phdr.elf64_p_filesz))then(*let _ = errln "offset went backwards" in*)Noneelseletnew_p_filesz=(Nat_big_num.add(Ml_bindings.nat_big_num_of_uint64phdr.elf64_p_filesz)(ifNat_big_num.equalisec1.elf64_section_typesht_progbitsthenisec1.elf64_section_sizeelse(Nat_big_num.of_int0)))in(* The new memsz is the virtual address end address of this section,
* minus the existing start vaddr of the phdr.
* Check that the new section begins after the old vaddr+memsz. *)ifNat_big_num.lessisec1.elf64_section_addr(Nat_big_num.add(Ml_bindings.nat_big_num_of_uint64phdr.elf64_p_vaddr)(Ml_bindings.nat_big_num_of_uint64phdr.elf64_p_memsz))then(*let _ = errln "vaddr went backwards" in*)Noneelseletnew_p_memsz=(Nat_big_num.add(Ml_bindings.nat_big_num_of_uint64phdr.elf64_p_memsz)isec1.elf64_section_size)inlet(one_if_zero:Nat_big_num.num->Nat_big_num.num)=(funn->ifNat_big_num.equaln((Nat_big_num.of_int0))then(Nat_big_num.of_int1)elsen)inletnew_p_align=(lcm(one_if_zero(Ml_bindings.nat_big_num_of_uint64phdr.elf64_p_align))(one_if_zeroisec1.elf64_section_align))inSome{elf64_p_type=(Uint32_wrapper.of_bigintnew_p_type);elf64_p_flags=(Uint32_wrapper.of_bigintnew_p_flags);elf64_p_offset=(phdr.elf64_p_offset);elf64_p_vaddr=(phdr.elf64_p_vaddr);elf64_p_paddr=(phdr.elf64_p_paddr);elf64_p_filesz=(Uint64_wrapper.of_bigintnew_p_filesz);elf64_p_memsz=(Uint64_wrapper.of_bigintnew_p_memsz);elf64_p_align=(Uint64_wrapper.of_bigintnew_p_align)})letmake_new_phdrisec1tmaxpagesize1commonpagesize1:elf64_program_header_table_entry=(letrounded_down_offset=(funisec1->round_down_tocommonpagesize1isec1.elf64_section_offset)inletoffset_round_down_amount=(funisec1->Nat_big_num.sub_natisec1.elf64_section_offset(rounded_down_offsetisec1))inletrounded_down_vaddr=(funisec1->round_down_tocommonpagesize1isec1.elf64_section_addr)inletvaddr_round_down_amount=(funisec1->Nat_big_num.sub_natisec1.elf64_section_addr(rounded_down_vaddrisec1))in{elf64_p_type=(Uint32_wrapper.of_bigintt)(** Type of the segment *);elf64_p_flags=(Uint32_wrapper.of_bigint(phdr_flags_from_section_flagsisec1.elf64_section_flagsisec1.elf64_section_name_as_string))(** Segment flags *);elf64_p_offset=(Uint64_wrapper.of_bigint(rounded_down_offsetisec1))(** Offset from beginning of file for segment *);elf64_p_vaddr=(Uint64_wrapper.of_bigint(rounded_down_vaddrisec1))(** Virtual address for segment in memory *);elf64_p_paddr=(Uint64_wrapper.of_bigint((Nat_big_num.of_int0)))(** Physical address for segment *);elf64_p_filesz=(Uint64_wrapper.of_bigint(ifNat_big_num.equalisec1.elf64_section_typesht_nobitsthen(Nat_big_num.of_int0)elseNat_big_num.addisec1.elf64_section_size(offset_round_down_amountisec1)))(** Size of segment in file, in bytes *);elf64_p_memsz=(Uint64_wrapper.of_bigint(Nat_big_num.addisec1.elf64_section_size(vaddr_round_down_amountisec1)))(** Size of segment in memory image, in bytes *);elf64_p_align=(Uint64_wrapper.of_bigint(* isec.elf64_section_align *)maxpagesize1)(** Segment alignment memory for memory and file *)})(*val make_load_phdrs : forall 'abifeature. natural -> natural -> annotated_memory_image 'abifeature -> list elf64_interpreted_section -> list elf64_program_header_table_entry*)letmake_load_phdrsmaxpagesize1commonpagesize1img2section_pairs_bare_sorted_by_address:(elf64_program_header_table_entry)list=((* accumulate sections into the phdr *)letrev_list=(List.fold_left(funaccum_phdr_list->(funisec1->((* Do we have a current phdr? *)(matchaccum_phdr_listwith[]->(* no, so make one *)(*let _ = errln ("Starting the first LOAD phdr for section " ^ isec.elf64_section_name_as_string)
in*)[make_new_phdrisec1elf_pt_loadmaxpagesize1commonpagesize1]|current_phdr::more->(* can we extend it with the current section? *)(matchmaybe_extend_phdrcurrent_phdrisec1load_can_combine_flagswithNone->(*let _ = errln ("Starting new LOAD phdr for section " ^ isec.elf64_section_name_as_string)
in*)(make_new_phdrisec1elf_pt_loadmaxpagesize1commonpagesize1)::(current_phdr::more)|Somephdr->phdr::more)))))[](List.filter(funisec1->flag_is_setshf_allocisec1.elf64_section_flags&¬(flag_is_setshf_tlsisec1.elf64_section_flags))section_pairs_bare_sorted_by_address))in(*let _ = errln "Successfully made phdrs"
in*)List.revrev_list)(*val tls_extend: forall 'abifeature. abi 'abifeature -> abi 'abifeature*)lettls_extenda:'abifeatureabi=({is_valid_elf_header=(a.is_valid_elf_header);make_elf_header=(a.make_elf_header);reloc=(a.reloc);section_is_special=(a.section_is_special);section_is_large=(a.section_is_large);maxpagesize=(a.maxpagesize);minpagesize=(a.minpagesize);commonpagesize=(a.commonpagesize);symbol_is_generated_by_linker=(a.symbol_is_generated_by_linker);make_phdrs=(funmaxpagesize1->funcommonpagesize1->funfile_type->funimg2->funsection_pairs_bare_sorted_by_address->(letrev_list=(List.fold_left(funaccum_phdr_list->(funisec1->((matchaccum_phdr_listwith[]->(*let _ = errln "Making a new TLS program header" in*)[make_new_phdrisec1elf_pt_tlsmaxpagesize1commonpagesize1]|current_phdr::more->(matchmaybe_extend_phdrcurrent_phdrisec1tls_can_combine_flagswithNone->(make_new_phdrisec1elf_pt_tlsmaxpagesize1commonpagesize1)::(current_phdr::more)|Somephdr->phdr::more)))))[](List.filter(funisec1->flag_is_setshf_allocisec1.elf64_section_flags&&flag_is_setshf_tlsisec1.elf64_section_flags)section_pairs_bare_sorted_by_address))inList.rev_append(List.rev(a.make_phdrsmaxpagesize1commonpagesize1file_typeimg2section_pairs_bare_sorted_by_address))(List.revrev_list)));max_phnum=(Nat_big_num.add((Nat_big_num.of_int1))a.max_phnum);guess_entry_point=(a.guess_entry_point);pad_data=(a.pad_data);pad_code=(a.pad_code);generate_support=(a.generate_support);concretise_support=(a.concretise_support);get_reloc_symaddr=(a.get_reloc_symaddr);parse_reloc_info=(a.parse_reloc_info)})(* We use these snappily-named functions in relocation calculations. *)(*val make_default_phdrs : forall 'abifeature. natural -> natural -> natural (* file type *) -> annotated_memory_image 'abifeature -> list elf64_interpreted_section -> list elf64_program_header_table_entry*)letmake_default_phdrsmaxpagesize1commonpagesize1timg2section_pairs_bare_sorted_by_address:(elf64_program_header_table_entry)list=((* FIXME: do the shared object and dyn. exec. stuff too *)make_load_phdrsmaxpagesize1commonpagesize1img2section_pairs_bare_sorted_by_address)(*val find_start_symbol_address : forall 'abifeature. Ord 'abifeature, AbiFeatureTagEquiv 'abifeature => annotated_memory_image 'abifeature -> maybe natural*)letfind_start_symbol_addressdict_Basic_classes_Ord_abifeaturedict_Abi_classes_AbiFeatureTagEquiv_abifeatureimg2:(Nat_big_num.num)option=((* Do we have a symbol called "_start"? *)letall_defs=(Memory_image_orderings.defined_symbols_and_rangesdict_Basic_classes_Ord_abifeaturedict_Abi_classes_AbiFeatureTagEquiv_abifeatureimg2)inletget_entry_point=(fun(maybe_range,symbol_def)->ifsymbol_def.def_symname="_start"thenSome(maybe_range,symbol_def)elseNone)inletall_entry_points=(Lem_list.mapMaybeget_entry_pointall_defs)in(matchall_entry_pointswith[(maybe_range,symbol_def)]->(matchmaybe_rangewithSome(el_name,(el_off,len))->(matchPmap.lookupel_nameimg2.elementswithNone->failwith("_start symbol defined in nonexistent element `"^(el_name^"'"))|Someel_rec->(matchel_rec.startposwithNone->(*let _ = Missing_pervasives.errln "warning: saw `_start' in element with no assigned address" in *)None|Somex->(* success! *)Some(Nat_big_num.addxel_off)))|_->(*let _ = Missing_pervasives.errln "warning: `_start' symbol with no range" in*)None)|[]->(* no _start symbol *)None|_->(*let _ = Missing_pervasives.errln ("warning: saw multiple `_start' symbols: " ^
(let (ranges, defs) = unzip all_entry_points in show ranges)) in *)None))(*val pad_zeroes : natural -> list byte*)letpad_zeroesn:(char)list=(replicate0n(Char.chr(Nat_big_num.to_int((Nat_big_num.of_int0)))))(*val pad_0x90 : natural -> list byte*)letpad_0x90n:(char)list=(replicate0n(Char.chr(Nat_big_num.to_int(Nat_big_num.mul((Nat_big_num.of_int9))((Nat_big_num.of_int16))))))(* null_abi captures ABI details common to all ELF-based, System V-based systems.
* HACK: for now, specialise to 64-bit ABIs. *)(*val null_abi : abi any_abi_feature*)letnull_abi:(any_abi_feature)abi=({is_valid_elf_header=is_valid_elf64_header;make_elf_header=(make_elf64_headerelf_data_2lsbelf_osabi_none((Nat_big_num.of_int0))elf_ma_none);reloc=noop_reloc;section_is_special=elf_section_is_special;section_is_large=(funs->(funf->false));maxpagesize=(Nat_big_num.mul(Nat_big_num.mul((Nat_big_num.of_int2))((Nat_big_num.of_int256)))((Nat_big_num.of_int4096)))(* 2MB; bit of a guess, based on gdb and prelink code *);minpagesize=((Nat_big_num.of_int1024))(* bit of a guess again *);commonpagesize=((Nat_big_num.of_int4096));symbol_is_generated_by_linker=(funsymname->symname="_GLOBAL_OFFSET_TABLE_");make_phdrs=make_default_phdrs;max_phnum=((Nat_big_num.of_int2));guess_entry_point=(find_start_symbol_addressinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict);pad_data=pad_zeroes;pad_code=pad_zeroes;generate_support=((* fun _ -> *)fun_->get_empty_memory_image());concretise_support=(funimg2->img2);get_reloc_symaddr=(default_get_reloc_symaddrinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict);parse_reloc_info=parse_elf64_relocation_info})(*val got_entry_ordering : (string * maybe symbol_definition) -> (string * maybe symbol_definition) -> Basic_classes.ordering*)letgot_entry_ordering(s1,md1)(s2,md2):int=(compares1s2)(* FIXME *)letis_ifunc_def:(symbol_definition)option->bool=(funmaybe_def->(matchmaybe_defwithNone->false|Somed->Nat_big_num.equal(get_elf64_symbol_typed.def_syment)stt_gnu_ifunc))letamd64_reloc_needs_got_slot:'a->reloc_site->(symbol_definition)option->bool=(funsymref->funrr->funmaybe_def->let(rel_type1,_)=(parse_elf64_relocation_inforr.ref_relent.elf64_ra_info)inif(Pset.memrel_type1(Pset.from_listNat_big_num.compare[r_x86_64_got32;r_x86_64_gotpcrel;r_x86_64_gottpoff;r_x86_64_gotoff64;r_x86_64_gotpc32(* ; r_x86_64_gotpc32_tlsdesc *)]))thentrueelseifis_ifunc_defmaybe_defthen(* This reference is bound to a STT_GNU_IFUNC definition.
* What now needs to happen is as follows.
* - we ensure that a GOT entry is generated for this symbol (we do this here);
* - we ensure that a PLT entry (specifically .iplt) is generated for the symbol (Below);
* - on making the GOT, we also generate a .rela.plt relocation record covering the GOT slot;
* - when applying the relocation, of whatever kind, the address of the PLT slot
* is the address input to the calculation
* - the code marked by the STT_GNU_IFUNC symbol definition is not the function
* to call; it's the function that calculates the address of the function to call!
* this becomes the addend of the R_X86_64_IRELATIVE Elf64_Rela marking the GOT slot
* - note that for static linking, the GOT is usually pre-filled (cf. dynamically when it is filled by JUMP_SLOT relocs).
* ... but our GOT entries *must* have corresponding R_X86_64_IRELATIVEs generated
*)trueelsefalse)letamd64_reloc_needs_plt_slot(symref:symbol_reference_and_reloc_site)rrmaybe_defref_is_statically_linked:bool=(let(rel_type1,_)=(parse_elf64_relocation_inforr.ref_relent.elf64_ra_info)inif(Pset.memrel_type1(Pset.from_listNat_big_num.compare[r_x86_64_plt32(* NOTE: when generating shared libs, it starts to matter
* where the definition is -- anything that is locally interposable
* or undefined will need a slot. See amd64_get_reloc_symaddr. *)]))thennot(ref_is_statically_linkedrr)elseifis_ifunc_defmaybe_defthentrueelse(* not a PLT ref *)false)letamd64_find_got_label_and_elementimg2:((string*(symbol_definition)option)list*element)option=((matchPmap.lookup".got"img2.elementswithNone->(* got no GOT? okay... *)None|Somegot_el->(* Find the GOT tag. *)lettags_and_ranges=(Multimap.lookupBy0(instance_Basic_classes_Ord_Memory_image_range_tag_dictinstance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictLem_string_extra.instance_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.tagEquivinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0([]))))img2.by_tag)in(matchtags_and_rangeswith[]->failwith"error: GOT element but no ABI feature GOT tag"|[(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(l))),_)]->Some(l,got_el)|_->failwith("multiple GOT elements/tags"))))letamd64_find_plt_label_and_elementimg2:((string*(symbol_definition)option*(any_abi_feature)plt_entry_content_fn)list*element)option=((matchPmap.lookup".plt"img2.elementswithNone->(* got no PLT? okay... *)None|Someplt_el->(* Find the PLT tag. *)lettags_and_ranges=(Multimap.lookupBy0(instance_Basic_classes_Ord_Memory_image_range_tag_dictinstance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictLem_string_extra.instance_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.tagEquivinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(AbiFeature(Amd64AbiFeature(Abi_amd64.PLT0([]))))img2.by_tag)in(matchtags_and_rangeswith[]->failwith"error: PLT element but no ABI feature PLT tag"|[(AbiFeature(Amd64AbiFeature(Abi_amd64.PLT0(l))),_)]->Some(l,plt_el)|_->failwith("multiple PLT elements/tags"))))letgot_slot_index_for_symnamedict_Basic_classes_Eq_asymnamegot_label:(int)option=(Lem_list.find_index(fun(s,_)->dict_Basic_classes_Eq_a.isEqual_methodssymname)got_label)(*val amd64_get_reloc_symaddr : symbol_definition -> annotated_memory_image any_abi_feature -> list (maybe element_range * symbol_definition) -> maybe reloc_site -> natural*)letamd64_get_reloc_symaddrthe_input_defoutput_imgranges_and_defsmaybe_reloc1:Nat_big_num.num=((* The default implementation simply looks up a "matching" symbol in the output image
* and calculates its address.
*
* That's normally fine, even for via-GOT references since their calculations don't
* use the symaddr. For via-PLT references, we need to use the PLT slot address.
* HMM. Isn't this duplicating the role of functions like amd64_plt_slot_addr?
* Recall that we created this get_reloc_symaddr mechanism to deal with IFUNC symbols.
* With an IFUNC symbol, we reference it simply using a PC32 relocation, but the address
* that gets filled in isn't the IFUNC address; it's the corresponding PLT slot.
* HMM: does this happen for other PC32 references? If so, we'll need this mechanism
* there. And it certainly does, because relocatable object code never uses PLT32
* relocs.
*
* I had previously tried to handle this issue in mark_fate_of_relocs, using the
* 1-argument ApplyReloc(_) and MakePIC to encode the "replacement". But at that stage,
* which is ABI-independent and happens before address assignment?, we can't know enough.
*)(* match bound_def_in_input with
Nothing -> 0
| Just the_input_def -> *)ifis_ifunc_def(Some(the_input_def))then(* We need to return the address of the "matching" PLT slot.
* PLT label entries are (symname, maybe_def, content_fn). *)(matchamd64_find_plt_label_and_elementoutput_imgwithNone->failwith"error: ifunc but no PLT"|Some(l,plt_el)->(matchLem_list.find_index(fun(symname,_,_)->symname=the_input_def.def_symname)lwith(* FIXME: using symnames seems wrong *)Someidx1->(matchplt_el.startposwithSomeaddr->Nat_big_num.addaddr(Nat_big_num.mul(Nat_big_num.of_intidx1)((Nat_big_num.of_int16)))(* size of a PLT entry *)|None->failwith"error: PLT has no address assigned")|None->(Nat_big_num.of_int0)))elsedefault_get_reloc_symaddrinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dictthe_input_defoutput_imgranges_and_defsmaybe_reloc1)(* end *)(* *)(*val amd64_generate_support : (* list (list reloc_site_resolution) -> *) list (string * annotated_memory_image any_abi_feature) -> annotated_memory_image any_abi_feature*)letamd64_generate_support(* reloc_resolution_lists *)input_fnames_and_imgs:(any_abi_feature)annotated_memory_image=((* We generate a basic GOT. At the moment we can only describe the GOT
* contents abstractly, not as its binary content, because addresses
* have not yet been fixed.
*
* To do this, we create a set of Abi_amd64.GOTEntry records, one for
* each distinct symbol that is referenced by one or more GOT-based relocations.
* To enumerate these, we look at all the symbol refs in the image.
*)letref_is_statically_linked=(fun_->true)inlet(fnames,input_imgs)=(List.splitinput_fnames_and_imgs)inlettags_and_ranges_by_image=(Lem_list.mapi(funi->fun(fname1,img2)->(i,fname1,Multimap.lookupBy0(instance_Basic_classes_Ord_Memory_image_range_tag_dictinstance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictLem_string_extra.instance_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.tagEquivinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(SymbolRef(null_symbol_reference_and_reloc_site))img2.by_tag))input_fnames_and_imgs)inletrefs_via_got=(list_concat_map(fun(i,fname1,tags_and_ranges)->Lem_list.mapMaybe(fun(tag,maybe_range)->(matchtagwithSymbolRef(symref)->(* Is this ref a relocation we're going to apply, and does it reference the GOT? *)(match(symref.maybe_reloc,symref.maybe_def_bound_to)with(None,_)->None|(Somerr,Some(ApplyReloc,maybe_def))->ifamd64_reloc_needs_got_slotsymrefrrmaybe_defthen(*let _ = errln ("Saw a via-GOT symbol reference: to `" ^ symref.ref.ref_symname ^ "' coming from linkable " ^ (show i) ^ " (" ^
fname ^ "), logically from section " ^ (show rr.ref_src_scn)) in *)Some(symref.ref.ref_symname,maybe_def)elseNone|(Somerr,Some(makePIC0,maybe_def))->failwith"FIXME: PIC support please")|_->failwith"impossible: reloc site tag is not a SymbolRef"))tags_and_ranges)tags_and_ranges_by_image)inlet(symnames,maybe_defs)=(List.splitrefs_via_got)in(*let _ = errln ("GOT includes defs with names: " ^ (show (Set_extra.toList (Set.fromList symnames))))
in*)letgot_pairs_set=(Pset.from_list(pairComparecompare(maybeComparecompare))refs_via_got)inletgot_defs_set=(Pset.from_list(maybeComparecompare)maybe_defs)in(* This is where we fix the order of the GOT entries. *)letgot_pairs_list=(Pset.elementsgot_pairs_set)inletgot_idx_and_maybe_def_by_symname_map=(Lem_map.fromList(Lem_map.instance_Map_MapKeyType_var_dictinstance_Basic_classes_SetType_var_dict)(mapi(funslot_idx->fun(symname,maybe_def)->(symname,(slot_idx,maybe_def)))got_pairs_list))inletgot_ifunc_set=(letx2=(Pset.from_list(maybeComparecompare)[])inPset.fold(funmaybe_dx2->ifis_ifunc_defmaybe_dthenPset.addmaybe_dx2elsex2)got_defs_setx2)in(* Quirk: what if we have the same def appearing under two different symnames?
* This shouldn't happen, at present.
* What if we have the same symname related to two different defs? This also
* shouldn't happen, because only global symbols go in the GOT, so we don't have
* to worry about local symbols with the same name as another symbol. But still, it
* could plausibly happen in some situations with weird symbol visibilities or binding. *)(* if Set.size pairs_set <> Set.size defs_set then
failwith "something quirky going on with GOT symbol defs and their names"
else *)(* let name_def_pairs = List.foldl (fun acc -> fun (idx, symname, (maybe_range, rr)) ->
Set.insert (
symname, (match rr.maybe_def_bound_to with
Map.lookup symname acc with
Nothing -> [item]
| Just l -> item :: l
end) acc) {} refs_via_got
in *)letgot_nentries=(Nat_big_num.of_int(Pset.cardinalgot_pairs_set))inletgot_entrysize=((Nat_big_num.of_int8))in(* We also need a PLT... sort of. We need a way to resolve via-PLT relocs.
* But we might do so without actually creating a (non-zero-length) PLT.
* Again, this is to accommodate the sorts of optimisations the GNU linker does.
*
* Note that every PLT entry has a corresponding GOT entry. Here we are simply
* enumerating the via-PLT relocs that imply a PLT entry. We look their GOT
* slots up later, by symbol name. *)letrefs_via_plt=(list_concat_map(fun(i,fname1,tags_and_ranges)->Lem_list.mapMaybe(fun(tag,maybe_range)->(matchtagwithSymbolRef(symref)->(* Is this ref a relocation we're going to apply, and does it reference the GOT? *)(match(symref.maybe_reloc,symref.maybe_def_bound_to)with(None,_)->None|(Somerr,Some(ApplyReloc,maybe_def))->ifamd64_reloc_needs_plt_slotsymrefrrmaybe_defref_is_statically_linkedthen(*let _ = if is_ifunc_def maybe_def then
(* we ensure that a PLT entry (specifically .iplt) is generated for the symbol *)
errln ("Saw a reference to IFUNC symbol `" ^ symref.ref.ref_symname ^ "'; ref is coming from linkable " ^ (show i) ^ " (" ^
fname ^ "), relent idx " ^ (show rr.ref_rel_idx) ^ " logically from section " ^ (show rr.ref_src_scn) )
else
errln ("Saw a via-PLT symbol reference: to `" ^ symref.ref.ref_symname ^ "' coming from linkable " ^ (show i) ^ " (" ^
fname ^ "), relent idx " ^ (show rr.ref_rel_idx) ^ " logically from section " ^ (show rr.ref_src_scn) ^
match maybe_def with Just _ -> ", with definition" | Nothing -> ", not bound to anything" end
)
in*)Some(symref.ref.ref_symname,maybe_def)elseNone|(Somerr,Some(makePIC0,maybe_def))->failwith"FIXME: PIC support please")|_->failwith"impossible: reloc site tag is not a SymbolRef"))tags_and_ranges)tags_and_ranges_by_image)in(*let _ = errln ("Saw " ^ (show (length refs_via_plt)) ^ " relocations of a via-PLT type")
in*)(* account for the optimisations we did on GOT slots *)letrefs_via_plt_having_got_slot=(Lem_list.mapMaybe(fun(symname,_)->(matchPmap.lookupsymnamegot_idx_and_maybe_def_by_symname_mapwithSome(idx1,maybe_d)->Some(symname,idx1,maybe_d)|None->None))refs_via_plt)in(*let _ = errln ("Saw " ^ (show (length refs_via_plt_having_got_slot)) ^ " relocations of a via-PLT type where we instantiated a GOT slot for the symbol")
in*)let(plt_symnames,plt_got_idxs,plt_ref_bound_to_maybe_defs)=(unzip3refs_via_plt_having_got_slot)inletplt_symnames_excluding_header=(Pset.elements((Pset.from_listcompareplt_symnames)))in(*let _ = errln ("PLT symnames: " ^ (show plt_symnames_excluding_header))
in*)letn_iplt_entries=(Pset.cardinalgot_ifunc_set)(* The content of the IPLT entries depends on the address assignment of GOT slots
* and the IFUNCs that they reference. We need to reserve space for them here, though. *)in(*let _ = errln ("We think there should be " ^ (show n_iplt_entries) ^ " PLT entries due to references to IFUNC symbols")
in*)(* let got_entries_referencing_functions = (List.filter (fun (symname, maybe_def) ->
match def with
Just d -> d.def_syment
| Nothing -> false
end) refs_via_got)
in *)letplt_needs_header_entry=((List.lengthplt_symnames_excluding_header)>n_iplt_entries)in(*let _ = errln ("PLT needs header entry? " ^ (show plt_needs_header_entry))
in*)lettotal_n_plt_entries=(Nat_big_num.add(ifplt_needs_header_entrythen(Nat_big_num.of_int1)else(Nat_big_num.of_int0))(Missing_pervasives.lengthplt_symnames_excluding_header))in(*let _ = errln ("PLT total entry count: " ^ (show total_n_plt_entries))
in*)letnew_by_range=(Pset.from_list(pairCompare(maybeCompare(pairComparecompare(pairCompareNat_big_num.compareNat_big_num.compare)))compare)[(Some(".plt",((Nat_big_num.of_int0),Nat_big_num.mul((Nat_big_num.of_int16))total_n_plt_entries)),AbiFeature(Amd64AbiFeature(Abi_amd64.PLT0((* header content fn *)(* the header entry is required only for dynamic linking, which is not supported yet *)(* (if plt_needs_header_entry then
("", Nothing, (((fun (got_base_addr : natural) -> fun (plt_base_addr : natural) ->
(0, [byte_of_natural 0; byte_of_natural 0; byte_of_natural 0; byte_of_natural 0;
byte_of_natural 0; byte_of_natural 0; byte_of_natural 0; byte_of_natural 0;
byte_of_natural 0; byte_of_natural 0; byte_of_natural 0; byte_of_natural 0;
byte_of_natural 0; byte_of_natural 0; byte_of_natural 0; byte_of_natural 0]))) : plt_entry_content_fn any_abi_feature))
else ("", Nothing, (((fun (got_base_addr : natural) -> fun (plt_base_addr : natural) -> (0, []))) : plt_entry_content_fn any_abi_feature))
)
++ *)(mapi(funplt_entry_idx_not_counting_header->(funsymname->(* We want to label the PLT entry with a function that
* - accepts the PLT base address, the GOT base address and the GOT slot number;
* - closure-captures whatever else it needs (whether we're inserting a PLT header);
* - yields the *full contents of the PLT entry* before relocation.
* - recall that PLT entries might be "header" (the special one at the start),
* "normal" (to be relocated with R_X86_64_JUMP_SLOT)
* or "irelative" (to be relocated with R_X86_64_IRELATIVE).
* Q. Why are R_X86_64_JUMP_SLOT necessary?
* The PLT entries are doing relative addressing, and
* the offset to the GOT entry is known at link time,
* so the linker should be able to fill them in. In
* fact, it does. HMM. Understand this better. *)(* What is the GOT slot number? *)let(got_slot_idx,maybe_def)=((matchPmap.lookupsymnamegot_idx_and_maybe_def_by_symname_mapwithSome(idx1,maybe_d)->(Nat_big_num.of_intidx1,maybe_d)|None->failwith("GOT does not contain symbol `"^(symname^"' required by PLT entry"))))in(symname,maybe_def,((fun(got_base_addr:Nat_big_num.num)->fun(plt_base_addr:Nat_big_num.num)->(* Okay, now we can generate the entry. NOTE that we're lexically still in generate_support,
* but we'll be called from concretise_support. The code that generates the header
* entry is actually in concretise_support.
*
* If the entry is a normal entry, it looks like
*
0x0000000000400410 <+0>: ff 25 02 0c 20 00 jmpq *0x200c02(%rip) # 0x601018 <puts@got.plt>
0x0000000000400416 <+6>: 68 00 00 00 00 pushq $0x0
0x000000000040041b <+11>: e9 e0 ff ff ff jmpq 0x400400
*
* If the entry is an irelative entry, it looks like
*
400350: ff 25 02 fd 2b 00 jmpq *0x2bfd02(%rip) # 6c0058 <_GLOBAL_OFFSET_TABLE_+0x58>
400356: 68 00 00 00 00 pushq $0x0
40035b: e9 00 00 00 00 jmpq 400360 <check_one_fd.part.0>
* ... i.e. basically the same but the pushq and jmpq have literal-zero args (they're not used).
*)letthis_plt_slot_base_addr=(Nat_big_num.addplt_base_addr(Nat_big_num.mul((Nat_big_num.of_int16))(Nat_big_num.add(Nat_big_num.of_intplt_entry_idx_not_counting_header)(ifplt_needs_header_entrythen(Nat_big_num.of_int1)else(Nat_big_num.of_int0)))))in(*let _ = Missing_pervasives.errln ("PLT slot base address for symname `" ^ symname ^ "': 0x" ^
(hex_string_of_natural this_plt_slot_base_addr))
in*)letgot_slot_addr=(Nat_big_num.addgot_base_addr(Nat_big_num.mul((Nat_big_num.of_int8))got_slot_idx))in(*let _ = Missing_pervasives.errln ("GOT slot address for symname `" ^ symname ^ "' (idx " ^ (show got_slot_idx) ^ "): 0x" ^
(hex_string_of_natural got_slot_addr))
in*)letmaybe_header_entry_address=(ifplt_needs_header_entrythenSome(plt_base_addr)elseNone)inletoffset_to_got_slot=(Nat_big_num.sub(got_slot_addr)((Nat_big_num.addthis_plt_slot_base_addr((Nat_big_num.of_int6)))))in(*let _ = Missing_pervasives.errln ("PLT's PC-relative index to GOT slot for symname `" ^ symname ^ "' (GOT idx " ^ (show got_slot_idx) ^ ") is (decimal)" ^
(show offset_to_got_slot))
in*)letcontent_bytes=(List.rev_append(List.rev(List.rev_append(List.rev(List.rev_append(List.rev(List.rev_append(List.rev(List.rev_append(List.rev[Char.chr(Nat_big_num.to_int((Nat_big_num.of_int255)));Char.chr(Nat_big_num.to_int((Nat_big_num.of_int37)))])(* offset to the GOT entry, from the *next* instruction start, signed 32-bit LE *)(to_le_signed_bytes((Nat_big_num.of_int4))offset_to_got_slot)))[Char.chr(Nat_big_num.to_int((Nat_big_num.of_int104)))]))(* plt slot number not including header, 32-bit LE *)(to_le_unsigned_bytes((Nat_big_num.of_int4))((Nat_big_num.of_intplt_entry_idx_not_counting_header)))))[Char.chr(Nat_big_num.to_int((Nat_big_num.of_int233)))]))(to_le_signed_bytes((Nat_big_num.of_int4))(ifis_ifunc_defmaybe_defthen(Nat_big_num.of_int0)else(matchmaybe_header_entry_addresswithNone->failwith"normal PLT entry but no PLT header!"|Someheader_entry_address->Nat_big_num.sub(header_entry_address)((Nat_big_num.addthis_plt_slot_base_addr((Nat_big_num.of_int16))))))))in(*let _ = errln ("Created a PLT entry consisting of " ^ (show (length content_bytes)) ^ " bytes.")
in*)(this_plt_slot_base_addr,content_bytes)(*
match maybe_def with
Nothing -> 0
| Just sd ->
match Memory_image_orderings.find_defs_matching sd img with
[] -> failwith ("no matching definitions for PLT entry named " ^ symname)
| [(Just(def_el_name, (def_start, def_len)), d)] ->
match element_and_offset_to_address (def_el_name, def_start) img with
Nothing -> failwith ("PLT: no address for definition offset in element " ^ def_el_name)
| Just x ->
let _ = errln ("PLT slot for symbol `" ^ symname ^
"' calculated at (non-PLT) address 0x" ^ (hex_string_of_natural x) ^
" (offset 0x" ^ (hex_string_of_natural def_start) ^ " in element " ^ def_el_name ^ ")")
in
x
end
| _ -> failwith ("multiple matching definitions for PLT entry named " ^ symname)
end
end
*)):any_abi_featureplt_entry_content_fn))))plt_symnames)))));(Some(".plt",((Nat_big_num.of_int0),Nat_big_num.mul((Nat_big_num.of_int16))total_n_plt_entries)),FileFeature(ElfSection((Nat_big_num.of_int1),{elf64_section_name=((Nat_big_num.of_int0))(* ignored *);elf64_section_type=sht_progbits;elf64_section_flags=shf_alloc;elf64_section_addr=((Nat_big_num.of_int0))(* ignored -- covered by element *);elf64_section_offset=((Nat_big_num.of_int0))(* ignored -- will be replaced when file offsets are assigned *);elf64_section_size=(Nat_big_num.mul((Nat_big_num.of_int16))total_n_plt_entries)(* ignored? NO, we use it in linker_script to avoid plumbing through the element record *);elf64_section_link=((Nat_big_num.of_int0));elf64_section_info=((Nat_big_num.of_int0));elf64_section_align=((Nat_big_num.of_int16));elf64_section_entsize=((Nat_big_num.of_int16));elf64_section_body=Byte_sequence.empty(* ignored *);elf64_section_name_as_string=".plt"})))(* For each GOT entry that corresponds to a thread-local symbol, we also need to
* generate a relocation record. HMM. These new relocation records are ones we don't
* yet have decisions for. That might be a problem.
*
* In fact, this approach is not appropriate for static linking. Just put the offsets
* in there when we concretise the GOT. Something like this will be good for
* dynamic linking, though. At the moment, creating a SymbolRef at this stage
* is problematic because it's not in the bindings list. When we generate shared
* objects, we'll have to revisit that code. *)(* (Just(".got", (i * got_entrysize, 8)), SymbolRef( <|
ref = <| ref_symname = symname
; ref_syment = sd.def_syment
; ref_sym_scn = 0
; ref_sym_idx = 0
|>
; maybe_def_bound_to = Just(ApplyReloc, Just sd)
; maybe_reloc = Just(
<|
ref_relent =
<| elf64_ra_offset = elf64_addr_of_natural 0
; elf64_ra_info = elf64_xword_of_natural r_x86_64_tpoff64
; elf64_ra_addend = elf64_sxword_of_integer 0
|>
; ref_rel_scn = 0
; ref_rel_idx = 0
; ref_src_scn = 0
|>
)
|>))
| forall ((i, symname, sd) IN (Set.fromList (mapMaybei (fun i -> fun (symname, maybe_def) ->
match maybe_def with Nothing -> Nothing | Just sd -> Just(i, symname, sd) end) refs_via_got)))
| get_elf64_symbol_type sd.def_syment = stt_tls
*);(Some(".got",((Nat_big_num.of_int0),Nat_big_num.mulgot_nentriesgot_entrysize)),AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(got_pairs_list))));(Some(".got",((Nat_big_num.of_int0),Nat_big_num.mulgot_nentriesgot_entrysize)),FileFeature(ElfSection((Nat_big_num.of_int2),{elf64_section_name=((Nat_big_num.of_int0))(* ignored *);elf64_section_type=sht_progbits;elf64_section_flags=(Nat_big_num.bitwise_orshf_writeshf_alloc);elf64_section_addr=((Nat_big_num.of_int0))(* ignored -- covered by element *);elf64_section_offset=((Nat_big_num.of_int0))(* ignored -- will be replaced when file offsets are assigned *);elf64_section_size=(Nat_big_num.mulgot_nentriesgot_entrysize)(* ignored? NO, we use it in linker_script to avoid plumbing through the element record *);elf64_section_link=((Nat_big_num.of_int0));elf64_section_info=((Nat_big_num.of_int0));elf64_section_align=((Nat_big_num.of_int8));elf64_section_entsize=got_entrysize;elf64_section_body=Byte_sequence.empty(* ignored *);elf64_section_name_as_string=".got"})));(* FIXME: I've a feeling _GLOBAL_OFFSET_TABLE_ generally doesn't mark the *start* of the GOT;
* it's some distance in. What about .got.plt? *)(Some(".got",((Nat_big_num.of_int0),Nat_big_num.mulgot_nentriesgot_entrysize)),SymbolDef({def_symname="_GLOBAL_OFFSET_TABLE_";def_syment=({elf64_st_name=(Uint32_wrapper.of_bigint((Nat_big_num.of_int0)))(* ignored *);elf64_st_info=(Uint32_wrapper.of_bigint((Nat_big_num.of_int0)))(* FIXME *);elf64_st_other=(Uint32_wrapper.of_bigint((Nat_big_num.of_int0)))(* FIXME *);elf64_st_shndx=(Uint32_wrapper.of_bigint((Nat_big_num.of_int1)));elf64_st_value=(Uint64_wrapper.of_bigint((Nat_big_num.of_int0)))(* ignored *);elf64_st_size=(Uint64_wrapper.of_bigint(Nat_big_num.mulgot_nentriesgot_entrysize))(* FIXME: start later, smaller size? zero size? *)});def_sym_scn=((Nat_big_num.of_int1));def_sym_idx=((Nat_big_num.of_int1));def_linkable_idx=((Nat_big_num.of_int0))}));(Some(".rela.iplt",((Nat_big_num.of_int0),(* size of an Elf64_Rela *)Nat_big_num.mul((Nat_big_num.of_int24))(Nat_big_num.of_intn_iplt_entries))),FileFeature(ElfSection((Nat_big_num.of_int3),{elf64_section_name=((Nat_big_num.of_int0))(* ignored *);elf64_section_type=sht_rela;elf64_section_flags=(Nat_big_num.bitwise_orshf_allocshf_info_link);elf64_section_addr=((Nat_big_num.of_int0))(* ignored -- covered by element *);elf64_section_offset=((Nat_big_num.of_int0))(* ignored -- will be replaced when file offsets are assigned *);elf64_section_size=((* size of an Elf64_Rela *)Nat_big_num.mul((Nat_big_num.of_int24))(Nat_big_num.of_intn_iplt_entries))(* ignored? NO, we use it in linker_script to avoid plumbing through the element record *);elf64_section_link=((Nat_big_num.of_int0));elf64_section_info=((* FIXME: want this to be the PLT section shndx *)(Nat_big_num.of_int0));elf64_section_align=((Nat_big_num.of_int8));elf64_section_entsize=((Nat_big_num.of_int24));elf64_section_body=Byte_sequence.empty(* ignored *);elf64_section_name_as_string=".rela.iplt"})))])in{elements=(Pmap.add".got"{startpos=None;length1=(Some(Nat_big_num.mulgot_nentriesgot_entrysize));contents=([])}(Pmap.add".plt"{startpos=None;length1=(letlen=(Nat_big_num.mul((Nat_big_num.of_int16))total_n_plt_entries)in(*let _ = errln ("PLT length in element: " ^ (show len) ^ " bytes")
in *)Some(Nat_big_num.mul((Nat_big_num.of_int16))total_n_plt_entries));contents=([])}(Pmap.add".rela.iplt"{startpos=None;length1=(Some((* size of an Elf64_Rela *)Nat_big_num.mul((Nat_big_num.of_int24))(Nat_big_num.of_intn_iplt_entries)));contents=([])}(Pmap.emptycompare))));by_tag=(by_tag_from_by_range(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)))instance_Basic_classes_SetType_var_dictnew_by_range);by_range=new_by_range})(*val amd64_concretise_support : annotated_memory_image any_abi_feature -> annotated_memory_image any_abi_feature*)letamd64_concretise_supportorig_img:(any_abi_feature)annotated_memory_image=((*let _ = errln "Concretising amd64 ABI support structures"
in*)(* Fill in the GOT contents. *)(matchamd64_find_got_label_and_elementorig_imgwithNone->orig_img(* no GOT, but that's okay *)|Some(got_l,got_el)->letgot_base_addr=((matchgot_el.startposwithSomea->a|None->failwith"GOT has no address assigned"))inlet(ranges_and_defs:(element_rangeoption*symbol_definition)list)=(Memory_image_orderings.defined_symbols_and_rangesinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dictorig_img)inletgot_entry_bytes_for=(funimg2->funsymname->funmaybe_def->funplt_l->funmaybe_plt_el->(matchmaybe_defwithNone->replicate0((Nat_big_num.of_int8))(Char.chr(Nat_big_num.to_int((Nat_big_num.of_int0))))|Somesd->(* What should the GOT slot be initialized to point to?
* If there's a PLT entry, we should point to that + 6,
* i.e. the second instruction.
*
* If there's not, then it might be a thread-local. *)(matchLem_list.find_index(fun(plt_symname,_,_)->symname=plt_symname)plt_lwithSomeplt_slot_idx->(matchmaybe_plt_elwithNone->failwith"GOT slot with PLT entry but no PLT element"|Someplt_el->(matchplt_el.startposwithSomeaddr->natural_to_le_byte_list_padded_to((Nat_big_num.of_int8))(Nat_big_num.add(Nat_big_num.addaddr(Nat_big_num.mul(Nat_big_num.of_intplt_slot_idx)((Nat_big_num.of_int16))))((Nat_big_num.of_int6)))|None->failwith("no PLT!")))|None->(* Just look for a definition. *)(matchMemory_image_orderings.find_defs_matchingsdranges_and_defswith[]->failwith("no matching definitions for GOT entry named "^symname)|[(Some(def_el_name,(def_start,def_len)),d)]->(matchelement_and_offset_to_address(def_el_name,def_start)img2withNone->failwith("no address for definition offset in element "^def_el_name)|Somex->(* If sd is a TLS symbol, we want its offset from the *end* of the
* TLS segment. *)(* FIXME: factor out this logic so that it lives in the TLS ABI spec. *)ifNat_big_num.equal(get_elf64_symbol_typesd.def_syment)stt_tlsthen(* FIXME: the right way to do this is to mark the segments in the image
* *first*. They can't have ranges, because they span many elements,
* but they can have vaddr ranges as arguments. *)letoffs=(i2n_signed64(Nat_big_num.sub((Nat_big_num.of_int0))((Nat_big_num.of_int8))))in(*let _ = errln ("GOT slot for TLS symbol `" ^ symname ^
"' created containing offset 0x" ^ (hex_string_of_natural offs))
in*)natural_to_le_byte_listoffselse(*let _ = errln ("GOT slot for symbol `" ^ symname ^
"' created pointing to address 0x" ^ (hex_string_of_natural x) ^
" (offset 0x" ^ (hex_string_of_natural def_start) ^ " in element " ^ def_el_name ^ ")")
in*)natural_to_le_byte_list_padded_to((Nat_big_num.of_int8))x)|[(None,_)]->failwith("matching definition for GOT entry named "^(symname^" has no range"))|_->failwith("multiple matching definitions for GOT entry named "^symname)))))inletconcretise_got=(funimg2->funplt_l->funmaybe_plt_el->letl=got_l(* Just(got_el_name, (got_start_off, got_len)))] -> *)in(*let _ = errln ("Concretising a GOT of " ^ (show (length l)) ^ " entries.")
in*)letgot_entry_contents=(Lem_list.map(fun(symname,maybe_def)->Lem_list.map(funb->Someb)(got_entry_bytes_forimg2symnamemaybe_defplt_lmaybe_plt_el))l)in(* We replace the GOT element's contents with the concrete addresses
* of the symbols it should contain. We leave the metadata label in there,
* for the relocation logic to find. If we change the order of entries,
* change it there too. *)letgot_content=(List.concatgot_entry_contents)inletnew_got_el=({contents=got_content;startpos=(got_el.startpos);length1=(got_el.length1)})inletnew_got_tag=(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(l))))inletgot_range=(Some(".got",((Nat_big_num.of_int0),Nat_big_num.mul((Nat_big_num.of_int8))(lengthl))))inletnew_by_tag=(Pset.(union)(Pset.diff(img2.by_tag:((any_abi_featurerange_tag)*(element_rangeoption))Pset.set)(Pset.from_list(pairComparecompare(maybeCompare(pairComparecompare(pairCompareNat_big_num.compareNat_big_num.compare))))[(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(l))),got_range)]))(Pset.from_list(pairComparecompare(maybeCompare(pairComparecompare(pairCompareNat_big_num.compareNat_big_num.compare))))[(new_got_tag,got_range)]))inletnew_elements_map=(Pmap.add".got"new_got_el(Pmap.remove".got"img2.elements))in{elements=new_elements_map;by_tag=new_by_tag;by_range=(by_range_from_by_taginstance_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)))new_by_tag)})in(matchamd64_find_plt_label_and_elementorig_imgwithNone->concretise_gotorig_img[]None(* no PLT, but possibly a GOT *)|Some(plt_l,plt_el)->letplt_base_addr=((matchplt_el.startposwithSomea->a|None->failwith"PLT has no address assigned"))inletconcretise_plt=(funimg2->letl=plt_lin(* We replace the PLT element's contents with the concrete entries
* for each of the symbols in the table. We leave the metadata label in there,
* for the relocation logic to find. If we change the order of entries,
* change it there too. *)letall_content=(List.concat(Lem_list.map(fun(_,_,plt_content_fn)->let(_,content)=(plt_content_fngot_base_addrplt_base_addr)incontent)l))in(*let _ = errln ("Got " ^ (show (length all_content)) ^ " bytes of PLT content")
in
let _ = errln ("Generated PLT reserved " ^ (show (match plt_el.length with
Just n -> n
| Nothing -> failwith "PLT has no length"
end)) ^ " bytes of PLT content")
in*)letnew_plt_el=({contents=(Lem_list.map(funb->Someb)all_content);startpos=(plt_el.startpos);length1=(Some(lengthall_content))})inletnew_elements_map=(Pmap.add".plt"new_plt_el(Pmap.remove".plt"img2.elements))in{elements=new_elements_map;by_tag=(img2.by_tag);by_range=(img2.by_range)})inletconcretise_rela_plt=(funimg2->letmaybe_rela_plt_el=(Pmap.lookup".rela.plt"img2.elements)inletmaybe_new_rela_plt_el=((matchmaybe_rela_plt_elwithNone->(* got no .rela.plt? okay... *)(*let _ = errln "No .rela.plt found"
in*)None|Somerela_plt_el->letgot_entry_iplt_widget_for=(funsymname->funmaybe_def->(matchmaybe_defwithNone->None|Somesd->ifnot(Nat_big_num.equal(get_elf64_symbol_typesd.def_syment)stt_gnu_ifunc)thenNoneelseSome(funindex_in_got->(* This is a 24-byte Elf64_Rela. *)let(r_offset:Nat_big_num.num)(* GOT *slot* address! *)=((matchgot_el.startposwithNone->failwith"internal error: GOT has no assigned address"|Someaddr->Nat_big_num.addaddr(Nat_big_num.mul((Nat_big_num.of_int8))index_in_got)))inlet(r_info:Nat_big_num.num)=r_x86_64_irelativein(List.rev_append(List.rev(List.rev_append(List.rev(natural_to_le_byte_list_padded_to((Nat_big_num.of_int8))r_offset))(natural_to_le_byte_list_padded_to((Nat_big_num.of_int8))r_info)))(* r_addend -- address of the ifunc definition.
* NOTE that this is NOT the same as the GOT entry bytes.
* It's the actual address of the ifunc, whereas
* the GOT entry is initialized to point back into the PLT entry. *)(matchMemory_image_orderings.find_defs_matchingsdranges_and_defswith[]->failwith("impossible: IPLT entry widget found matching ifunc definition for "^symname)|[(Some(def_el_name,(def_start,def_len)),d)]->(matchelement_and_offset_to_address(def_el_name,def_start)img2withNone->failwith("no address for ifunc definition offset in element "^def_el_name)|Somex->(* If sd is a TLS symbol, we want its offset from the *end* of the
* TLS segment. *)(* FIXME: factor out this logic so that it lives in the TLS ABI spec. *)ifnot(Nat_big_num.equal(get_elf64_symbol_typesd.def_syment)stt_gnu_ifunc)thenfailwith"impossible: found ifunc definition that is not an ifunc"elsenatural_to_le_byte_list_padded_to((Nat_big_num.of_int8))x)|_->failwith"impossible: more than one ifunc definition")))(* end Just sd *)))inletrela_iplt_widgets=(Lem_list.map(fun(symname,maybe_def)->got_entry_iplt_widget_forsymnamemaybe_def)got_l)inletnew_content_bytelists=(mapi(funi->funrela_widget->(matchrela_widgetwithSomef->f(Nat_big_num.of_inti)|None->[]))rela_iplt_widgets)inletnew_contents=(Lem_list.map(funb->Someb)(List.concatnew_content_bytelists))in(*let _ = errln ("Concretised .rela.plt; first 24 bytes: " ^ (show (take 24 new_contents)))
in*)Some({contents=new_contents;startpos=(rela_plt_el.startpos);length1=(rela_plt_el.length1)})))inletnew_elements_map=((matchmaybe_new_rela_plt_elwithSomenew_rela_plt_el->Pmap.add".rela.plt"new_rela_plt_el(Pmap.remove".rela.plt"img2.elements)|None->img2.elements))in{elements=new_elements_map;by_tag=(img2.by_tag);by_range=(img2.by_range)})inconcretise_rela_plt(concretise_plt(concretise_gotorig_imgplt_l(Someplt_el))))))(*val amd64_got_slot_idx : annotated_memory_image any_abi_feature -> symbol_reference_and_reloc_site -> natural*)letamd64_got_slot_idximg2rr:Nat_big_num.num=((*let _ = errln ("Looking up GOT slot for symbol " ^ rr.ref.ref_symname) in*)(matchPmap.lookup".got"img2.elementswithNone->(* got no GOT? okay... *)failwith"got no GOT"|Somegot_el->(* Find the GOT tag. *)lettags_and_ranges=(Multimap.lookupBy0(instance_Basic_classes_Ord_Memory_image_range_tag_dictinstance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictLem_string_extra.instance_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.tagEquivinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0([]))))img2.by_tag)in(matchtags_and_rangeswith[]->failwith"error: GOT element but no ABI feature GOT tag"|[(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(l))),Some(got_el_name,(got_start_off,got_len)))]->(* Find the slot corresponding to rr, if we have one. *)letgot_addr=((matchgot_el.startposwithSomeaddr->addr|None->failwith"GOT has no addr at reloc time"))in(matchrr.maybe_def_bound_towithSome(_,Some(d))->(matchLem_list.find_index(fun(symname,maybe_def)->(Lem.option_equal(=)(Some(d))maybe_def))lwithSomeidx1->Nat_big_num.of_intidx1|None->failwith("no GOT slot for reloc against `"^(rr.ref.ref_symname^"'")))|Some(_,None)->(* HACK: look for the weak symname. Really want more (ref-based) labelling. *)(matchLem_list.find_index(fun(symname,_)->symname=rr.ref.ref_symname)lwithSomeidx1->Nat_big_num.of_intidx1|None->failwith("no GOT slot for reloc against undefined symbol `"^(rr.ref.ref_symname^"'")))|_->failwith"GOT: unbound def")|_->failwith"got bad GOT")))(*val amd64_got_slot_addr : annotated_memory_image any_abi_feature -> symbol_reference_and_reloc_site -> natural*)letamd64_got_slot_addrimg2rr:Nat_big_num.num=((matchPmap.lookup".got"img2.elementswithNone->(* got no GOT? okay... *)failwith"got no GOT"|Somegot_el->(* Find the GOT tag. *)lettags_and_ranges=(Multimap.lookupBy0(instance_Basic_classes_Ord_Memory_image_range_tag_dictinstance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictLem_string_extra.instance_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.tagEquivinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0([]))))img2.by_tag)in(matchtags_and_rangeswith[]->failwith"error: GOT element but no ABI feature GOT tag"|[(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(l))),Some(got_el_name,(got_start_off,got_len)))]->(* Find the slot corresponding to rr, if we have one. *)letgot_addr=((matchgot_el.startposwithSomeaddr->addr|None->failwith"GOT has no addr at reloc time"))inNat_big_num.add(Nat_big_num.mul((Nat_big_num.of_int8))(amd64_got_slot_idximg2rr))got_addr|_->failwith"got bad GOT")))(*val amd64_plt_slot_addr : annotated_memory_image any_abi_feature -> symbol_reference_and_reloc_site -> natural -> natural*)letamd64_plt_slot_addrimg2rrraw_addr:Nat_big_num.num=((matchPmap.lookup".plt"img2.elementswithNone->(* got no PLT? okay... under static linking this can happen.
We use the actual symbol address of the *)(*let _ = errln "Warning: no PLT, so attempting to use actual symbol address as PLT slot address"
in*)(* if raw_addr = 0 then failwith "bailing rather than resolving PLT slot to null address (perhaps conservatively)" else *)raw_addr|Someplt_el->(* Find the PLT tag. *)lettags_and_ranges=(Multimap.lookupBy0(instance_Basic_classes_Ord_Memory_image_range_tag_dictinstance_Basic_classes_Ord_Abis_any_abi_feature_dict)(instance_Basic_classes_Ord_Maybe_maybe_dict(instance_Basic_classes_Ord_tup2_dictLem_string_extra.instance_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.tagEquivinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(AbiFeature(Amd64AbiFeature(Abi_amd64.PLT0([]))))img2.by_tag)in(matchtags_and_rangeswith[]->failwith"error: PLT element but no ABI feature PLT tag"|[(AbiFeature(Amd64AbiFeature(Abi_amd64.PLT0(l))),Some(plt_el_name,(plt_start_off,plt_len)))]->letplt_addr=((matchplt_el.startposwithSomeaddr->addr|None->failwith"PLT has no addr at reloc time"))in(* Find the slot corresponding to rr, if we have one. *)(matchrr.maybe_def_bound_towithSome(_,Some(d))->(matchLem_list.mapMaybe(fun(symname,maybe_def,fn)->if(Lem.option_equal(=)(Some(d))maybe_def)thenSomefnelseNone)lwith[fn]->letgot_addr=((matchPmap.lookup".got"img2.elementswithNone->(* got no GOT? okay... *)failwith"got no GOT (applying PLT calculation)"|Somegot_el->(matchgot_el.startposwithSomeaddr->addr|None->failwith"concrete GOT has no addr")))inlet(addr,content)=(fngot_addrplt_addr)in(*let _ = errln ("Calculated PLT slot for `" ^ d.def_symname ^ "', from PLT addr " ^ (hex_string_of_natural plt_addr)
^ " and GOT addr " ^ (hex_string_of_natural got_addr) ^ ", as " ^ (hex_string_of_natural addr))
in*)addr|[]->(* failwith ("internal error: no PLT entry for reloc against `" ^ rr.ref.ref_symname ^ "'") *)(* If we got no PLT slot, we assume it's because the PLT entry was optimised out.
* So we just return the address of the symbol itself. *)(*let _ = errln ("No PLT entry for reloc against `" ^ rr.ref.ref_symname ^
"', which we assume was optimised to avoid the GOT")
in*)let(ranges_and_defs:(element_rangeoption*symbol_definition)list)=(defined_symbols_and_rangesinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dictimg2)in(matchMemory_image_orderings.find_defs_matchingdranges_and_defswith[]->(Nat_big_num.of_int0)(* HMM -- should be an error? *)|[(Some(el_name,(start_off,len)),matching_d)]->(matchelement_and_offset_to_address(el_name,start_off)img2withSomea->a|None->failwith("internal error: could not get address for PLT-short-circuited symbol `"^(rr.ref.ref_symname^"'")))|_->failwith("output image has multiple and/or no-location definitions to which via-PLT ref to `"^(rr.ref.ref_symname^"' could resolve")))|_->failwith("internal error: multiple PLT entries for reloc against `"^(rr.ref.ref_symname^"'")))|Some(_,None)->(* weak, so 0 *)(Nat_big_num.of_int0)|_->failwith"PLT: unbound def")|_->failwith"got bad PLT")))(** [amd64_base_addr rr site_addr] computes back the base address at which a
* shared object has been loaded into memory during execution. It's kind of
* lame to have this function because the linker will do the opposite operation
* when relocating, but I don't want to add a new argument to the reloc
* function. *)(*val amd64_base_addr : symbol_reference_and_reloc_site -> natural -> natural*)letamd64_base_addrrrsite_addr:Nat_big_num.num=(letreloc_site1=((matchrr.maybe_relocwith|None->failwith"amd64_base_addr: no reloc site during relocation"|Somers->rs))inletoffset=(Ml_bindings.nat_big_num_of_uint64reloc_site1.ref_relent.elf64_ra_offset)inNat_big_num.sub_natsite_addroffset)(** [amd64_reloc r] yields a function that applies relocations of type [r]. *)(*val amd64_reloc : reloc_fn any_abi_feature*)letamd64_relocr:bool*((any_abi_feature)annotated_memory_image->Nat_big_num.num->symbol_reference_and_reloc_site->Nat_big_num.num*(Nat_big_num.num->Nat_big_num.num->Nat_big_num.num->Nat_big_num.num))=((* See AMD64 ABI Draft 0.99.7 Table 4.10 (page 71) *)(match(string_of_amd64_relocation_typer)with|"R_X86_64_NONE"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int0),(funs->funa->fune->failwith"amd64_reloc: tried to apply a R_X86_64_NONE relocation"))))))|"R_X86_64_64"->(true,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->i2n(Nat_big_num.add(n2is)a)))))))|"R_X86_64_PC32"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->i2n_signed32(Nat_big_num.sub(Nat_big_num.add(n2is)a)(n2isite_addr))))))))|"R_X86_64_GOT32"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->i2n_signed32(Nat_big_num.add(n2i(amd64_got_slot_idximg2rr))a)))))))|"R_X86_64_PLT32"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->i2n_signed32(Nat_big_num.sub(Nat_big_num.add(n2i(amd64_plt_slot_addrimg2rrs))a)(n2isite_addr))))))))|"R_X86_64_COPY"->(false,(funimg2->(funsite_addr->(funrr->(size_of_copy_relocimg2rr,(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_COPY")(* FIXME *))))))|"R_X86_64_GLOB_DAT"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->s))))))|"R_X86_64_JUMP_SLOT"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->s))))))|"R_X86_64_RELATIVE"->(true,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->i2n(Nat_big_num.add(n2i(amd64_base_addrrrsite_addr))a)))))))|"R_X86_64_GOTPCREL"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->i2n_signed32(Nat_big_num.sub(Nat_big_num.add(n2i(amd64_got_slot_addrimg2rr))a)(n2isite_addr))))))))|"R_X86_64_32"->(true,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->i2n(Nat_big_num.add(n2is)a)))))))|"R_X86_64_32S"->(true,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->i2n_signed32(Nat_big_num.add(n2is)a)))))))|"R_X86_64_16"->(true,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int2),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_16")(* FIXME *))))))|"R_X86_64_PC16"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int2),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_PC16")(* FIXME *))))))|"R_X86_64_8"->(true,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int1),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_8")(* FIXME *))))))|"R_X86_64_PC8"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int1),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_PC8")(* FIXME *))))))|"R_X86_64_DTPMOD64"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_DTPMOD64")(* FIXME *))))))|"R_X86_64_DTPOFF64"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_DTPOFF64")(* FIXME *))))))|"R_X86_64_TPOFF64"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->i2n_signed64(Nat_big_num.sub((Nat_big_num.of_int0))((Nat_big_num.of_int8))))(* FIXME *))))))|"R_X86_64_TLSGD"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_TLSGD")(* FIXME *))))))|"R_X86_64_TLSLD"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_TLSLD")(* FIXME *))))))|"R_X86_64_DTPOFF32"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_DTPOFF32")(* FIXME *))))))|"R_X86_64_GOTTPOFF"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->i2n_signed32(Nat_big_num.sub(Nat_big_num.add(n2i(amd64_got_slot_addrimg2rr))a)(n2isite_addr))))))))|"R_X86_64_TPOFF32"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_TPOFF32")(* FIXME *))))))|"R_X86_64_PC64"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_PC64")(* FIXME *))))))|"R_X86_64_GOTOFF64"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_GOTOFF64")(* FIXME *))))))|"R_X86_64_GOTPC32"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_GOTPC32")(* FIXME *))))))|"R_X86_64_SIZE32"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_SIZE32")(* FIXME *))))))|"R_X86_64_SIZE64"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_SIZE64")(* FIXME *))))))|"R_X86_64_GOTPC32_TLSDESC"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int4),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_GOTPC32_TLSDESC")(* FIXME *))))))|"R_X86_64_TLSDESC_CALL"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int0)(* FIXME *),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_TLSDESC_CALL")(* FIXME *))))))|"R_X86_64_TLSDESC"->(false,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int16),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_TLSDESC")(* FIXME *))))))|"R_X86_64_IRELATIVE"->(true,(funimg2->(funsite_addr->(funrr->((Nat_big_num.of_int8),(funs->funa->fune->failwith"amd64_reloc: unimplemented R_X86_64_IRELATIVE")(* FIXME *))))))|_->failwith("unrecognised relocation "^(string_of_amd64_relocation_typer))))(*val sysv_amd64_std_abi : abi any_abi_feature*)letsysv_amd64_std_abi:(any_abi_feature)abi=({is_valid_elf_header=header_is_amd64;make_elf_header=(make_elf64_headerelf_data_2lsbelf_osabi_none((Nat_big_num.of_int0))elf_ma_x86_64);reloc=amd64_reloc;section_is_special=section_is_special2;section_is_large=(funs->(funf->flag_is_setshf_x86_64_larges.elf64_section_flags));maxpagesize=((Nat_big_num.of_int65536));minpagesize=((Nat_big_num.of_int4096));commonpagesize=((Nat_big_num.of_int4096))(* XXX: DPM, changed from explicit reference to null_abi field due to problems in HOL4. *);symbol_is_generated_by_linker=(funsymname->symname="_GLOBAL_OFFSET_TABLE_");make_phdrs=make_default_phdrs;max_phnum=((Nat_big_num.of_int2))(* incremented by extensions *);guess_entry_point=(find_start_symbol_addressinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict);pad_data=pad_zeroes;pad_code=pad_0x90;generate_support=amd64_generate_support;concretise_support=amd64_concretise_support;get_reloc_symaddr=amd64_get_reloc_symaddr;parse_reloc_info=parse_elf64_relocation_info})(*val sysv_aarch64_le_std_abi : abi any_abi_feature*)letsysv_aarch64_le_std_abi:(any_abi_feature)abi=({is_valid_elf_header=header_is_aarch64_le;make_elf_header=(make_elf64_headerelf_data_2lsbelf_osabi_none((Nat_big_num.of_int0))elf_ma_aarch64);reloc=aarch64_le_reloc;section_is_special=section_is_special2;section_is_large=(fun_->(fun_->false));maxpagesize=(Nat_big_num.mul(Nat_big_num.mul((Nat_big_num.of_int2))((Nat_big_num.of_int256)))((Nat_big_num.of_int4096)))(* 2MB; bit of a guess, based on gdb and prelink code *);minpagesize=((Nat_big_num.of_int1024))(* bit of a guess again *);commonpagesize=((Nat_big_num.of_int4096));symbol_is_generated_by_linker=(funsymname->symname="_GLOBAL_OFFSET_TABLE_");make_phdrs=make_default_phdrs;max_phnum=((Nat_big_num.of_int2))(* incremented by extensions *);guess_entry_point=(find_start_symbol_addressinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict);pad_data=pad_zeroes;pad_code=pad_zeroes;generate_support=((* fun _ -> *)fun_->get_empty_memory_image());concretise_support=(funimg2->img2);get_reloc_symaddr=(default_get_reloc_symaddrinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict);parse_reloc_info=parse_elf64_relocation_info})(*val sysv_mips64_std_abi : abi any_abi_feature*)letsysv_mips64_std_abi:(any_abi_feature)abi=({is_valid_elf_header=header_is_mips64;make_elf_header=(make_elf64_headerabi_mips64_data_encodingelf_osabi_none((Nat_big_num.of_int0))elf_ma_mips);reloc=mips64_reloc;section_is_special=elf_section_is_special;section_is_large=(funs->(funf->false));maxpagesize=abi_mips64_page_size_max;minpagesize=abi_mips64_page_size_min;commonpagesize=((Nat_big_num.of_int4096));symbol_is_generated_by_linker=(funsymname->symname="_GLOBAL_OFFSET_TABLE_");make_phdrs=make_default_phdrs;max_phnum=((Nat_big_num.of_int2));guess_entry_point=(find_start_symbol_addressinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(* TODO: on MIPS it's __start, not _start *);pad_data=pad_zeroes;pad_code=pad_zeroes;generate_support=((* fun _ -> *)fun_->get_empty_memory_image());concretise_support=(funimg2->img2);get_reloc_symaddr=(default_get_reloc_symaddrinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict);parse_reloc_info=abi_mips_parse_elf64_relocation_info})(*val sysv_cheri_mips64_std_abi : abi any_abi_feature*)letsysv_cheri_mips64_std_abi:(any_abi_feature)abi=({is_valid_elf_header=header_is_cheri_mips64;make_elf_header=(make_elf64_headerabi_cheri_mips64_data_encodingelf_osabi_none((Nat_big_num.of_int0))elf_ma_mips);reloc=cheri_mips64_reloc;section_is_special=elf_section_is_special;section_is_large=(funs->(funf->false));maxpagesize=abi_cheri_mips64_page_size_max;minpagesize=abi_cheri_mips64_page_size_min;commonpagesize=((Nat_big_num.of_int4096));symbol_is_generated_by_linker=(funsymname->symname="_GLOBAL_OFFSET_TABLE_");make_phdrs=make_default_phdrs;max_phnum=((Nat_big_num.of_int2));guess_entry_point=(find_start_symbol_addressinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)(* TODO: on MIPS it's __start, not _start *);pad_data=pad_zeroes;pad_code=pad_zeroes;generate_support=((* fun _ -> *)fun_->get_empty_memory_image());concretise_support=(funimg2->img2);get_reloc_symaddr=(default_get_reloc_symaddrinstance_Basic_classes_Ord_Abis_any_abi_feature_dictinstance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict);parse_reloc_info=parse_elf64_relocation_info})(*val all_abis : list (abi any_abi_feature)*)letall_abis:((any_abi_feature)abi)list=([sysv_amd64_std_abi;sysv_aarch64_le_std_abi;sysv_mips64_std_abi;sysv_cheri_mips64_std_abi;null_abi])