summaryrefslogtreecommitdiff
path: root/lib/ocaml_rts/linksem/abis/abis.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ocaml_rts/linksem/abis/abis.ml')
-rw-r--r--lib/ocaml_rts/linksem/abis/abis.ml1420
1 files changed, 1420 insertions, 0 deletions
diff --git a/lib/ocaml_rts/linksem/abis/abis.ml b/lib/ocaml_rts/linksem/abis/abis.ml
new file mode 100644
index 00000000..0cbd92d8
--- /dev/null
+++ b/lib/ocaml_rts/linksem/abis/abis.ml
@@ -0,0 +1,1420 @@
+(*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.
+ *)
+
+open Lem_basic_classes
+open Lem_bool
+open Lem_num
+open Lem_maybe
+open Lem_list
+open Lem_set
+(*import Map*)
+open Lem_string
+open Show
+open Lem_assert_extra
+open Error
+open Missing_pervasives
+
+open Elf_file
+open Elf_header
+open Elf_interpreted_section
+open Elf_relocation
+open Elf_symbol_table
+open Elf_program_header_table
+open Elf_section_header_table
+open Memory_image
+
+open Abi_amd64
+open Abi_amd64_relocation
+
+open Abi_aarch64_le
+open Abi_aarch64_relocation
+
+open Abi_power64
+open Abi_power64_relocation
+
+open Gnu_ext_abi
+
+open Abi_classes
+open Abi_utilities
+open Elf_types_native_uint
+
+open Memory_image_orderings
+
+(** Relocation operators and their validity on a given platform *)
+
+(*val is_valid_abi_aarch64_relocation_operator : relocation_operator -> bool*)
+let is_valid_abi_aarch64_relocation_operator op:bool=
+ ((match op with
+ | 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*)
+let is_valid_abi_aarch64_relocation_operator2 op:bool=
+ ((match op with
+ | GTLSIdx -> true
+ ))
+
+(*val is_valid_abi_amd64_relocation_operator : relocation_operator -> bool*)
+let is_valid_abi_amd64_relocation_operator op:bool=
+ ((match op with
+ | Indirect -> true
+ | _ -> false (* XXX: not sure about this? *)
+ ))
+
+(*val is_valid_abi_amd64_relocation_operator2 : relocation_operator2 -> bool*)
+let is_valid_abi_amd64_relocation_operator2 op:bool=
+ ((match op with
+ | _ -> false
+ ))
+
+(*val is_valid_abi_power64_relocation_operator : relocation_operator -> bool*)
+let is_valid_abi_power64_relocation_operator op:bool= false (* TODO *)
+
+(*val is_valid_abi_power64_relocation_operator2 : relocation_operator2 -> bool*)
+let is_valid_abi_power64_relocation_operator2 op:bool=
+ ((match op with
+ | _ -> false
+ ))
+
+(** Misc. ABI related stuff *)
+
+type any_abi_feature = Amd64AbiFeature of any_abi_feature amd64_abi_feature
+ | Aarch64LeAbiFeature of aarch64_le_abi_feature
+
+(*val anyAbiFeatureCompare : any_abi_feature -> any_abi_feature -> Basic_classes.ordering*)
+let anyAbiFeatureCompare f1 f2:int=
+ ((match (f1, f2) with
+ (Amd64AbiFeature(af1), Amd64AbiFeature(af2)) -> Abi_amd64.abiFeatureCompare0 af1 af2
+ |(Amd64AbiFeature(_), _) -> (-1)
+ |(Aarch64LeAbiFeature(af1), Amd64AbiFeature(af2)) -> 1
+ |(Aarch64LeAbiFeature(af1), Aarch64LeAbiFeature(af2)) -> abiFeatureCompare af1 af2
+ ))
+
+(*val anyAbiFeatureTagEquiv : any_abi_feature -> any_abi_feature -> bool*)
+let anyAbiFeatureTagEquiv f1 f2:bool=
+ ((match (f1, f2) with
+ (Amd64AbiFeature(af1), Amd64AbiFeature(af2)) -> Abi_amd64.abiFeatureTagEq0 af1 af2
+ |(Amd64AbiFeature(_), _) -> false
+ |(Aarch64LeAbiFeature(af1), Amd64AbiFeature(af2)) -> false
+ |(Aarch64LeAbiFeature(af1), Aarch64LeAbiFeature(af2)) -> abiFeatureTagEq af1 af2
+ ))
+
+let instance_Basic_classes_Ord_Abis_any_abi_feature_dict:(any_abi_feature)ord_class= ({
+
+ compare_method = anyAbiFeatureCompare;
+
+ isLess_method = (fun f1 -> (fun f2 -> ( Lem.orderingEqual(anyAbiFeatureCompare f1 f2) (-1))));
+
+ isLessEqual_method = (fun f1 -> (fun f2 -> Pset.mem (anyAbiFeatureCompare f1 f2)(Pset.from_list compare [(-1); 0])));
+
+ isGreater_method = (fun f1 -> (fun f2 -> ( Lem.orderingEqual(anyAbiFeatureCompare f1 f2) 1)));
+
+ isGreaterEqual_method = (fun f1 -> (fun f2 -> Pset.mem (anyAbiFeatureCompare f1 f2)(Pset.from_list compare [1; 0])))})
+
+let instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict:(any_abi_feature)abiFeatureTagEquiv_class= ({
+
+ abiFeatureTagEquiv_method = anyAbiFeatureTagEquiv})
+
+let make_elf64_header data osabi abiv ma t entry shoff phoff phnum shnum shstrndx:elf64_header=
+ ({ elf64_ident = ([elf_mn_mag0; elf_mn_mag1; elf_mn_mag2; elf_mn_mag3;
+ Uint32.of_string (Nat_big_num.to_string elf_class_64);
+ Uint32.of_string (Nat_big_num.to_string data);
+ Uint32.of_string (Nat_big_num.to_string elf_ev_current);
+ Uint32.of_string (Nat_big_num.to_string osabi);
+ Uint32.of_string (Nat_big_num.to_string abiv);
+ Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0));
+ Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0));
+ Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0));
+ Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0));
+ Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0));
+ Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0));
+ Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))])
+ ; elf64_type = (Uint32.of_string (Nat_big_num.to_string t))
+ ; elf64_machine = (Uint32.of_string (Nat_big_num.to_string ma))
+ ; elf64_version = (Uint32.of_string (Nat_big_num.to_string elf_ev_current))
+ ; elf64_entry = (Uint64.of_string (Nat_big_num.to_string entry))
+ ; elf64_phoff = (Uint64.of_string (Nat_big_num.to_string phoff))
+ ; elf64_shoff = (Uint64.of_string (Nat_big_num.to_string shoff))
+ ; elf64_flags = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0)))
+ ; elf64_ehsize = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 64)))
+ ; elf64_phentsize= (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 56)))
+ ; elf64_phnum = (Uint32.of_string (Nat_big_num.to_string phnum))
+ ; elf64_shentsize= (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 64)))
+ ; elf64_shnum = (Uint32.of_string (Nat_big_num.to_string shnum))
+ ; elf64_shstrndx = (Uint32.of_string (Nat_big_num.to_string shstrndx))
+ })
+
+(*val phdr_flags_from_section_flags : natural -> string -> natural*)
+let phdr_flags_from_section_flags section_flags sec_name:Nat_big_num.num=
+ (let flags = (Nat_big_num.bitwise_or elf_pf_r (Nat_big_num.bitwise_or
+ (if flag_is_set shf_write section_flags then elf_pf_w else Nat_big_num.of_int 0)
+ (if flag_is_set shf_execinstr section_flags then elf_pf_x else Nat_big_num.of_int 0)))
+ 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*)
+let phdr_is_writable flags:bool= (Nat_big_num.equal
+ (Nat_big_num.bitwise_and flags elf_pf_w) elf_pf_w)
+
+type can_combine_flags_fn = Nat_big_num.num Pset.set -> Nat_big_num.num option
+
+(* 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*)
+let load_can_combine_flags flagsets:(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. *)let flagslist = (Pset.elements flagsets)
+ in
+ let union_flags = (List.fold_left Nat_big_num.bitwise_or(Nat_big_num.of_int 0) flagslist)
+ in
+ if List.exists phdr_is_writable flagslist
+ then
+ if List.for_all phdr_is_writable flagslist then Some union_flags
+ else None
+ else
+ Some union_flags)
+
+(*val tls_can_combine_flags : can_combine_flags_fn*)
+let tls_can_combine_flags flagsets:(Nat_big_num.num)option= (Some (List.fold_left Nat_big_num.bitwise_or(Nat_big_num.of_int 0) (Pset.elements flagsets)))
+
+let maybe_extend_phdr phdr isec1 can_combine_flags:(elf64_program_header_table_entry)option=
+ (let new_p_type = (Nat_big_num.of_string (Uint32.to_string phdr.elf64_p_type))
+ in
+ let this_section_phdr_flags = (phdr_flags_from_section_flags isec1.elf64_section_flags isec1.elf64_section_name_as_string)
+ in
+ let maybe_extended_flags = (can_combine_flags(Pset.from_list Nat_big_num.compare [ this_section_phdr_flags; Nat_big_num.of_string (Uint32.to_string phdr.elf64_p_flags) ]))
+ in
+ if (Lem.option_equal Nat_big_num.equal maybe_extended_flags None) then (*let _ = errln "flag mismatch" in*) None
+ else let new_p_flags = ((match maybe_extended_flags with Some flags -> 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. *)
+ if Nat_big_num.less isec1.elf64_section_offset (Nat_big_num.add (Nat_big_num.of_string (Uint64.to_string phdr.elf64_p_offset)) (Ml_bindings.nat_big_num_of_uint64 phdr.elf64_p_filesz))
+ then (*let _ = errln "offset went backwards" in*) None
+ else
+ let new_p_filesz = (Nat_big_num.add (Ml_bindings.nat_big_num_of_uint64 phdr.elf64_p_filesz) (if Nat_big_num.equal isec1.elf64_section_type sht_progbits then isec1.elf64_section_size else Nat_big_num.of_int 0))
+ 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. *)
+ if Nat_big_num.less isec1.elf64_section_addr (Nat_big_num.add (Ml_bindings.nat_big_num_of_uint64 phdr.elf64_p_vaddr) (Ml_bindings.nat_big_num_of_uint64 phdr.elf64_p_memsz))
+ then (*let _ = errln "vaddr went backwards" in*) None
+ else
+ let new_p_memsz = (Nat_big_num.add (Ml_bindings.nat_big_num_of_uint64 phdr.elf64_p_memsz) isec1.elf64_section_size)
+ in
+ let (one_if_zero : Nat_big_num.num -> Nat_big_num.num) = (fun n -> if Nat_big_num.equal n(Nat_big_num.of_int 0) then Nat_big_num.of_int 1 else n)
+ in
+ let new_p_align = (lcm (one_if_zero (Ml_bindings.nat_big_num_of_uint64 phdr.elf64_p_align)) (one_if_zero isec1.elf64_section_align))
+ in
+ Some
+ { elf64_p_type = (Uint32.of_string (Nat_big_num.to_string new_p_type))
+ ; elf64_p_flags = (Uint32.of_string (Nat_big_num.to_string new_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.of_string (Nat_big_num.to_string new_p_filesz))
+ ; elf64_p_memsz = (Uint64.of_string (Nat_big_num.to_string new_p_memsz))
+ ; elf64_p_align = (Uint64.of_string (Nat_big_num.to_string new_p_align))
+ })
+
+let make_new_phdr isec1 t maxpagesize1 commonpagesize1:elf64_program_header_table_entry=
+ (let rounded_down_offset = (fun isec1 -> round_down_to commonpagesize1 isec1.elf64_section_offset)
+ in
+ let offset_round_down_amount = (fun isec1 -> Nat_big_num.sub_nat isec1.elf64_section_offset (rounded_down_offset isec1))
+ in
+ let rounded_down_vaddr = (fun isec1 -> round_down_to commonpagesize1 isec1.elf64_section_addr)
+ in
+ let vaddr_round_down_amount = (fun isec1 -> Nat_big_num.sub_nat isec1.elf64_section_addr (rounded_down_vaddr isec1))
+ in
+ { elf64_p_type = (Uint32.of_string (Nat_big_num.to_string t)) (** Type of the segment *)
+ ; elf64_p_flags = (Uint32.of_string (Nat_big_num.to_string (phdr_flags_from_section_flags isec1.elf64_section_flags isec1.elf64_section_name_as_string))) (** Segment flags *)
+ ; elf64_p_offset = (Uint64.of_string (Nat_big_num.to_string (rounded_down_offset isec1))) (** Offset from beginning of file for segment *)
+ ; elf64_p_vaddr = (Uint64.of_string (Nat_big_num.to_string (rounded_down_vaddr isec1))) (** Virtual address for segment in memory *)
+ ; elf64_p_paddr = (Uint64.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (** Physical address for segment *)
+ ; elf64_p_filesz = (Uint64.of_string (Nat_big_num.to_string (if Nat_big_num.equal isec1.elf64_section_type sht_nobits then Nat_big_num.of_int 0 else Nat_big_num.add isec1.elf64_section_size (offset_round_down_amount isec1)))) (** Size of segment in file, in bytes *)
+ ; elf64_p_memsz = (Uint64.of_string (Nat_big_num.to_string ( Nat_big_num.add isec1.elf64_section_size (vaddr_round_down_amount isec1)))) (** Size of segment in memory image, in bytes *)
+ ; elf64_p_align = (Uint64.of_string (Nat_big_num.to_string (* 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*)
+let make_load_phdrs maxpagesize1 commonpagesize1 img2 section_pairs_bare_sorted_by_address:(elf64_program_header_table_entry)list=
+(
+ (* accumulate sections into the phdr *)let rev_list = (List.fold_left (fun accum_phdr_list -> (fun isec1 -> (
+ (* Do we have a current phdr? *)
+ (match accum_phdr_list with
+ [] -> (* no, so make one *)
+ (*let _ = errln ("Starting the first LOAD phdr for section " ^ isec.elf64_section_name_as_string)
+ in*)
+ [make_new_phdr isec1 elf_pt_load maxpagesize1 commonpagesize1]
+ | current_phdr :: more ->
+ (* can we extend it with the current section? *)
+ (match maybe_extend_phdr current_phdr isec1 load_can_combine_flags with
+ None ->
+ (*let _ = errln ("Starting new LOAD phdr for section " ^ isec.elf64_section_name_as_string)
+ in*)
+ (make_new_phdr isec1 elf_pt_load maxpagesize1 commonpagesize1) :: (current_phdr :: more)
+ | Some phdr -> phdr :: more
+ )
+ )
+ ))) [] (List.filter (fun isec1 -> flag_is_set shf_alloc isec1.elf64_section_flags
+ && not (flag_is_set shf_tls isec1.elf64_section_flags)) section_pairs_bare_sorted_by_address))
+ in
+ (*let _ = errln "Successfully made phdrs"
+ in*)
+ List.rev rev_list)
+
+(*val tls_extend: forall 'abifeature. abi 'abifeature -> abi 'abifeature*)
+let tls_extend a:'abifeature abi=
+ ({ 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 = (fun maxpagesize1 -> fun commonpagesize1 -> fun file_type -> fun img2 -> fun section_pairs_bare_sorted_by_address -> (
+ let rev_list = (List.fold_left (fun accum_phdr_list -> (fun isec1 -> (
+ (match accum_phdr_list with
+ [] ->
+ (*let _ = errln "Making a new TLS program header" in*)
+ [make_new_phdr isec1 elf_pt_tls maxpagesize1 commonpagesize1]
+ | current_phdr :: more ->
+ (match maybe_extend_phdr current_phdr isec1 tls_can_combine_flags with
+ None ->
+ (make_new_phdr isec1 elf_pt_tls maxpagesize1 commonpagesize1) :: (current_phdr :: more)
+ | Some phdr -> phdr :: more
+ )
+ )
+ ))) [] (List.filter (fun isec1 -> flag_is_set shf_alloc isec1.elf64_section_flags
+ && flag_is_set shf_tls isec1.elf64_section_flags) section_pairs_bare_sorted_by_address))
+ in
+ List.rev_append (List.rev (a.make_phdrs maxpagesize1 commonpagesize1 file_type img2 section_pairs_bare_sorted_by_address)) (List.rev rev_list)
+ ))
+ ; max_phnum = (Nat_big_num.add(Nat_big_num.of_int 1) 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)
+ })
+
+(* 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*)
+let make_default_phdrs maxpagesize1 commonpagesize1 t img2 section_pairs_bare_sorted_by_address:(elf64_program_header_table_entry)list=
+(
+ (* FIXME: do the shared object and dyn. exec. stuff too *)make_load_phdrs maxpagesize1 commonpagesize1 img2 section_pairs_bare_sorted_by_address)
+
+(*val find_start_symbol_address : forall 'abifeature. Ord 'abifeature, AbiFeatureTagEquiv 'abifeature => annotated_memory_image 'abifeature -> maybe natural*)
+let find_start_symbol_address dict_Basic_classes_Ord_abifeature dict_Abi_classes_AbiFeatureTagEquiv_abifeature img2:(Nat_big_num.num)option=
+(
+ (* Do we have a symbol called "_start"? *)let all_defs = (Memory_image_orderings.defined_symbols_and_ranges
+ dict_Basic_classes_Ord_abifeature dict_Abi_classes_AbiFeatureTagEquiv_abifeature img2)
+ in
+ let get_entry_point = (fun (maybe_range, symbol_def) ->
+ if symbol_def.def_symname = "_start"
+ then Some (maybe_range, symbol_def)
+ else None
+ )
+ in
+ let all_entry_points = (Lem_list.mapMaybe get_entry_point all_defs)
+ in
+ (match all_entry_points with
+ [(maybe_range, symbol_def)] ->
+ (match maybe_range with
+ Some (el_name, (el_off, len)) ->
+ (match Pmap.lookup el_name img2.elements with
+ None -> failwith ("_start symbol defined in nonexistent element `" ^ (el_name ^ "'"))
+ | Some el_rec ->
+ (match el_rec.startpos with
+ None -> (*let _ = Missing_pervasives.errln "warning: saw `_start' in element with no assigned address" in *)None
+ | Some x -> (* success! *) Some ( Nat_big_num.add x el_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*)
+let pad_zeroes n:(char)list= (replicate0 n (Char.chr (Nat_big_num.to_int (Nat_big_num.of_int 0))))
+
+(*val pad_0x90 : natural -> list byte*)
+let pad_0x90 n:(char)list= (replicate0 n (Char.chr (Nat_big_num.to_int ( Nat_big_num.mul(Nat_big_num.of_int 9)(Nat_big_num.of_int 16)))))
+
+(* 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*)
+let null_abi:(any_abi_feature)abi= ({
+ is_valid_elf_header = is_valid_elf64_header
+ ; make_elf_header = (make_elf64_header elf_data_2lsb elf_osabi_none(Nat_big_num.of_int 0) elf_ma_none)
+ ; reloc = noop_reloc
+ ; section_is_special = elf_section_is_special
+ ; section_is_large = (fun s -> (fun f -> false))
+ ; maxpagesize = (Nat_big_num.mul (Nat_big_num.mul(Nat_big_num.of_int 2)(Nat_big_num.of_int 256))(Nat_big_num.of_int 4096)) (* 2MB; bit of a guess, based on gdb and prelink code *)
+ ; minpagesize =(Nat_big_num.of_int 1024) (* bit of a guess again *)
+ ; commonpagesize =(Nat_big_num.of_int 4096)
+ ; symbol_is_generated_by_linker = (fun symname -> symname = "_GLOBAL_OFFSET_TABLE_")
+ ; make_phdrs = make_default_phdrs
+ ; max_phnum =(Nat_big_num.of_int 2)
+ ; guess_entry_point =
+ (find_start_symbol_address
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict
+ instance_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 = (fun img2 -> img2)
+ ; get_reloc_symaddr =
+ (default_get_reloc_symaddr
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)
+ })
+
+(*val got_entry_ordering : (string * maybe symbol_definition) -> (string * maybe symbol_definition) -> Basic_classes.ordering*)
+let got_entry_ordering (s1, md1) (s2, md2):int= (compare s1 s2) (* FIXME *)
+
+let is_ifunc_def:(symbol_definition)option ->bool= (fun maybe_def ->
+(match maybe_def with
+ None -> false
+ | Some d -> Nat_big_num.equal (get_elf64_symbol_type d.def_syment) stt_gnu_ifunc
+))
+
+let amd64_reloc_needs_got_slot:'a ->reloc_site ->(symbol_definition)option ->bool= (fun symref -> fun rr -> fun maybe_def ->
+ if ( Pset.mem(get_elf64_relocation_a_type rr.ref_relent)(Pset.from_list Nat_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 *)
+ ])) then
+ true
+ else if is_ifunc_def maybe_def
+ then
+ (* 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
+ *)
+ true
+ else false)
+
+
+let amd64_reloc_needs_plt_slot (symref : symbol_reference_and_reloc_site) rr maybe_def ref_is_statically_linked:bool=
+ (if ( Pset.mem(get_elf64_relocation_a_type rr.ref_relent)(Pset.from_list Nat_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. *)
+ ])) then
+ not (ref_is_statically_linked rr)
+ else if is_ifunc_def maybe_def
+ then
+ true
+ else
+ (* not a PLT ref *)
+ false)
+
+let amd64_find_got_label_and_element img2:((string*(symbol_definition)option)list*element)option=
+ ((match Pmap.lookup ".got" img2.elements with
+ None -> (* got no GOT? okay... *) None
+ | Some got_el ->
+ (* Find the GOT tag. *)
+ let tags_and_ranges = (Multimap.lookupBy0
+ (instance_Basic_classes_Ord_Memory_image_range_tag_dict
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict) (instance_Basic_classes_Ord_Maybe_maybe_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ Lem_string_extra.instance_Basic_classes_Ord_string_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ instance_Basic_classes_Ord_Num_natural_dict
+ instance_Basic_classes_Ord_Num_natural_dict))) instance_Basic_classes_SetType_var_dict (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) (Memory_image_orderings.tagEquiv
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict) (AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0([])))) img2.by_tag)
+ in
+ (match tags_and_ranges with
+ [] -> 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")
+ )
+ ))
+
+let amd64_find_plt_label_and_element img2:((string*(symbol_definition)option*(any_abi_feature)plt_entry_content_fn)list*element)option=
+ ((match Pmap.lookup ".plt" img2.elements with
+ None -> (* got no PLT? okay... *) None
+ | Some plt_el ->
+ (* Find the PLT tag. *)
+ let tags_and_ranges = (Multimap.lookupBy0
+ (instance_Basic_classes_Ord_Memory_image_range_tag_dict
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict) (instance_Basic_classes_Ord_Maybe_maybe_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ Lem_string_extra.instance_Basic_classes_Ord_string_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ instance_Basic_classes_Ord_Num_natural_dict
+ instance_Basic_classes_Ord_Num_natural_dict))) instance_Basic_classes_SetType_var_dict (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) (Memory_image_orderings.tagEquiv
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict) (AbiFeature(Amd64AbiFeature(Abi_amd64.PLT0([])))) img2.by_tag)
+ in
+ (match tags_and_ranges with
+ [] -> 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")
+ )
+ ))
+
+let got_slot_index_for_symname dict_Basic_classes_Eq_a symname got_label:(int)option=
+ (Lem_list.find_index (fun (s, _) ->
+ dict_Basic_classes_Eq_a.isEqual_method s symname) got_label)
+
+(*val amd64_get_reloc_symaddr : symbol_definition -> annotated_memory_image any_abi_feature -> maybe reloc_site -> natural*)
+let amd64_get_reloc_symaddr the_input_def output_img maybe_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 -> *)if is_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). *)
+ (match amd64_find_plt_label_and_element output_img with
+ None -> failwith "error: ifunc but no PLT"
+ | Some (l, plt_el) ->
+ (match Lem_list.find_index (fun (symname, _, _) -> symname = the_input_def.def_symname) l with
+ (* FIXME: using symnames seems wrong *)
+ Some idx1 ->
+ (match plt_el.startpos with
+ Some addr -> Nat_big_num.add addr (Nat_big_num.mul (Nat_big_num.of_int idx1)(Nat_big_num.of_int 16)) (* size of a PLT entry *)
+ | None -> failwith "error: PLT has no address assigned"
+ )
+ | None ->Nat_big_num.of_int 0
+ )
+ )
+ else default_get_reloc_symaddr
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict the_input_def output_img maybe_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*)
+let amd64_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.
+ *)let ref_is_statically_linked = (fun _ -> true)
+ in
+ let (fnames, input_imgs) = (List.split input_fnames_and_imgs)
+ in
+ let tags_and_ranges_by_image = (Lem_list.mapi (fun i -> fun (fname1, img2) ->
+ (i, fname1, Multimap.lookupBy0
+ (instance_Basic_classes_Ord_Memory_image_range_tag_dict
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict) (instance_Basic_classes_Ord_Maybe_maybe_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ Lem_string_extra.instance_Basic_classes_Ord_string_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ instance_Basic_classes_Ord_Num_natural_dict
+ instance_Basic_classes_Ord_Num_natural_dict))) instance_Basic_classes_SetType_var_dict (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) (Memory_image_orderings.tagEquiv
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict) (SymbolRef(null_symbol_reference_and_reloc_site)) img2.by_tag)
+ ) input_fnames_and_imgs)
+ in
+ let refs_via_got = (list_concat_map (fun (i, fname1, tags_and_ranges) -> Lem_list.mapMaybe (fun (tag, maybe_range) -> (match tag with
+ SymbolRef(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
+ | (Some rr, Some(ApplyReloc, maybe_def)) ->
+ if amd64_reloc_needs_got_slot symref rr maybe_def then
+ (*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)
+ else None
+ | (Some rr, 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 (symnames, maybe_defs) = (List.split refs_via_got)
+ in
+ (*let _ = errln ("GOT includes defs with names: " ^ (show (Set_extra.toList (Set.fromList symnames))))
+ in*)
+ let got_pairs_set = (Pset.from_list (pairCompare compare (maybeCompare compare)) refs_via_got)
+ in
+ let got_defs_set = (Pset.from_list (maybeCompare compare) maybe_defs)
+ in
+ (* This is where we fix the order of the GOT entries. *)
+ let got_pairs_list = (Pset.elements got_pairs_set)
+ in
+ let got_idx_and_maybe_def_by_symname_map = (Lem_map.fromList
+ (Lem_map.instance_Map_MapKeyType_var_dict
+ instance_Basic_classes_SetType_var_dict) (mapi (fun slot_idx -> fun (symname, maybe_def) -> (symname, (slot_idx, maybe_def))) got_pairs_list))
+ in
+ let got_ifunc_set = (let x2 =(Pset.from_list (maybeCompare compare)
+ []) in Pset.fold
+ (fun maybe_d x2 ->
+ if is_ifunc_def maybe_d then Pset.add maybe_d x2 else x2) got_defs_set
+ x2)
+ 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 *)
+ let got_nentries = (Nat_big_num.of_int (Pset.cardinal got_pairs_set))
+ in
+ let got_entrysize =(Nat_big_num.of_int 8)
+ 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. *)
+ let refs_via_plt = (list_concat_map (fun (i, fname1, tags_and_ranges) -> Lem_list.mapMaybe (fun (tag, maybe_range) -> (match tag with
+ SymbolRef(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
+ | (Some rr, Some(ApplyReloc, maybe_def)) ->
+ if amd64_reloc_needs_plt_slot symref rr maybe_def ref_is_statically_linked
+ then
+ (*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)
+ else None
+ | (Some rr, 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 *)
+ let refs_via_plt_having_got_slot = (Lem_list.mapMaybe (fun (symname, _) ->
+ (match Pmap.lookup symname got_idx_and_maybe_def_by_symname_map with
+ Some(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) = (unzip3 refs_via_plt_having_got_slot)
+ in
+ let plt_symnames_excluding_header = (Pset.elements ((Pset.from_list compare plt_symnames)))
+ in
+ (*let _ = errln ("PLT symnames: " ^ (show plt_symnames_excluding_header))
+ in*)
+ let n_iplt_entries = (Pset.cardinal got_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 *)
+ let plt_needs_header_entry = ((List.length plt_symnames_excluding_header) > n_iplt_entries)
+ in
+ (*let _ = errln ("PLT needs header entry? " ^ (show plt_needs_header_entry))
+ in*)
+ let total_n_plt_entries = (Nat_big_num.add (if plt_needs_header_entry then Nat_big_num.of_int 1 else Nat_big_num.of_int 0) (Missing_pervasives.length plt_symnames_excluding_header))
+ in
+ (*let _ = errln ("PLT total entry count: " ^ (show total_n_plt_entries))
+ in*)
+ let new_by_range =(Pset.from_list (pairCompare (maybeCompare (pairCompare compare (pairCompare Nat_big_num.compare Nat_big_num.compare))) compare) [
+ (Some(".plt", (Nat_big_num.of_int 0, Nat_big_num.mul(Nat_big_num.of_int 16) 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 (fun plt_entry_idx_not_counting_header -> (fun symname ->
+ (* 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) = ((match Pmap.lookup symname got_idx_and_maybe_def_by_symname_map with
+ Some(idx1, maybe_d) -> (Nat_big_num.of_int idx1, 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).
+ *)
+ let this_plt_slot_base_addr = (Nat_big_num.add plt_base_addr (Nat_big_num.mul(Nat_big_num.of_int 16) (
+ Nat_big_num.add(Nat_big_num.of_int plt_entry_idx_not_counting_header) (if plt_needs_header_entry then Nat_big_num.of_int 1 else Nat_big_num.of_int 0))))
+ in
+ (*let _ = Missing_pervasives.errln ("PLT slot base address for symname `" ^ symname ^ "': 0x" ^
+ (hex_string_of_natural this_plt_slot_base_addr))
+ in*)
+ let got_slot_addr = (Nat_big_num.add got_base_addr (Nat_big_num.mul(Nat_big_num.of_int 8) 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*)
+ let maybe_header_entry_address = (if plt_needs_header_entry then Some(plt_base_addr) else None)
+ in
+ let offset_to_got_slot = (Nat_big_num.sub ( got_slot_addr) (( Nat_big_num.add this_plt_slot_base_addr(Nat_big_num.of_int 6))))
+ 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*)
+ let content_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_int 255)); Char.chr (Nat_big_num.to_int (Nat_big_num.of_int 37))]) (* offset to the GOT entry, from the *next* instruction start, signed 32-bit LE *)(to_le_signed_bytes(Nat_big_num.of_int 4) offset_to_got_slot))) [Char.chr (Nat_big_num.to_int (Nat_big_num.of_int 104))])) (* plt slot number not including header, 32-bit LE *)(to_le_unsigned_bytes(Nat_big_num.of_int 4) ((Nat_big_num.of_int plt_entry_idx_not_counting_header))))) [Char.chr (Nat_big_num.to_int (Nat_big_num.of_int 233))])) (to_le_signed_bytes(Nat_big_num.of_int 4) (
+ if is_ifunc_def maybe_def
+ then Nat_big_num.of_int 0
+ else (match maybe_header_entry_address with
+ None -> failwith "normal PLT entry but no PLT header!"
+ | Some header_entry_address -> Nat_big_num.sub ( header_entry_address) (( Nat_big_num.add this_plt_slot_base_addr(Nat_big_num.of_int 16)))
+ )
+ )))
+ 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_feature plt_entry_content_fn))
+ ))
+ plt_symnames)
+ )))
+ )
+ ; (Some(".plt", (Nat_big_num.of_int 0, Nat_big_num.mul(Nat_big_num.of_int 16) total_n_plt_entries)), FileFeature(ElfSection(Nat_big_num.of_int 1,
+ { elf64_section_name =(Nat_big_num.of_int 0) (* ignored *)
+ ; elf64_section_type = sht_progbits
+ ; elf64_section_flags = shf_alloc
+ ; elf64_section_addr =(Nat_big_num.of_int 0) (* ignored -- covered by element *)
+ ; elf64_section_offset =(Nat_big_num.of_int 0) (* ignored -- will be replaced when file offsets are assigned *)
+ ; elf64_section_size = (Nat_big_num.mul(Nat_big_num.of_int 16) 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_int 0)
+ ; elf64_section_info =(Nat_big_num.of_int 0)
+ ; elf64_section_align =(Nat_big_num.of_int 16)
+ ; elf64_section_entsize =(Nat_big_num.of_int 16)
+ ; 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_int 0, Nat_big_num.mul got_nentries got_entrysize)), AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(got_pairs_list))))
+ ; (Some(".got", (Nat_big_num.of_int 0, Nat_big_num.mul got_nentries got_entrysize)), FileFeature(ElfSection(Nat_big_num.of_int 2,
+ { elf64_section_name =(Nat_big_num.of_int 0) (* ignored *)
+ ; elf64_section_type = sht_progbits
+ ; elf64_section_flags = (Nat_big_num.bitwise_or shf_write shf_alloc)
+ ; elf64_section_addr =(Nat_big_num.of_int 0) (* ignored -- covered by element *)
+ ; elf64_section_offset =(Nat_big_num.of_int 0) (* ignored -- will be replaced when file offsets are assigned *)
+ ; elf64_section_size = (Nat_big_num.mul got_nentries got_entrysize) (* ignored? NO, we use it in linker_script to avoid plumbing through the element record *)
+ ; elf64_section_link =(Nat_big_num.of_int 0)
+ ; elf64_section_info =(Nat_big_num.of_int 0)
+ ; elf64_section_align =(Nat_big_num.of_int 8)
+ ; 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_int 0, Nat_big_num.mul got_nentries got_entrysize)), SymbolDef({
+ def_symname = "_GLOBAL_OFFSET_TABLE_"
+ ; def_syment = ({ elf64_st_name = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (* ignored *)
+ ; elf64_st_info = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (* FIXME *)
+ ; elf64_st_other = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (* FIXME *)
+ ; elf64_st_shndx = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 1)))
+ ; elf64_st_value = (Uint64.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (* ignored *)
+ ; elf64_st_size = (Uint64.of_string (Nat_big_num.to_string ( Nat_big_num.mul got_nentries got_entrysize))) (* FIXME: start later, smaller size? zero size? *)
+ })
+ ; def_sym_scn =(Nat_big_num.of_int 1)
+ ; def_sym_idx =(Nat_big_num.of_int 1)
+ ; def_linkable_idx =(Nat_big_num.of_int 0)
+ }))
+ ; (Some(".rela.iplt", (Nat_big_num.of_int 0, (* size of an Elf64_Rela *) Nat_big_num.mul(Nat_big_num.of_int 24) (Nat_big_num.of_int n_iplt_entries))), FileFeature(ElfSection(Nat_big_num.of_int 3,
+ { elf64_section_name =(Nat_big_num.of_int 0) (* ignored *)
+ ; elf64_section_type = sht_rela
+ ; elf64_section_flags = (Nat_big_num.bitwise_or shf_alloc shf_info_link)
+ ; elf64_section_addr =(Nat_big_num.of_int 0) (* ignored -- covered by element *)
+ ; elf64_section_offset =(Nat_big_num.of_int 0) (* 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_int 24) (Nat_big_num.of_int n_iplt_entries)) (* ignored? NO, we use it in linker_script to avoid plumbing through the element record *)
+ ; elf64_section_link =(Nat_big_num.of_int 0)
+ ; elf64_section_info =(Nat_big_num.of_int (* FIXME: want this to be the PLT section shndx *)0)
+ ; elf64_section_align =(Nat_big_num.of_int 8)
+ ; elf64_section_entsize =(Nat_big_num.of_int 24)
+ ; 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.mul got_nentries got_entrysize))
+ ; contents = ([])
+ } (Pmap.add ".plt" {
+ startpos = None
+ ; length1 = (let len = (Nat_big_num.mul(Nat_big_num.of_int 16) total_n_plt_entries) in
+ (*let _ = errln ("PLT length in element: " ^ (show len) ^ " bytes")
+ in *) Some ( Nat_big_num.mul(Nat_big_num.of_int 16) 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_int 24) (Nat_big_num.of_int n_iplt_entries)))
+ ; contents = ([])
+ } (Pmap.empty compare)
+ )))
+ ; by_tag = (by_tag_from_by_range
+ (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) instance_Basic_classes_SetType_var_dict new_by_range)
+ ; by_range = new_by_range
+ })
+
+(*val amd64_concretise_support : annotated_memory_image any_abi_feature -> annotated_memory_image any_abi_feature*)
+let amd64_concretise_support orig_img:(any_abi_feature)annotated_memory_image=
+(
+ (*let _ = errln "Concretising amd64 ABI support structures"
+ in*)
+ (* Fill in the GOT contents. *)(match amd64_find_got_label_and_element orig_img with
+ None -> orig_img (* no GOT, but that's okay *)
+ | Some (got_l, got_el) ->
+ let got_base_addr = ((match got_el.startpos with
+ Some a -> a
+ | None -> failwith "GOT has no address assigned"
+ ))
+ in
+ let got_entry_bytes_for = (fun img2 -> fun symname -> fun maybe_def -> fun plt_l -> fun maybe_plt_el -> (match maybe_def with
+ None -> replicate0(Nat_big_num.of_int 8) (Char.chr (Nat_big_num.to_int (Nat_big_num.of_int 0)))
+ | Some sd ->
+ (* 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. *)
+ (match Lem_list.find_index (fun (plt_symname, _, _) -> symname = plt_symname) plt_l with
+ Some plt_slot_idx ->
+ (match maybe_plt_el with
+ None -> failwith "GOT slot with PLT entry but no PLT element"
+ | Some plt_el ->
+ (match plt_el.startpos with
+ Some addr -> natural_to_le_byte_list_padded_to(Nat_big_num.of_int 8) ( Nat_big_num.add (Nat_big_num.add addr ( Nat_big_num.mul(Nat_big_num.of_int plt_slot_idx)(Nat_big_num.of_int 16)))(Nat_big_num.of_int 6))
+ | None -> failwith ("no PLT!")
+ )
+ )
+ | None ->
+ (* Just look for a definition. *)
+ (match Memory_image_orderings.find_defs_matching
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict sd img2 with
+ [] -> failwith ("no matching definitions for GOT entry named " ^ symname)
+ | [(Some(def_el_name, (def_start, def_len)), d)] ->
+ (match element_and_offset_to_address (def_el_name, def_start) img2 with
+ None -> failwith ("no address for definition offset in element " ^ def_el_name)
+ | Some x ->
+ (* 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. *)
+ if Nat_big_num.equal (get_elf64_symbol_type sd.def_syment) stt_tls then
+ (* 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. *)
+ let offs = (i2n_signed( 64) (Nat_big_num.sub(Nat_big_num.of_int 0)(Nat_big_num.of_int 8)))
+ in
+ (*let _ = errln ("GOT slot for TLS symbol `" ^ symname ^
+ "' created containing offset 0x" ^ (hex_string_of_natural offs))
+ in*)
+ natural_to_le_byte_list offs
+ else (*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_int 8) x
+ )
+ | _ -> failwith ("multiple matching definitions for GOT entry named " ^ symname)
+ )
+ )
+ ))
+ in
+ let concretise_got = (fun img2 -> fun plt_l -> fun maybe_plt_el ->
+ let l = got_l
+ (* Just(got_el_name, (got_start_off, got_len)))] -> *)
+ in
+ (*let _ = errln ("Concretising a GOT of " ^ (show (length l)) ^ " entries.")
+ in*)
+ let got_entry_contents = (Lem_list.map (fun (symname, maybe_def) ->
+ Lem_list.map (fun b -> Some b) (got_entry_bytes_for img2 symname maybe_def plt_l maybe_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. *)
+ let got_content = (List.concat got_entry_contents)
+ in
+ let new_got_el =
+ ({ contents = got_content
+ ; startpos = (got_el.startpos)
+ ; length1 = (got_el.length1)
+ })
+ in
+ let new_got_tag = (AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(l))))
+ in
+ let got_range = (Some(".got", (Nat_big_num.of_int 0, Nat_big_num.mul(Nat_big_num.of_int 8) (length l))))
+ in
+ let new_by_tag =
+ (Pset.(union)( Pset.diff(img2.by_tag : (( any_abi_feature range_tag) * ( element_range option)) Pset.set)(Pset.from_list (pairCompare compare (maybeCompare (pairCompare compare (pairCompare Nat_big_num.compare Nat_big_num.compare)))) [(AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0(l))), got_range)]))(Pset.from_list (pairCompare compare (maybeCompare (pairCompare compare (pairCompare Nat_big_num.compare Nat_big_num.compare)))) [(new_got_tag, got_range)]))
+ in
+ let new_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_tag
+ instance_Basic_classes_SetType_var_dict (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) new_by_tag)
+ })
+ in
+ (match amd64_find_plt_label_and_element orig_img with
+ None -> concretise_got orig_img [] None (* no PLT, but possibly a GOT *)
+ | Some (plt_l, plt_el) ->
+ let plt_base_addr = ((match plt_el.startpos with
+ Some a -> a
+ | None -> failwith "PLT has no address assigned"
+ ))
+ in
+ let concretise_plt = (fun img2 ->
+ let l = plt_l
+ in
+ (* 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. *)
+ let all_content = (List.concat (Lem_list.map (fun (_, _, plt_content_fn) ->
+ let (_, content) = (plt_content_fn got_base_addr plt_base_addr) in
+ content
+ ) 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*)
+ let new_plt_el =
+ ({ contents = (Lem_list.map (fun b -> Some b) all_content)
+ ; startpos = (plt_el.startpos)
+ ; length1 = (Some(length all_content))
+ })
+ in
+ let new_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)
+ })
+ in
+ let concretise_rela_plt = (fun img2 ->
+ let maybe_rela_plt_el = (Pmap.lookup ".rela.plt" img2.elements)
+ in
+ let maybe_new_rela_plt_el = ((match maybe_rela_plt_el with
+ None -> (* got no .rela.plt? okay... *)
+ (*let _ = errln "No .rela.plt found"
+ in*)
+ None
+ | Some rela_plt_el ->
+ let got_entry_iplt_widget_for = (fun symname -> fun maybe_def -> (match maybe_def with
+ None -> None
+ | Some sd ->
+ if not (Nat_big_num.equal (get_elf64_symbol_type sd.def_syment) stt_gnu_ifunc) then None
+ else Some(fun index_in_got ->
+ (* This is a 24-byte Elf64_Rela. *)
+ let (r_offset : Nat_big_num.num) (* GOT *slot* address! *) =
+ ((match got_el.startpos with
+ None -> failwith "internal error: GOT has no assigned address"
+ | Some addr -> Nat_big_num.add addr ( Nat_big_num.mul(Nat_big_num.of_int 8) index_in_got)
+ ))
+ in
+ let (r_info : Nat_big_num.num) = r_x86_64_irelative in
+ ( List.rev_append (List.rev (List.rev_append (List.rev (natural_to_le_byte_list_padded_to(Nat_big_num.of_int 8) r_offset)) (natural_to_le_byte_list_padded_to(Nat_big_num.of_int 8) 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. *)(match Memory_image_orderings.find_defs_matching
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict sd img2 with
+ [] -> failwith ("impossible: IPLT entry widget found matching ifunc definition for " ^ symname)
+ | [(Some(def_el_name, (def_start, def_len)), d)] ->
+ (match element_and_offset_to_address (def_el_name, def_start) img2 with
+ None -> failwith ("no address for ifunc definition offset in element " ^ def_el_name)
+ | Some x ->
+ (* 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. *)
+ if not (Nat_big_num.equal (get_elf64_symbol_type sd.def_syment) stt_gnu_ifunc)
+ then failwith "impossible: found ifunc definition that is not an ifunc"
+ else
+ natural_to_le_byte_list_padded_to(Nat_big_num.of_int 8) x
+ )
+ | _ -> failwith "impossible: more than one ifunc definition"
+ )
+ ))
+ (* end Just sd *)
+ ))
+ in
+ let rela_iplt_widgets = (Lem_list.map (fun (symname, maybe_def) -> got_entry_iplt_widget_for symname maybe_def) got_l)
+ in
+ let new_content_bytelists =
+ (mapi (fun i -> fun rela_widget ->
+ (match rela_widget with
+ Some f -> f (Nat_big_num.of_int i)
+ | None -> []
+ )
+ ) rela_iplt_widgets)
+ in
+ let new_contents = (Lem_list.map (fun b -> Some b) (List.concat new_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)
+ }
+ )
+ ))
+ in
+ let new_elements_map = ((match maybe_new_rela_plt_el with
+ Some new_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)
+ })
+ in
+ concretise_rela_plt (concretise_plt (concretise_got orig_img plt_l (Some plt_el)))
+) ))
+
+(*val amd64_got_slot_idx : annotated_memory_image any_abi_feature -> symbol_reference_and_reloc_site -> natural*)
+let amd64_got_slot_idx img2 rr:Nat_big_num.num=
+(
+ (*let _ = errln ("Looking up GOT slot for symbol " ^ rr.ref.ref_symname) in*)(match Pmap.lookup ".got" img2.elements with
+ None -> (* got no GOT? okay... *) failwith "got no GOT"
+ | Some got_el ->
+ (* Find the GOT tag. *)
+ let tags_and_ranges = (Multimap.lookupBy0
+ (instance_Basic_classes_Ord_Memory_image_range_tag_dict
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict) (instance_Basic_classes_Ord_Maybe_maybe_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ Lem_string_extra.instance_Basic_classes_Ord_string_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ instance_Basic_classes_Ord_Num_natural_dict
+ instance_Basic_classes_Ord_Num_natural_dict))) instance_Basic_classes_SetType_var_dict (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) (Memory_image_orderings.tagEquiv
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict) (AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0([])))) img2.by_tag)
+ in
+ (match tags_and_ranges with
+ [] -> 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. *)
+ let got_addr = ((match got_el.startpos with Some addr -> addr | None -> failwith "GOT has no addr at reloc time" ))
+ in
+ (match rr.maybe_def_bound_to with
+ Some (_, Some(d)) ->
+ (match Lem_list.find_index (fun (symname, maybe_def) -> (Lem.option_equal (=) (Some(d)) maybe_def)) l with
+ Some idx1 -> Nat_big_num.of_int idx1
+ | 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. *)
+ (match Lem_list.find_index (fun (symname, _) -> symname = rr.ref.ref_symname) l with
+ Some idx1 -> Nat_big_num.of_int idx1
+ | 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*)
+let amd64_got_slot_addr img2 rr:Nat_big_num.num=
+ ((match Pmap.lookup ".got" img2.elements with
+ None -> (* got no GOT? okay... *) failwith "got no GOT"
+ | Some got_el ->
+ (* Find the GOT tag. *)
+ let tags_and_ranges = (Multimap.lookupBy0
+ (instance_Basic_classes_Ord_Memory_image_range_tag_dict
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict) (instance_Basic_classes_Ord_Maybe_maybe_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ Lem_string_extra.instance_Basic_classes_Ord_string_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ instance_Basic_classes_Ord_Num_natural_dict
+ instance_Basic_classes_Ord_Num_natural_dict))) instance_Basic_classes_SetType_var_dict (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) (Memory_image_orderings.tagEquiv
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict) (AbiFeature(Amd64AbiFeature(Abi_amd64.GOT0([])))) img2.by_tag)
+ in
+ (match tags_and_ranges with
+ [] -> 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. *)
+ let got_addr = ((match got_el.startpos with Some addr -> addr | None -> failwith "GOT has no addr at reloc time" ))
+ in Nat_big_num.add (Nat_big_num.mul(Nat_big_num.of_int 8) (amd64_got_slot_idx img2 rr)) got_addr
+ | _ -> failwith "got bad GOT"
+ )
+ ))
+
+(*val amd64_plt_slot_addr : annotated_memory_image any_abi_feature -> symbol_reference_and_reloc_site -> natural -> natural*)
+let amd64_plt_slot_addr img2 rr raw_addr:Nat_big_num.num=
+ ((match Pmap.lookup ".plt" img2.elements with
+ None ->
+ (* 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
+ | Some plt_el ->
+ (* Find the PLT tag. *)
+ let tags_and_ranges = (Multimap.lookupBy0
+ (instance_Basic_classes_Ord_Memory_image_range_tag_dict
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict) (instance_Basic_classes_Ord_Maybe_maybe_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ Lem_string_extra.instance_Basic_classes_Ord_string_dict
+ (instance_Basic_classes_Ord_tup2_dict
+ instance_Basic_classes_Ord_Num_natural_dict
+ instance_Basic_classes_Ord_Num_natural_dict))) instance_Basic_classes_SetType_var_dict (instance_Basic_classes_SetType_Maybe_maybe_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_var_dict
+ (instance_Basic_classes_SetType_tup2_dict
+ instance_Basic_classes_SetType_Num_natural_dict
+ instance_Basic_classes_SetType_Num_natural_dict))) (Memory_image_orderings.tagEquiv
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict) (AbiFeature(Amd64AbiFeature(Abi_amd64.PLT0([])))) img2.by_tag)
+ in
+ (match tags_and_ranges with
+ [] -> 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)))] ->
+ let plt_addr = ((match plt_el.startpos with Some addr -> addr | None -> failwith "PLT has no addr at reloc time" ))
+ in
+ (* Find the slot corresponding to rr, if we have one. *)
+ (match rr.maybe_def_bound_to with
+ Some (_, Some(d)) ->
+ (match Lem_list.mapMaybe (fun (symname, maybe_def, fn) -> if (Lem.option_equal (=) (Some(d)) maybe_def) then Some fn else None) l with
+ [fn] ->
+ let got_addr =
+ ((match Pmap.lookup ".got" img2.elements with
+ None -> (* got no GOT? okay... *) failwith "got no GOT (applying PLT calculation)"
+ | Some got_el -> (match got_el.startpos with
+ Some addr -> addr
+ | None -> failwith "concrete GOT has no addr"
+ )
+ ))
+ in
+ let (addr, content) = (fn got_addr plt_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*)
+ (match Memory_image_orderings.find_defs_matching
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict d img2 with
+ [] ->Nat_big_num.of_int 0 (* HMM -- should be an error? *)
+ | [(Some(el_name, (start_off, len)), matching_d)] ->
+ (match element_and_offset_to_address (el_name, start_off) img2 with
+ Some a -> 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) ->Nat_big_num.of_int (* weak, so 0 *)0
+ | _ -> failwith "PLT: unbound def"
+ )
+ | _ -> failwith "got bad PLT"
+ )
+ ))
+
+(** [amd64_reloc r] yields a function that applies relocations of type [r]. *)
+(*val amd64_reloc : reloc_fn any_abi_feature*)
+let amd64_reloc r: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))=
+ ((match (string_of_amd64_relocation_type r) with
+ | "R_X86_64_NONE" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 0, (fun s -> fun a -> fun e -> e))))))
+ | "R_X86_64_64" -> (true, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8, (fun s -> fun a -> fun e -> i2n ( Nat_big_num.add(n2i s) a)))))))
+ | "R_X86_64_PC32" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> i2n_signed( 32) ( Nat_big_num.sub( Nat_big_num.add(n2i s) a) (n2i site_addr))))))))
+ | "R_X86_64_GOT32" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> i2n_signed( 32) ( Nat_big_num.add(n2i (amd64_got_slot_idx img2 rr)) a)))))))
+ | "R_X86_64_PLT32" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> i2n_signed( 32) ( Nat_big_num.sub (Nat_big_num.add(n2i (amd64_plt_slot_addr img2 rr s)) a) (n2i site_addr))) )))) )
+ | "R_X86_64_COPY" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (size_of_copy_reloc img2 rr, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_GLOB_DAT" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (size_of_def rr, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_JUMP_SLOT" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_RELATIVE" -> (true, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_GOTPCREL" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> i2n_signed( 32) ( Nat_big_num.sub (Nat_big_num.add(n2i (amd64_got_slot_addr img2 rr)) a) (n2i site_addr))) )))) )
+ | "R_X86_64_32" -> (true, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> i2n ( Nat_big_num.add(n2i s) a)))))))
+ | "R_X86_64_32S" -> (true, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> i2n_signed( 32) ( Nat_big_num.add(n2i s) a)))))))
+ | "R_X86_64_16" -> (true, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 2, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_PC16" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 2, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_8" -> (true, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 1, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_PC8" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 1, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_DTPMOD64" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_DTPOFF64" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_TPOFF64" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8 (* CHECK *), (fun s -> fun a -> fun e -> i2n_signed( 64) (Nat_big_num.sub(Nat_big_num.of_int 0)(Nat_big_num.of_int 8))) (* FIXME *))))))
+ | "R_X86_64_TLSGD" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_TLSLD" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_DTPOFF32" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_GOTTPOFF" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> i2n_signed( 32) ( Nat_big_num.sub (Nat_big_num.add(n2i (amd64_got_slot_addr img2 rr)) a) (n2i site_addr))))))))
+ | "R_X86_64_TPOFF32" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_PC64" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_GOTOFF64" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_GOTPC32" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_SIZE32" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_SIZE64" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8, (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_GOTPC32_TLSDESC" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_TLSDESC_CALL" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 4 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_TLSDESC" -> (false, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | "R_X86_64_IRELATIVE" -> (true, (fun img2 -> (fun site_addr -> (fun rr -> (Nat_big_num.of_int 8 (* CHECK *), (fun s -> fun a -> fun e -> e) (* FIXME *))))))
+ | _ -> failwith "unrecognised relocation"
+))
+
+(*val sysv_amd64_std_abi : abi any_abi_feature*)
+let sysv_amd64_std_abi:(any_abi_feature)abi=
+ ({ is_valid_elf_header = header_is_amd64
+ ; make_elf_header = (make_elf64_header elf_data_2lsb elf_osabi_none(Nat_big_num.of_int 0) elf_ma_x86_64)
+ ; reloc = amd64_reloc
+ ; section_is_special = section_is_special0
+ ; section_is_large = (fun s -> (fun f -> flag_is_set shf_x86_64_large s.elf64_section_flags))
+ ; maxpagesize =(Nat_big_num.of_int 65536)
+ ; minpagesize =(Nat_big_num.of_int 4096)
+ ; commonpagesize =(Nat_big_num.of_int 4096)
+ (* XXX: DPM, changed from explicit reference to null_abi field due to problems in HOL4. *)
+ ; symbol_is_generated_by_linker = (fun symname -> symname = "_GLOBAL_OFFSET_TABLE_")
+ ; make_phdrs = make_default_phdrs
+ ; max_phnum =(Nat_big_num.of_int 2) (* incremented by extensions *)
+ ; guess_entry_point =
+ (find_start_symbol_address
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict
+ instance_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
+ })
+
+(*val sysv_aarch64_le_std_abi : abi any_abi_feature*)
+let sysv_aarch64_le_std_abi:(any_abi_feature)abi=
+ ({ is_valid_elf_header = header_is_aarch64_le
+ ; make_elf_header = (make_elf64_header elf_data_2lsb elf_osabi_none(Nat_big_num.of_int 0) elf_ma_aarch64)
+ ; reloc = aarch64_le_reloc
+ ; section_is_special = section_is_special0
+ ; section_is_large = (fun _ -> (fun _ -> false))
+ ; maxpagesize = (Nat_big_num.mul (Nat_big_num.mul(Nat_big_num.of_int 2)(Nat_big_num.of_int 256))(Nat_big_num.of_int 4096)) (* 2MB; bit of a guess, based on gdb and prelink code *)
+ ; minpagesize =(Nat_big_num.of_int 1024) (* bit of a guess again *)
+ ; commonpagesize =(Nat_big_num.of_int 4096)
+ ; symbol_is_generated_by_linker = (fun symname -> symname = "_GLOBAL_OFFSET_TABLE_")
+ ; make_phdrs = make_default_phdrs
+ ; max_phnum =(Nat_big_num.of_int 2) (* incremented by extensions *)
+ ; guess_entry_point =
+ (find_start_symbol_address
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict
+ instance_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 = (fun img2 -> img2)
+ ; get_reloc_symaddr =
+ (default_get_reloc_symaddr
+ instance_Basic_classes_Ord_Abis_any_abi_feature_dict
+ instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict)
+ })
+
+(*val all_abis : list (abi any_abi_feature)*)
+let all_abis:((any_abi_feature)abi)list= ([sysv_amd64_std_abi; sysv_aarch64_le_std_abi; null_abi])
+