summaryrefslogtreecommitdiff
path: root/lib/ocaml_rts/linksem/linker_script.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ocaml_rts/linksem/linker_script.ml')
-rw-r--r--lib/ocaml_rts/linksem/linker_script.ml2783
1 files changed, 0 insertions, 2783 deletions
diff --git a/lib/ocaml_rts/linksem/linker_script.ml b/lib/ocaml_rts/linksem/linker_script.ml
deleted file mode 100644
index 535d9037..00000000
--- a/lib/ocaml_rts/linksem/linker_script.ml
+++ /dev/null
@@ -1,2783 +0,0 @@
-(*Generated by Lem from linker_script.lem.*)
-open Lem_basic_classes
-open Lem_function
-open Lem_string
-open Lem_tuple
-open Lem_bool
-open Lem_list
-open Lem_sorting
-open Lem_num
-open Lem_maybe
-open Lem_assert_extra
-open Lem_set
-(*import Map*)
-
-open Byte_sequence
-open Default_printing
-open Error
-open Missing_pervasives
-open Show
-
-open Elf_header
-open Elf_file
-open Elf_interpreted_section
-
-open Abis
-open Command_line
-open Input_list
-open Linkable_list
-open Memory_image
-open Elf_memory_image (* HMM -- ideally we'd be ELF-agnostic in this file.
- But Abstract_abi is now merged into Elf_memory_image, so never mind. *)
-open Elf_memory_image_of_elf64_file
-open Elf_relocation
-open Elf_symbol_table
-open Elf_section_header_table
-open Elf_types_native_uint
-open Memory_image_orderings
-
-(* We model two kinds of linker script: "implicit scripts", which are supplied
- * on the command line as input objects, and "control scripts" of which there
- * is exactly one per link job. The abstract syntax of each script comes from the
- * same grammar.
- *
- * We define the control script as a bunch of functions, to allow for
- * link jobs where we don't have an AST and the script behaviour is hard-coded.
- *)
-
-(* Input sections come from individual (relocatable) ELF files.
- * The name of this file is important!
- *
- * Each input "section" is always an identified section or common symbol
- * *within* some ELF memory image. *)
-
-type input_section_rec = {
- idx : Nat_big_num.num (* linkable idx *)
-; fname : string
-; img : elf_memory_image
-; shndx : Nat_big_num.num
-; secname: string
-; isec : elf64_interpreted_section
-}
-
-type input_spec
- = Common of (Nat_big_num.num * string * elf_memory_image * symbol_definition) (* string is symbol name -- must be a COMMON symbol *)
- | InputSection of input_section_rec
-
-(* A control script defines
- * - output sections
- * - a mapping from output sections to (ordered) input sections
- * - extra symbols
- * - output format etc. (skip this for now)
- *)
-
-(* We will have to deal with merging etc. at some point, somewhere
- * (maybe here, maybe not); for now we just produce an ordered list
- * of sections.
- *)
-
-(* We can't model linker scripts as plain Lem functions without writing
- * them to a very different structure than that of scripts. The reason is that
- * certain features of the script language necessitate multiple passes
- * over the script structure. For example, to figure out how big an
- * output section is, hence where to begin the next section, you need to
- * know which of the input sections are marked for KEEP. For that, you need
- * a def-use graph over input sections. But for that, you also need to account
- * for *all* symbol definitions, and the script itself is allowed to add new
- * ones (right in among its input sections). So we have to do one pass to
- * enumerate the symbol additions, and another pass to eliminate sections
- * that we don't want to KEEP.
- *
- * Other gotchas include:
- *
- * - symbol provision and address advancement can occur in among the input
- * section queries, but also outside any output section.
- *
- * - semantics of DATA_SEGMENT_ALIGN depend on future script contents
- *
- * - ONLY_IF_RO and ONLY_IF_RW are tricky: need to evaluate the input section
- * queries
- *
- * - semantics of empty sections are subtle (". = ." will force an empty section
- * to be emitted, but ". = . + 0" will not do so).
- *
- * Our approach is to define an interpreter for (at present) most of the script
- * language.
- *)
-
-type symbol_def_policy = AlwaysDefine
- | ProvideIfUsed
-
-type input_selector = input_spec list -> input_spec list
-
-type address_expr = Memory_image.expr
-
-type output_guard = AlwaysOutput
- | OnlyIfRo
- | OnlyIfRw
-
-type symbol_spec = (Nat_big_num.num * Uint32.uint32 * Uint32.uint32) (* size, info, other *)
-
-type retain_policy
- = DefaultKeep
- | KeepEvenWhenGC
-
-type address_expr_fn_ref = Nat_big_num.num
-type 'a address_expr_fn_map = (address_expr_fn_ref, (Nat_big_num.num -> 'a -> Nat_big_num.num)) Pmap.map
-(* 'a = allocated_sections_map *)
-
-type output_section_composition_element
- = IncludeInputSection of (retain_policy * input_section_rec)
- | IncludeCommonSymbol of (retain_policy * string (* file *) * Nat_big_num.num (* linkable_idx *) * symbol_definition * elf_memory_image)
- | Hole of address_expr_fn (* compute the next addr to continue layout at *)
- | ProvideSymbol of (symbol_def_policy * string * symbol_spec)
-and
-sort_policy
- = DefaultSort (* Use command line sort option, else "seen" order *)
- | SeenOrder (* Always use "seen" order *)
- | ByName
- | ByNameThenAlignment
- | ByAlignment
- | ByAlignmentThenName
- | ByInitPriority
-and
-(* This mirrors the OutputSection constructor, except that the script elements have become
- * output_section_composition_elements, and we might store the size here. *)
-output_section_spec =
- OutputSectionSpec of (output_guard * Nat_big_num.num option * string * ( output_section_composition_element list))
-and
-allocated_sections_map =
- AllocatedSectionsMap of (string, (output_section_spec (* OutputSection element idx *) * Nat_big_num.num)) Pmap.map
-and
-address_expr_fn
- = AddressExprFn of address_expr_fn_ref
-
-type script_element =
- DefineSymbol of (symbol_def_policy * string * symbol_spec)
-| AdvanceAddress of address_expr_fn
-| MarkAndAlignDataSegment of (Nat_big_num.num * Nat_big_num.num) (* maxpagesize, commonpagesize *)
-| MarkDataSegmentEnd
-| MarkDataSegmentRelroEnd (*of (allocated_sections_map -> (natural * (natural -> natural))) DPM: commented out because of positivity constrains in Isabelle *)
-| OutputSection of (output_guard * ( (* address_expr *) address_expr_fn option) * string * script_element list)
-| DiscardInput of input_selector
- (* Input queries can only occur within an output section.
- Output sections may not nest within other output sections.
- (Ideally we would use something like polymorphic variants to encode this.)
- *)
-| InputQuery of (retain_policy * sort_policy * input_selector)
-
-(* A linker control script is a function from inputs to output elements.
- * We can define them in syntax (using an interpreter)
- * or in Lem directly (as functions). *)
-type linker_control_script = script_element list
-type labelled_linker_control_script = (script_element * Nat_big_num.num) list
-
-(*val all_suffixes : list char -> list (list char)*)
-let rec all_suffixes chars:((char)list)list=
- ((match chars with
- [] -> [[]]
- | c :: morecs -> chars :: (all_suffixes morecs)
- ))
-
-(*val glob_match : list char -> list char -> bool*)
-let rec glob_match pat str:bool=
- ((match (pat, str) with
- ([], []) -> true
- | ('?':: morepat, _ :: morestr) -> glob_match morepat morestr
- | ('*':: morepat, _) ->
- (* if any suffix of the remaining string matches
- * the remaining pattern, we've matched the pattern
- * from '*' onwards. *)
- let or_suffix_match = (fun matched -> (fun newlist ->
- matched || glob_match morepat newlist))
- in
- List.fold_left (or_suffix_match) false (all_suffixes str)
- | (patc :: morepat, c :: morestr) -> (patc = c) && glob_match morepat morestr
- | ([], _) -> (* ran out of pattern *) false
- | (_, []) -> (* ran out of str *) false
- ))
-
-(*val default_symbol_spec : symbol_spec*)
-let default_symbol_spec:Nat_big_num.num*Uint32.uint32*Uint32.uint32= (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)))
-(*val hidden_symbol_spec : symbol_spec*)
-let hidden_symbol_spec:Nat_big_num.num*Uint32.uint32*Uint32.uint32= (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 stv_hidden))
-
-(* These Lem functions replicate linker script functions or builtin behaviours. *)
-
-(*val only_sections : input_selector*)
-let only_sections inputs:(input_spec)list= (Lem_list.mapMaybe
- (fun i -> (match i with
- | InputSection(_) -> Some(i)
- | _ -> None
- )) inputs)
-
-(*val filter_and_concat : (input_spec -> bool) -> input_selector*) (* a.k.a. list input_spec -> list input_spec *)
-let filter_and_concat p inputs:(input_spec)list= (List.filter p inputs)
-
-(*val name_matches : string -> input_spec -> bool*)
-let name_matches pat input:bool=
- ((match input with
- InputSection(inp) ->
- (*let _ = errln ("Does section name `" ^ inp.secname ^ "' match glob pattern `" ^ pat ^ "'? ") in
- let result = *)glob_match (Xstring.explode pat) (Xstring.explode inp.secname) (*in
- let _ = errln (if result then "yes" else "no")
- in result*)
- | _ -> false
- ))
-
-(*val file_matches : string -> input_spec -> bool*)
-let file_matches pat input:bool=
- ((match input with
- InputSection(inp) -> glob_match (Xstring.explode pat) (Xstring.explode inp.fname)
- | _ -> false
- ))
-
-let compareInputSpecByNameThenAlignment i1 i2:int=
- (let toPair = (fun is -> ((match is with
- Common(idx1, fname1, img2, def) -> ("COMMON" (* FIXME: is this right? *), Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_value)
- | InputSection(isrec) -> (isrec.isec.elf64_section_name_as_string, isrec.isec.elf64_section_align)
- )))
- in (pairCompare compare Nat_big_num.compare (toPair i1) (toPair i2)))
-
-let compareInputSpecByAlignment i1 i2:int=
- (let toNatural = (fun is -> ((match is with
- Common(idx1, fname1, img2, def) -> Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_value
- | InputSection(isrec) -> isrec.isec.elf64_section_align
- )))
- in Nat_big_num.compare (toNatural i1) (toNatural i2))
-
-let compareInputSpecByName i1 i2:int=
- (let toString = (fun is -> ((match is with
- Common(idx1, fname1, img2, def) -> "COMMON"
- | InputSection(isrec) -> isrec.isec.elf64_section_name_as_string
- )))
- in compare (toString i1) (toString i2))
-
-let compareInputSpecByAlignmentThenName i1 i2:int=
- (let toPair = (fun is -> ((match is with
- Common(idx1, fname1, img2, def) -> (Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_value,
- "COMMON" (* FIXME: is this right? *))
- | InputSection(isrec) -> (isrec.isec.elf64_section_align, isrec.isec.elf64_section_name_as_string)
- )))
- in (pairCompare Nat_big_num.compare compare (toPair i1) (toPair i2)))
-
-let compareInputSpecByInitPriority i1 i2:int= 0 (* FIXME *)
-
-(* DATA_SEGMENT_ALIGN is defined by two formulae
- * (over pos and commonpagesize/maxpagesize)
- * "... depending on whether the latter uses fewer COMMONPAGESIZE sized
- pages for the data segment (area between the result of this
- expression and `DATA_SEGMENT_END') than the former or not. If the
- latter form is used, it means COMMONPAGESIZE bytes of runtime
- memory will be saved at the expense of up to COMMONPAGESIZE wasted
- bytes in the on-disk file."
-
- So the amount of padding that gets inserted here depends on the location
- of something that comes *later*, namely DATA_SEGMENT_END.
- So, we can't model it as a function of the current position.
- Instead, we add MarkDataSegmentEnd and friends
- to the script_element ADT.
- *)
-
-let has_writability:'a ->input_spec ->bool= (fun writable -> (fun input_sec -> (
- (match input_sec with
- Common(_, _, _, _)
- -> (* all common symbols are potentially writable *) true
- | InputSection(inp)
- -> let (flags : Nat_big_num.num) = ((match elf_memory_image_section_by_index inp.shndx inp.img with
- Some x -> x.elf64_section_flags
- | None -> failwith ("impossible: no such section" (*(index " ^ (show inp.shndx) ^ ")""*))
- ))
- in
- flag_is_set shf_write flags
- )
-)))
-
-(* LARGE_COMMON seems to have been defined in this patch set:
- https://sourceware.org/ml/binutils/2005-07/txt00014.txt
- and at the time was "only for x86-64". It seems to be analogous
- to ".lbss", i.e. "large bss". libbfd defines SHF_X86_64_LARGE.
- The best comment seems to be in llvm's Support/ELF.h:
-
-0814 // If an object file section does not have this flag set, then it may not hold
-0815 // more than 2GB and can be freely referred to in objects using smaller code
-0816 // models. Otherwise, only objects using larger code models can refer to them.
-0817 // For example, a medium code model object can refer to data in a section that
-0818 // sets this flag besides being able to refer to data in a section that does
-0819 // not set it; likewise, a small code model object can refer only to code in a
-0820 // section that does not set this flag.
-
- *)
-
-(*val address_zero : natural -> address_expr_fn_map allocated_sections_map ->
- (natural * address_expr_fn_map allocated_sections_map * address_expr_fn)*)
-let address_zero fresh alloc_map:Nat_big_num.num*((Nat_big_num.num),(Nat_big_num.num ->allocated_sections_map ->Nat_big_num.num))Pmap.map*address_expr_fn=
- (let alloc_map' = (Pmap.add fresh (fun pos -> (fun secs ->Nat_big_num.of_int 0)) alloc_map) in
- let fresh' = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- (fresh', alloc_map', AddressExprFn fresh))
-
-(*
-val output_sec_composition_size : list output_section_composition_element -> natural
-let output_sec_composition_size comp = List.foldl (+) 0 (List.map size_of_output_section_composition_element comp)
-*)
-(*val do_output_section_layout_starting_at_addr : natural -> allocated_sections_map -> list output_section_composition_element -> (natural * list natural)*)
-let do_output_section_layout_starting_at_addr start_addr (AllocatedSectionsMap secs) comps:Nat_big_num.num*(Nat_big_num.num)list=
-(
- (* map out where we plumb in each section, accounting for their alignment *)List.fold_left (fun (next_free_addr, addr_list) -> (fun comp_el -> (match comp_el with
- IncludeInputSection(retain_pol, irec (* fname, linkable_idx, shndx, isec, img *)) ->
- let aligned_next_free = (align_up_to irec.isec.elf64_section_align next_free_addr)
- in
- (*let _ = errln ("Aligned start address up to 0x" ^ hex_string_of_natural aligned_next_free ^
- " (align 0x" ^ (hex_string_of_natural irec.isec.elf64_section_align) ^
- ") for included output section `" ^
- irec.isec.elf64_section_name_as_string ^ "' from file `" ^ irec.fname ^ "'")
- in*)
- ( Nat_big_num.add aligned_next_free irec.isec.elf64_section_size, List.rev_append (List.rev addr_list) [aligned_next_free])
- | IncludeCommonSymbol(retain_pol, fname1, linkable_idx, def, img2) ->
- let aligned_next_free = (align_up_to (Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_value) next_free_addr)
- in
- ( Nat_big_num.add aligned_next_free (Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_size), List.rev_append (List.rev addr_list) [aligned_next_free])
- (*| Hole(AddressExprFn f) -> (f next_free_addr secs, addr_list ++ [next_free_addr])*)
- | ProvideSymbol(pol, name1, spec) -> (next_free_addr, List.rev_append (List.rev addr_list) [next_free_addr])
- )
- )) (start_addr, []) comps)
-
-(*val output_sec_composition_size_given_start_addr : natural -> allocated_sections_map -> list output_section_composition_element -> natural*)
-let output_sec_composition_size_given_start_addr start_addr secs comp:Nat_big_num.num=
- (let (end_addr, comp_addrs) = (do_output_section_layout_starting_at_addr start_addr secs comp)
- in Nat_big_num.sub_nat
- end_addr start_addr)
-
-(*val sizeof : string -> allocated_sections_map -> natural*)
-let sizeof secname1 (AllocatedSectionsMap secs):Nat_big_num.num=
- ((match Pmap.lookup secname1 secs with
- Some(OutputSectionSpec (_, maybe_addr, _, comp), _) -> (match maybe_addr with
- Some addr -> output_sec_composition_size_given_start_addr addr (AllocatedSectionsMap secs) comp
- | None -> failwith ("error: sizeof applied to section without defined start address")
- )
- | None -> failwith ("error: sizeof applied to non-existent section name " ^ secname1)
- ))
-
-(*val alignof_output_section_composition_element : output_section_composition_element -> natural*)
-let alignof_output_section_composition_element comp:Nat_big_num.num=
- ((match comp with
- IncludeInputSection(_, irec) -> irec.isec.elf64_section_align
- | IncludeCommonSymbol(_, _, _, def, _) -> Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_value
- | _ ->Nat_big_num.of_int 1 (* CHECK *)
- ))
-
-(*val alignof_output_section : list output_section_composition_element -> natural*)
-let alignof_output_section comps:Nat_big_num.num=
- (let aligns = (Lem_list.map alignof_output_section_composition_element comps)
- in
- List.fold_left (fun acc_lcm -> fun next -> lcm acc_lcm next)(Nat_big_num.of_int 1) aligns)
-
-(*val default_linker_control_script : natural -> address_expr_fn_map allocated_sections_map ->
- abi any_abi_feature -> maybe natural -> maybe natural -> maybe natural ->
- natural -> (natural * address_expr_fn_map allocated_sections_map * linker_control_script)*)
-let default_linker_control_script fresh alloc_map a user_text_segment_start user_data_segment_start user_rodata_segment_start elf_headers_size:Nat_big_num.num*((Nat_big_num.num),(Nat_big_num.num ->allocated_sections_map ->Nat_big_num.num))Pmap.map*(script_element)list=
- (let segment_start name1 default= ((match name1 with
- "ldata-segment" -> (match user_data_segment_start with
- None -> default
- | Some addr -> (* fun _ -> *) addr
- )
- | "text-segment" -> (match user_text_segment_start with
- None -> default
- | Some addr -> (* fun _ -> *) addr
- )
- ))
- in
- let is_large_common = (fun inp -> (* FIXME: treat large commons separately *) false
- )
- in
- let is_common = (fun isec1 -> (match isec1 with
- Common(idx1, fname1, img2, def) -> (*let _ = errln ("Common or large-common symbol: " ^ def.def_symname) in *)
- not (is_large_common isec1)
- | _ -> false
- ))
- in
- let alloc_fn1 = (fun _ -> (fun _ -> Nat_big_num.add (segment_start "text-segment" ( Nat_big_num.mul(Nat_big_num.of_int 4)(Nat_big_num.of_int 1048576))) elf_headers_size)) in
- let alloc_fn1_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn1_ref alloc_fn1 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- let alloc_fn2 = (fun addr -> (fun _ -> Nat_big_num.sub_nat
- (* (align_up_to a.maxpagesize addr) - (natural_land (a.maxpagesize - addr) (a.maxpagesize - 1)) *)
- (*
- FIXME: understand the intention of this assignment.
- Evaluating a simple example of this (from true-static-uClibc)
-
- (ALIGN (0x200000) - ((0x200000 - .) & 0x1fffff))
-
- starting from 0x00000000004017dc
- means
- 0x600000 - ((0x200000 - 0x4017dc) & 0x1fffff)
- i.e.
- 0x600000 - (((-0x2017dc)) & 0x1fffff)
- i.e.
- 0x600000 - ( -0x2017dc
- & 0x1fffff )
-
- which really does come to (according to bash) 0x4017dc
- i.e. we subtract 0x1fe824 from 0x600000
- and end up back where we started.
-
- What does ANDing a negative number mean?
- It doesn't seem to work for us.
- Well, to take the negation we flip every bit and add one.
- So if we don't want to do a subtraction that might go negative,
- we can instead add the complement.
- *)
- (align_up_to a.maxpagesize addr) (Nat_big_num.bitwise_and ( Nat_big_num.add a.maxpagesize (compl64 addr)) ( Nat_big_num.sub_nat a.maxpagesize(Nat_big_num.of_int 1))))) in
- let (fresh, alloc_map, (address_zero_fn : address_expr_fn)) = (address_zero fresh alloc_map) in
- let alloc_fn2_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn2_ref alloc_fn2 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- let alloc_fn3 = (fun pos -> (fun secs -> align_up_to (if Nat_big_num.equal pos(Nat_big_num.of_int 0) then (Nat_big_num.div(Nat_big_num.of_int 64)(Nat_big_num.of_int 8)) else Nat_big_num.of_int 1) pos)) in
- let alloc_fn3_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn3_ref alloc_fn3 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- let alloc_fn4 = (fun pos -> (fun secs -> align_up_to (Nat_big_num.div(Nat_big_num.of_int 64)(Nat_big_num.of_int 8)) pos)) in
- let alloc_fn4_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn4_ref alloc_fn4 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- let alloc_fn5 = (fun pos -> (fun secs -> segment_start "ldata-segment" pos)) in
- let alloc_fn5_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn5_ref alloc_fn5 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- let alloc_fn6 = (fun pos -> fun secs -> align_up_to ( Nat_big_num.add a.maxpagesize ( Nat_big_num.sub_nat(Nat_big_num.bitwise_and pos a.maxpagesize)(Nat_big_num.of_int 1))) pos) in
- let alloc_fn6_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn6_ref alloc_fn6 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- let alloc_fn7 = (fun pos -> (fun secs -> (if not (Nat_big_num.equal pos(Nat_big_num.of_int 0)) then Nat_big_num.div(Nat_big_num.of_int 64)(Nat_big_num.of_int 8) else Nat_big_num.of_int 1))) in
- let alloc_fn7_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn7_ref alloc_fn7 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- let alloc_fn8 = (fun pos -> (fun secs -> align_up_to (Nat_big_num.div(Nat_big_num.of_int 64)(Nat_big_num.of_int 8)) pos)) in
- let alloc_fn8_ref = fresh in
- let alloc_map = (Pmap.add alloc_fn8_ref alloc_fn8 alloc_map) in
- let fresh = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- (fresh, alloc_map, [
- (* For now, we base our script on the GNU bfd linker's scripts.
- Here's the static -z combreloc one.
-
-/* Script for -z combreloc: combine and sort reloc sections */
-/* Copyright (C) 2014 Free Software Foundation, Inc.
- Copying and distribution of this script, with or without modification,
- are permitted in any medium without royalty provided the copyright
- notice and this notice are preserved. */
-OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
- "elf64-x86-64")
-OUTPUT_ARCH(i386:x86-64)
-ENTRY(_start)
-SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .note.gnu.build-id : { *(.note.gnu.build-id) }
- .hash : { *(.hash) }
- .gnu.hash : { *(.gnu.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rela.dyn :
- {
- *(.rela.init)
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.* )
- *(.rela.fini)
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.* )
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.* )
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.* )
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.* )
- *(.rela.ctors)
- *(.rela.dtors)
- *(.rela.got)
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.* )
- *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.* )
- *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.* )
- *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.* )
- *(.rela.ifunc)
- }
- .rela.plt :
- {
- *(.rela.plt)
- PROVIDE_HIDDEN (__rela_iplt_start = .);
- *(.rela.iplt)
- PROVIDE_HIDDEN (__rela_iplt_end = .);
- }
- .init :
- {
- KEEP ( *(SORT_NONE(.init)))
- }
- .plt : { *(.plt) *(.iplt) }
- .plt.bnd : { *(.plt.bnd) }
- .text :
- {
- *(.text.unlikely .text.*_unlikely .text.unlikely.* )
- *(.text.exit .text.exit.* )
- *(.text.startup .text.startup.* )
- *(.text.hot .text.hot.* )
- *(.text .stub .text.* .gnu.linkonce.t.* )
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- }
- .fini :
- {
- KEEP ( *(SORT_NONE(.fini)))
- }
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.* ) }
- .rodata1 : { *(.rodata1) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- .eh_frame : ONLY_IF_RO { KEEP ( *(.eh_frame)) }
- .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
- .gcc_except_table.* ) }
- /* These sections are generated by the Sun/Oracle C++ compiler. */
- .exception_ranges : ONLY_IF_RO { *(.exception_ranges
- .exception_ranges* ) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
- /* Exception handling */
- .eh_frame : ONLY_IF_RW { KEEP ( *(.eh_frame)) }
- .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.* ) }
- .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges* ) }
- /* Thread Local Storage sections */
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.* ) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.* ) *(.tcommon) }
- .preinit_array :
- {
- PROVIDE_HIDDEN (__preinit_array_start = .);
- KEEP ( *(.preinit_array))
- PROVIDE_HIDDEN (__preinit_array_end = .);
- }
- .init_array :
- {
- PROVIDE_HIDDEN (__init_array_start = .);
- KEEP ( *(SORT_BY_INIT_PRIORITY(.init_array.* ) SORT_BY_INIT_PRIORITY(.ctors.* )))
- KEEP ( *(.init_array EXCLUDE_FILE ( *crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
- PROVIDE_HIDDEN (__init_array_end = .);
- }
- .fini_array :
- {
- PROVIDE_HIDDEN (__fini_array_start = .);
- KEEP ( *(SORT_BY_INIT_PRIORITY(.fini_array.* ) SORT_BY_INIT_PRIORITY(.dtors.* )))
- KEEP ( *(.fini_array EXCLUDE_FILE ( *crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
- PROVIDE_HIDDEN (__fini_array_end = .);
- }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP ( *crtbegin.o(.ctors))
- KEEP ( *crtbegin?.o(.ctors))
- /* We don't want to include the .ctor section from
- the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP ( *(EXCLUDE_FILE ( *crtend.o *crtend?.o ) .ctors))
- KEEP ( *(SORT(.ctors.* )))
- KEEP ( *(.ctors))
- }
- .dtors :
- {
- KEEP ( *crtbegin.o(.dtors))
- KEEP ( *crtbegin?.o(.dtors))
- KEEP ( *(EXCLUDE_FILE ( *crtend.o *crtend?.o ) .dtors))
- KEEP ( *(SORT(.dtors.* )))
- KEEP ( *(.dtors))
- }
- .jcr : { KEEP ( *(.jcr)) }
- .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.* ) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.* ) }
- .dynamic : { *(.dynamic) }
- .got : { *(.got) *(.igot) }
- . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
- .got.plt : { *(.got.plt) *(.igot.plt) }
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.* )
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- _edata = .; PROVIDE (edata = .);
- . = .;
- __bss_start = .;
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.* )
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections.
- FIXME: Why do we need it? When there is no .bss section, we don't
- pad the .data section. */
- . = ALIGN(. != 0 ? 64 / 8 : 1);
- }
- .lbss :
- {
- *(.dynlbss)
- *(.lbss .lbss.* .gnu.linkonce.lb.* )
- *(LARGE_COMMON)
- }
- . = ALIGN(64 / 8);
- . = SEGMENT_START("ldata-segment", .);
- .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
- {
- *(.lrodata .lrodata.* .gnu.linkonce.lr.* )
- }
- .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
- {
- *(.ldata .ldata.* .gnu.linkonce.l.* )
- . = ALIGN(. != 0 ? 64 / 8 : 1);
- }
- . = ALIGN(64 / 8);
- _end = .; PROVIDE (end = .);
- . = DATA_SEGMENT_END (.);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.* ) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* DWARF 3 */
- .debug_pubtypes 0 : { *(.debug_pubtypes) }
- .debug_ranges 0 : { *(.debug_ranges) }
- /* DWARF Extension. */
- .debug_macro 0 : { *(.debug_macro) }
- .gnu.attributes 0 : { KEEP ( *(.gnu.attributes)) }
- /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_* ) }
-}
- *)
-
- (* function from
- inputs and configuration
- to
- output sections-with-address-and-policy, output symbols-with-address-and-attributes,
- discards, orphans
- BUT
- 1. policy is not a property of output sections, but of *inputs within outputs*
- i.e. KEEP( *(.init))
-
- what's helpful for writing such functions?
-
- e.g. only_if_ro (input_query) (output ):
-
- i.e. ++ only_if_ro OutputSection(AlwaysOutput, Nothing, ".eh_frame", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".eh_frame"))])
-
- want to take a bunch of outputs
- and return a bunch of outputs?
-
- if so, need to return a "current address"
-
- *)
- (DefineSymbol(ProvideIfUsed, "__executable_start", default_symbol_spec))
- ; AdvanceAddress(AddressExprFn alloc_fn1_ref)
- ; OutputSection(AlwaysOutput, None, ".interp", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".interp"))])
- ; OutputSection(AlwaysOutput, None, ".note.gnu.build-id", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".note.gnu.build-id"))])
- ; OutputSection(AlwaysOutput, None, ".hash", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".hash"))])
- ; OutputSection(AlwaysOutput, None, ".gnu.hash", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".gnu.hash"))])
- ; OutputSection(AlwaysOutput, None, ".dynsym", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".dynsym"))])
- ; OutputSection(AlwaysOutput, None, ".dynstr", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".dynstr"))])
- ; OutputSection(AlwaysOutput, None, ".gnu.version", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".gnu.version"))])
- ; OutputSection(AlwaysOutput, None, ".gnu.version_d", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".gnu.version_d"))])
- ; OutputSection(AlwaysOutput, None, ".gnu.version_r", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".gnu.version_r"))])
- ; OutputSection(AlwaysOutput, None, ".rela.dyn", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".rela.init"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.text" s || (name_matches ".rela.text.*" s || name_matches ".rela.gnu.linkonce.t.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.rodata" s || (name_matches ".rela.rodata.*" s || name_matches ".rela.gnu.linkonce.r.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.data" s || (name_matches ".rela.data.*" s || name_matches ".rela.gnu.linkonce.d.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.tdata" s || (name_matches ".rela.tdata.*" s || name_matches ".rela.gnu.linkonce.td.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.tbss" s || (name_matches ".rela.tbss.*" s || name_matches ".rela.gnu.linkonce.tb.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".rela.ctors"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".rela.got"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.bss" s || (name_matches ".rela.bss.*" s || name_matches ".rela.gnu.linkonce.b.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.ldata" s || (name_matches ".rela.ldata.*" s || name_matches ".rela.gnu.linkonce.l.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rela.lbss" s || (name_matches ".rela.lbss.*" s || name_matches ".rela.gnu.linkonce.lb.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".rela.ifunc"))
- ])
- ; OutputSection(AlwaysOutput, None, ".rela.plt", [
- InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".rela.plt"))
- ; DefineSymbol(ProvideIfUsed, "__rela_iplt_start", (Nat_big_num.of_int 0, make_symbol_info stb_local stt_notype (* FIXME *), make_symbol_other stv_hidden))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".rela.iplt"))
- ; DefineSymbol(ProvideIfUsed, "__rela_iplt_end", (Nat_big_num.of_int 0, make_symbol_info stb_local stt_notype (* FIXME *), make_symbol_other stv_hidden))
- ])
- ; OutputSection(AlwaysOutput, None, ".init", [
- InputQuery(KeepEvenWhenGC, SeenOrder, filter_and_concat (name_matches ".init"))
- ])
- ; OutputSection(AlwaysOutput, None, ".plt", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".plt"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".iplt"))
- ])
- ; OutputSection(AlwaysOutput, None, ".plt.bnd", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".plt.bnd"))])
- ; OutputSection(AlwaysOutput, None, ".text", [
- InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".text.unlikely" s || (name_matches ".text.*_unlikely" s || name_matches ".text.unlikely.*" s)
- ))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".text.exit" s || name_matches ".text.exit.*" s))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".text.startup" s || name_matches ".text.startup.*" s))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".text.hot" s || name_matches ".text.hot.*" s))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".text" s || (name_matches ".stub" s || (name_matches ".text.*" s || name_matches ".gnu.linkonce.t.*" s))))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- (* ".gnu.warning sections are handled specially by elf32.em."
- * GAH. That means that what we specify here is not (completely) what
- * needs to happen with these sections. *)
- fun s -> name_matches ".gnu_warning" s))
- ])
- ; OutputSection(AlwaysOutput, None, ".fini", [
- InputQuery(KeepEvenWhenGC, SeenOrder, filter_and_concat (name_matches ".fini"))
- ])
- ; DefineSymbol(ProvideIfUsed, "__etext", default_symbol_spec)
- ; DefineSymbol(ProvideIfUsed, "_etext", default_symbol_spec)
- ; DefineSymbol(ProvideIfUsed, "etext", default_symbol_spec)
- ; OutputSection(AlwaysOutput, None, ".rodata", [
- InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".rodata" s || (name_matches ".rodata.*" s || name_matches ".gnu.linkonce.r.*" s)
- ))])
- ; OutputSection(AlwaysOutput, None, ".eh_frame_hdr", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".eh_frame_hdr")) ])
- ; OutputSection(OnlyIfRo, None, ".eh_frame", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".eh_frame"))])
- ; OutputSection(OnlyIfRo, None, ".gcc_except_table", [InputQuery(DefaultKeep, DefaultSort,
- filter_and_concat (fun s -> name_matches ".gcc_except_table" s || name_matches ".gcc_except_table.*" s))])
- ; OutputSection(OnlyIfRo, None, ".exception_ranges", [InputQuery(DefaultKeep, DefaultSort,
- filter_and_concat (fun s -> name_matches ".exception_ranges" s || name_matches ".exception_ranges*" s))])
- ; AdvanceAddress(AddressExprFn alloc_fn2_ref)
- ; MarkAndAlignDataSegment( Nat_big_num.mul (Nat_big_num.mul(Nat_big_num.of_int (* a.maxpagesize *)2)(Nat_big_num.of_int 1024))(Nat_big_num.of_int 1024) (* <-- for some reason binutils assumes 2MB max page size,
- even if ABI says smaller *), a.commonpagesize)
- ; OutputSection(OnlyIfRw, None, ".eh_frame", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".eh_frame"))])
- ; OutputSection(OnlyIfRw, None, ".gcc_except_table", [InputQuery(DefaultKeep, DefaultSort,
- filter_and_concat (fun s -> name_matches ".gcc_except_table" s || name_matches ".gcc_except_table.*" s))])
- ; OutputSection(OnlyIfRw, None, ".exception_ranges", [InputQuery(DefaultKeep, DefaultSort,
- filter_and_concat (fun s -> name_matches ".exception_ranges" s || name_matches ".exception_ranges*" s))])
- ; OutputSection(AlwaysOutput, None, ".tdata", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat
- (fun s -> name_matches ".tdata" s || (name_matches ".tdata.*" s || name_matches ".gnu.linkonce.td.*" s)))])
- ; OutputSection(AlwaysOutput, None, ".tbss", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat
- (fun s -> name_matches ".tbss" s || (name_matches ".tbss.*" s || name_matches ".gnu.linkonce.tb.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".tcommon"))])
- ; OutputSection(AlwaysOutput, None, ".preinit_array", [
- DefineSymbol(ProvideIfUsed, "__preinit_array_start", default_symbol_spec)
- ; InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat (fun s -> name_matches ".preinit_array" s))
- ; DefineSymbol(ProvideIfUsed, "__preinit_array_end", default_symbol_spec)
- ])
- ; OutputSection(AlwaysOutput, None, ".init_array", [
- DefineSymbol(ProvideIfUsed, "__init_array_start", default_symbol_spec)
- ; InputQuery(KeepEvenWhenGC, ByInitPriority, filter_and_concat (fun s -> name_matches ".init_array.*" s))
- ; InputQuery(KeepEvenWhenGC, ByInitPriority, filter_and_concat (fun s -> name_matches ".ctors.*" s))
- ; InputQuery(KeepEvenWhenGC, ByInitPriority, filter_and_concat
- (fun s -> name_matches ".init_array" s
- || (name_matches ".ctors" s && not (file_matches "*crtbegin.o" s || (file_matches "*crtbegin?.o" s
- || (file_matches "*crtend.o" s || file_matches "*crtend?.o " s)))))
- )
- ; DefineSymbol(ProvideIfUsed, "__init_array_end", default_symbol_spec)
- ])
- ; OutputSection(AlwaysOutput, None, ".fini_array", [
- DefineSymbol(ProvideIfUsed, "__fini_array_start", default_symbol_spec)
- ; InputQuery(KeepEvenWhenGC, ByInitPriority, filter_and_concat (fun s -> name_matches ".fini_array.*" s))
- ; InputQuery(KeepEvenWhenGC, ByInitPriority, filter_and_concat (fun s -> name_matches ".dtors.*" s))
- ; InputQuery(KeepEvenWhenGC, ByInitPriority, filter_and_concat
- (fun s -> name_matches ".fini_array" s
- || (name_matches ".dtors" s && not (file_matches "*crtbegin.o" s || (file_matches "*crtbegin?.o" s
- || (file_matches "*crtend.o" s || file_matches "*crtend?.o " s)))))
- )
- ; DefineSymbol(ProvideIfUsed, "__fini_array_end", default_symbol_spec)
- ])
- ; OutputSection(AlwaysOutput, None, ".ctors", [
- InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat (fun s -> file_matches "*crtbegin.o" s && name_matches ".ctors" s))
- ; InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat (fun s -> file_matches "*crtbegin?.o" s && name_matches ".ctors" s))
- ; InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat
- (fun s -> not (file_matches "*crtend.o" s || file_matches "*crtend?.o" s) && name_matches ".ctors" s))
- ; InputQuery(KeepEvenWhenGC, ByName, filter_and_concat (fun s -> name_matches ".ctors.*" s))
- ; InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat
- (fun s -> (file_matches "*crtend.o" s || file_matches "*crtend?.o" s) && name_matches ".ctors" s))
- (* NOTE: this exclusion is implicit in the usual linker script,
- * because it won't match an input section more than once. We should
- * just replicate this behaviour, since other parts of the script might rely on it
- * less obviously. *)
- ])
- ; OutputSection(AlwaysOutput, None, ".dtors", [
- InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat (fun s -> file_matches "*crtbegin.o" s && name_matches ".dtors" s))
- ; InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat (fun s -> file_matches "*crtbegin?.o" s && name_matches ".dtors" s))
- ; InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat
- (fun s -> not (file_matches "*crtend.o" s || file_matches "*crtend?.o" s) && name_matches ".dtors" s))
- ; InputQuery(KeepEvenWhenGC, ByName, filter_and_concat (fun s -> name_matches ".dtors.*" s))
- ; InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat
- (fun s -> (file_matches "*crtend.o" s || file_matches "*crtend?.o" s) && name_matches ".dtors" s))
- ])
- ; OutputSection(AlwaysOutput, None, ".jcr", [InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat (name_matches ".jcr"))])
- ; OutputSection(AlwaysOutput, None, ".data.rel.ro", [
- InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".data.rel.ro.local*" s || name_matches ".gnu.linkonce.d.rel.ro.local.*" s
- ));
- InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".data.rel.ro" s || (name_matches ".data.rel.ro.*" s || name_matches ".gnu.linkonce.d.rel.ro.*" s)
- ))
- ])
- ; OutputSection(AlwaysOutput, None, ".dynamic", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".dynamic"))])
- ; OutputSection(AlwaysOutput, None, ".got", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".got"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".igot"))
- ])
- ; MarkDataSegmentRelroEnd (*(fun secs -> (if (sizeof ".got.plt" secs) >= 24 then 24 else 0, (fun pos -> pos)))*)
- ; OutputSection(AlwaysOutput, None, ".got.plt", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".got.plt"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".igot.plt"))
- ])
- ; OutputSection(AlwaysOutput, None, ".data", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".data" s || (name_matches ".data.*" s || name_matches ".gnu.linkonce.d.*" s)))
- (* the script also has SORT(CONSTRUCTORS) here, but it has no effect for ELF (I think) *)
- ])
- ; OutputSection(AlwaysOutput, None, ".data1", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".data1"))])
- ; DefineSymbol(AlwaysDefine, "_edata", default_symbol_spec)
- ; DefineSymbol(ProvideIfUsed, "edata", default_symbol_spec)
- ; (* . = .; <-- does this do anything? YES! It forces an output section to be emitted.
- Since it occurs *outside* any output section,
- it is assumed to start
- *)
- DefineSymbol(AlwaysDefine, "__bss_start", default_symbol_spec)
- ; OutputSection(AlwaysOutput, None, ".bss", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".dynbss"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".bss" s || (name_matches ".bss.*" s || name_matches ".gnu.linkonce.b.*" s)))
- ; InputQuery(DefaultKeep, DefaultSort, (fun inputlist ->
- (*let _ = errln "Looking for commons" in *)
- let result = (filter_and_concat is_common inputlist)
- in
- (*let _ = errln ("Got " ^ (show (length (result))) ^ " commons; sanity check: input list contains " ^
- (show (length inputlist)) ^ " of which " ^
- (show (length (List.filter (fun inp -> match inp with
- Common _ -> true
- | _ -> false
- end) inputlist))) ^ " are commons."
- )
- in*) result)
- )
- ])
- ; AdvanceAddress(AddressExprFn alloc_fn3_ref)
- ; OutputSection(AlwaysOutput, None, ".lbss", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".dynlbss"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".dynlbss"))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".lbss" s || (name_matches ".lbss.*" s || name_matches ".gnu.linkonce.lb.*" s)
- ))
- ; InputQuery(DefaultKeep, DefaultSort, filter_and_concat (is_large_common))
- ])
- ; AdvanceAddress(AddressExprFn alloc_fn4_ref)
- ; AdvanceAddress(AddressExprFn alloc_fn5_ref)
- ; OutputSection(AlwaysOutput, Some (AddressExprFn alloc_fn6_ref),
- ".lrodata",
- [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".lrodata" s || (name_matches ".lrodata.*" s || name_matches ".gnu.linkonce.lr.*" s)
- ))
- ; AdvanceAddress(AddressExprFn alloc_fn7_ref)
- ])
- ; AdvanceAddress(AddressExprFn alloc_fn8_ref)
- ; DefineSymbol(AlwaysDefine, "_end", default_symbol_spec)
- ; DefineSymbol(ProvideIfUsed, "end", default_symbol_spec)
- ; MarkDataSegmentEnd
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".stab", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".stab"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".stabstr", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".stabstr"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".stab.excl", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".stab.excl"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".stab.exclstr", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".stab.exclstr"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".stab.index", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".stab.index"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".stab.indexstr", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".stab.indexstr"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".comment", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".comment"))])
- (* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. *)
- (* DWARF 1 *)
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".line", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".line"))])
- (* GNU DWARF 1 extensions *)
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_srcinfo", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_srcinfo"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_sfnames", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_sfname"))])
- (* DWARF 1.1 and DWARF 2 *)
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_aranges", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_aranges"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_pubnames", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_pubnames"))])
- (* DWARF 2 *)
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_info", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".debug_info" s || name_matches ".gnu.linkonce.wi.*" s))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_abbrev", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_abbrev"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_line", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (
- fun s -> name_matches ".debug_line" s || (name_matches ".debug_line.*" s || name_matches ".debug_line_end" s)))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_frame", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_frame"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_str", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_str"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_loc", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_loc"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_macinfo", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_macinfo"))])
- (* SGI/MIPS DWARF 2 extensions *)
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_weaknames", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_weaknames"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_funcnames", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_funcnames"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_typenames", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_typenames"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_varnames", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_varnames"))])
- (* DWARF 3 *)
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_pubtypes", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_pubtypes"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_ranges", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_ranges"))])
- (* DWARF Extension. *)
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".debug_macro", [InputQuery(DefaultKeep, DefaultSort, filter_and_concat (name_matches ".debug_macro"))])
- ; OutputSection(AlwaysOutput, Some address_zero_fn, ".gnu.attributes", [InputQuery(KeepEvenWhenGC, DefaultSort, filter_and_concat (name_matches ".gnu.attributes"))])
- ; DiscardInput(filter_and_concat (fun s -> name_matches ".note.GNU-stack" s || (name_matches ".gnu_debuglink" s || name_matches ".gnu.lto_*" s)))
- (* NOTE: orphan sections are dealt with in the core linking logic,
- not the script. *)
- ]))
-
-let interpret_guard guard comp name1:bool=
- ((match guard with
- always0 -> true
- | OnlyIfRo ->
- let v = (List.for_all (fun comp_el -> (match comp_el with
- IncludeInputSection(retainpol, (* fname, linkable_idx, shndx, isec, img *) irec) -> Nat_big_num.equal(Nat_big_num.of_int
- (* is this section read-only? if it doesn't have shf_write, yes *)0) (Nat_big_num.bitwise_and irec.isec.elf64_section_flags shf_write)
- | _ -> (* holes, common symbols and provided symbols shouldn't prevent ONLY_IF_RO *) true
- )) comp)
- in (*let _ = errln ("only_if_ro evaluated " ^ (show v) ^ " for output section " ^ name)
- in*) v
- | OnlyIfRw ->
- let v = (List.for_all (fun comp_el -> (match comp_el with
- IncludeInputSection(retainpol, (* fname, linkable_idx, shndx, isec, img *) irec) -> not (Nat_big_num.equal(Nat_big_num.of_int
- (* is this section read-only? if it doesn't have shf_write, yes *)0) (Nat_big_num.bitwise_and irec.isec.elf64_section_flags shf_write))
- | _ -> (* holes etc. shouldn't prevent ONLY_IF_RW *) true
- )) comp)
- in (*let _ = errln ("only_if_rw evaluated " ^ (show v) ^ " for output section " ^ name)
- in *)v
- ))
-
-(* Passes over the script:
- *
- * 1. assign input sections to output sections (or discard) and define symbols.
- *
- * 2. compute def-use and optionally GC, removing unwanted sections and symbols
- *
- * 3. build image, assigning addresses as we go.
- *
- * Some passes require matching/retrieving what a previous pass on the same node did.
- * So we give each script element a natural "idx" label.
- *)
-(*val label_script_aux : natural -> linker_control_script -> labelled_linker_control_script*)
-let label_script_aux start script1:(script_element*Nat_big_num.num)list=
- (mapi (fun i -> fun el -> (el, ( Nat_big_num.add start (Nat_big_num.of_int i)))) script1)
-
-(*val label_script : linker_control_script -> labelled_linker_control_script*)
-let label_script script1:(script_element*Nat_big_num.num)list= (label_script_aux(Nat_big_num.of_int 0) script1)
-
-type input_output_assignment = ( input_spec list * (output_section_spec * Nat_big_num.num) list)
-
-(*val assign_inputs_to_output_sections :
- input_output_assignment -> (* accumulator: list of discards, list of output compositions (these include symbols) *)
- set (natural * natural) -> (* used sections *)
- set (natural * natural * natural) -> (* used commons *)
- list input_spec -> (* remaining inputs *)
- maybe (output_section_spec * natural) -> (* cur_sec -- the current output section spec and its OutputSection script item idx *)
- maybe input_spec -> (* last input section to be output -- might not have one *)
- (input_spec -> input_spec -> Basic_classes.ordering) (* "seen ordering" *) ->
- labelled_linker_control_script ->
- input_output_assignment*) (* accumulated result *)
-let rec assign_inputs_to_output_sections acc used_sections used_commons inputs (cur_output_sec : (output_section_spec * Nat_big_num.num)option) last_input_sec seen_ordering script1:(input_spec)list*(output_section_spec*Nat_big_num.num)list=
- (let (rev_discards, rev_outputs) = acc in
- let flush_output_sec
- = (fun maybe_output_sec_and_idx -> (match (maybe_output_sec_and_idx : (output_section_spec * Nat_big_num.num)option) with
- Some (OutputSectionSpec (guard, addr, name1, comp), script_idx) ->
- (*let _ = errln ("Guardedly flushing output section named " ^ name ^ " with " ^ (
- match addr with Nothing -> "no address yet" | Just a -> "address 0x" ^ (hex_string_of_natural a) end
- ) ^ " and composed of " ^ (show (length comp)) ^ " constituents.")
- in*)
- (* evaluate the guard *)
- if interpret_guard guard comp name1
- then (* do it *) (rev_discards, (((OutputSectionSpec (guard, addr, name1, comp)), script_idx) :: rev_outputs))
- else (* ignore it *) acc
- | None -> (* for convenience, make this a no-op rather than error *)
- (* failwith "internal error: flushing output section with no current output section" *)
- acc
- ))
- in
- (match script1 with
- [] -> flush_output_sec cur_output_sec
- | (element1, idx1) :: more_elements_and_idx ->
- let do_nothing = (acc, used_sections, used_commons, cur_output_sec, last_input_sec)
- in
- let (new_acc, new_used_sections, new_used_commons, (new_cur_output_sec : (output_section_spec * Nat_big_num.num)option), new_last_input_sec)
- = ((match element1 with
- DefineSymbol(symdefpol, name1, (symsize, syminfo, symother)) ->
- (* Label the current section in the image
- * with a new symbol definition. If there isn't
- * a current section, use the ABS section (what is that labelling?). *)
- (acc,
- used_sections,
- used_commons,
- (match (cur_output_sec : (output_section_spec * Nat_big_num.num)option) with
- None -> (*let _ = errln ("FIXME: for defining `" ^ name ^ "': ABS symbol defs not yet supported") in*) None
- | Some ((OutputSectionSpec (guard, maybe_addr, secname1, comp)), output_script_idx) ->
- (*let _ = errln ("Including a symbol named `" ^ name ^ " in composition of output section `" ^ secname ^ "'") in*)
- Some ((OutputSectionSpec (guard, maybe_addr, secname1,
- List.rev_append (List.rev comp) [ProvideSymbol(symdefpol, name1, (symsize, syminfo, symother))]))
- , output_script_idx)
- ),
- last_input_sec)
- | AdvanceAddress(AddressExprFn advance_fn) ->
- (* If we're inside a section, insert a hole,
- * else just update the logical address *)
- (*let _ = errln ("Advancing location counter") in*)
- (match cur_output_sec with
- None -> do_nothing
- (* This assignment is setting a new LMA. *)
- (* (acc, *)
- | Some (sec, idx1) -> do_nothing
- )
- | MarkAndAlignDataSegment(maxpagesize1, commonpagesize1) ->
- (* The "data segment end" is a distinguished label,
- * so we can encode the whole thing into a conditional. *)
- (*let _ = errln ("Mark/aligning data segment") in*)
- do_nothing
- | MarkDataSegmentEnd ->
- (*let _ = errln ("Marking data segment end") in*)
- do_nothing
- | MarkDataSegmentRelroEnd(*(fun_from_secs_to_something)*) ->
- (*let _ = errln ("Marking data segment relro end") in*)
- do_nothing
- | OutputSection(outputguard, maybe_expr, name1, sub_elements) ->
- (* If we have a current output section, finish it and add it to the image.
- * Q. Where do guards ("ONLY_IF_RO" etc) get evaluated?
- * A. Inside flush_output_sec. *)
- (*let _ = errln ("Recursively composing a new output section `" ^ name ^ "'...") in*)
- let acc_with_output_sec = (flush_output_sec cur_output_sec)
- in
- let new_cur_output_sec = (Some((OutputSectionSpec(outputguard, (* maybe_expr pos secs *) None, name1, [])), idx1))
- in
- (* Recurse down the list of input queries, assigning them to this output sec
- * Note that output sections may not nest within other output sections.
- * At the end of the list of sub_elements, we will flush the section we built up.
- *)
- let final_acc
- = (assign_inputs_to_output_sections acc used_sections used_commons inputs new_cur_output_sec last_input_sec seen_ordering (label_script sub_elements))
- in
- (* NOTE that this sub-accumulation will never add a new output section
- * because output sections can't nest. *)
- (final_acc, used_sections, used_commons, (* cur_output_sec *) None, last_input_sec)
- | DiscardInput(selector) ->
- let selected = (selector inputs)
- in
- let (rev_discards, rev_outputs) = acc in
- (*let _ = Missing_pervasives.errln ("Processing discard rule; selected " ^ (show (length selected))
- ^ " inputs.")
- in*)
- (( List.rev_append (List.rev (List.rev (let x2 =
- ([]) in List.fold_right (fun i x2 -> if true then i :: x2 else x2) selected x2))) rev_discards, rev_outputs), used_sections, used_commons, cur_output_sec, last_input_sec)
- | InputQuery(retainpol, sortpol, selector) ->
- (* Input queries can only occur within an output section. *)
- (match cur_output_sec with
- None -> failwith "linker script error: input query without output section"
- | Some ((OutputSectionSpec (output_guard1, output_sec_addr, output_sec_name, output_composition)), output_script_idx) ->
- (* Add them to the current output spec. We have to be careful about ordering:
- * according to the GNU ld manual (and observed behaviour), by default
- * "the linker will place files and sections matched by wildcards in the order
- * in which they are seen during the link". For .o files on the command line,
- * this means the command line order. But for members of archives, it means
- * the order in which they were "pulled in" during input enumeration. We
- * actually don't compute this here; it is passed in from our caller in link.lem. *)
- let sortfun = ((match sortpol with
- DefaultSort -> List.sort seen_ordering (* FIXME: pay attention to command line *)
- | SeenOrder -> List.sort seen_ordering
- | ByName -> List.sort compareInputSpecByName
- | ByNameThenAlignment -> List.sort compareInputSpecByNameThenAlignment
- | ByAlignment -> List.sort compareInputSpecByAlignment
- | ByAlignmentThenName -> List.sort compareInputSpecByAlignmentThenName
- | ByInitPriority -> List.sort compareInputSpecByInitPriority
- ))
- in
- let selected = (selector inputs)
- in
- let selected_deduplicated = (List.filter (fun inp -> (match inp with
- InputSection(irec) -> not ( Pset.mem(irec.idx, irec.shndx) used_sections)
- | Common(idx1, fname1, img2, def) -> not ( Pset.mem(idx1, def.def_sym_scn, def.def_sym_idx) used_commons)
- )) selected)
- in
- (*let _ = errln ("Evaluated an input query, yielding " ^
- (show (length selected)) ^ " undeduplicated and " ^
- (show (length selected_deduplicated)) ^
- " deduplicated results, to be added to composition currently of " ^
- (show (length output_composition)) ^ " items.") in*)
- (* Search input memory images for matching sections. *)
- let sorted_selected_inputs = (sortfun selected_deduplicated)
- in
- let (sectionMatchList : input_section_rec list) = (Lem_list.mapMaybe (fun inp ->
- (match inp with
- InputSection(x) ->
- (*let _ = errln ("Matched an input section named " ^ x.isec.elf64_section_name_as_string ^
- " in a file " ^ x.fname ^ " with first 20 bytes " ^ (show (take 20
- (let maybe_elname = elf_memory_image_element_coextensive_with_section x.shndx x.img
- in
- match maybe_elname with
- Nothing -> failwith ("impossible: no such element (matching shndx " ^ (show x.shndx) ^ ")")
- | Just idstr ->
- match Map.lookup idstr x.img.elements with
- Just el -> el.contents
- | Nothing -> failwith "no such element"
- end
- end
- ))))
- in*)
- Some x
- | _ -> None
- )) sorted_selected_inputs)
- in
- let commonMatchList = (Lem_list.mapMaybe (fun inp ->
- (match inp with
- | Common(idx1, fname1, img2, def) -> Some(idx1, fname1, img2, def)
- | _ -> None
- )) sorted_selected_inputs)
- in
-
- (acc,
- Pset.(union) used_sections (let x2 =(Pset.from_list (pairCompare Nat_big_num.compare Nat_big_num.compare)
- []) in List.fold_right
- (fun irec x2 -> if true then Pset.add (irec.idx, irec.shndx) x2 else x2)
- sectionMatchList x2),
- Pset.(union) used_commons (let x2 =(Pset.from_list (tripleCompare Nat_big_num.compare Nat_big_num.compare Nat_big_num.compare)
- []) in List.fold_right
- (fun(idx1, fname1, img2, def) x2 ->
- if true then Pset.add (idx1, def.def_sym_scn, def.def_sym_idx) x2 else x2)
- commonMatchList x2),
- (* new_cur_output_spec *) Some (
- (OutputSectionSpec(output_guard1, output_sec_addr, output_sec_name,
- List.rev_append (List.rev (List.rev_append (List.rev output_composition) (let x2 =
- ([]) in List.fold_right
- (fun input_sec x2 ->
- if true then
- IncludeInputSection
- (retainpol, (* input_sec.fname, input_sec.idx, input_sec.shndx, input_sec.isec, input_sec.img *) input_sec)
- :: x2 else x2) sectionMatchList x2))) (let x2 = ([]) in List.fold_right
- (fun(idx1, fname1, img2, def) x2 ->
- if true then
- IncludeCommonSymbol (DefaultKeep, fname1, idx1, def, img2) :: x2 else
- x2) commonMatchList x2)
- )), output_script_idx),
- last_input_sec
- )
- )
- ))
- in
- (*let _ = match new_cur_output_sec with
- Just (OutputSectionSpec (guard, addr, name, comp), script_idx) ->
- errln ("Now output section `" ^ name ^ "' is composed of " ^ (show (length comp)) ^ " elements.")
- | Nothing -> ()
- end in*)
- assign_inputs_to_output_sections new_acc new_used_sections new_used_commons
- (inputs : input_spec list)
- (new_cur_output_sec)
- (new_last_input_sec : input_spec option)
- seen_ordering
- (more_elements_and_idx : labelled_linker_control_script)
- ))
-
-(* NOTE: this is also responsible for deleting any PROVIDEd symbols that
- * were not actually referenced. BUT HOW, if we haven't built the image and
- * hence haven't added the symbols yet? Symbols affect reachability, so
- * we're going to have to figure this out. Really we want a memory image that
- * does not yet have addresses assigned, but does have the symbols inserted.
- * BUT even that is not right, because we want to be able to remove some
- * sections (GC them). So the section composition is not yet fixed. So we have
- * a problem.
- *
- * Note that the only symbols we have to remove are ones that were PROVIDEd
- * in our output composition. So doing the GC on output compositions seems
- * sane. We can get the graph's edge list by inspecting the constituent memory
- * images from which each output section composition element is drawn.
- * Collecting sections and collecting symbols seems fair. Note that symbols
- * can never be placed mid-section (I don't think?? they can use arbitrary
- * expressions, but not that depend on whether an input section is included
- * or not) so removing a section should never imply the removal of a symbol.
- *
- * So that implies we need not yet build a memory image.
- *)
-(*val compute_def_use_and_gc : allocated_sections_map -> allocated_sections_map*)
-let compute_def_use_and_gc outputs_by_name:allocated_sections_map= outputs_by_name (* FIXME: implement GC *)
-
-let output_section_type comp:Nat_big_num.num=
-(
- (* are we composed entirely of nobits sections and common symbols? *)let all_nobits = (List.for_all (fun comp_el ->
- (match comp_el with
- IncludeInputSection(retain_pol,(* fname, linkable_idx, shndx, isec, img *) irec) -> Nat_big_num.equal
- irec.isec.elf64_section_type sht_nobits
- | IncludeCommonSymbol(retain_pol, fname1, linkable_idx, def, img2) -> true
- | _ -> (* padding and symdefs can be nobits *) true
- )) comp)
- in
- if all_nobits then sht_nobits else sht_progbits)
-
-let output_section_flags comp:Nat_big_num.num=
- (let writable = (List.exists (fun comp_el ->
- (match comp_el with
- IncludeInputSection(retain_pol, (* fname, linkable_idx, shndx, isec, img *) irec) ->
- flag_is_set shf_write irec.isec.elf64_section_flags
- | IncludeCommonSymbol(retain_pol, fname1, linkable_idx, def, img2) ->
- (* assume common symbols are writable *) true
- | _ -> (* padding and symdefs do not make a section writable *) false
- )) comp)
- in
- let executable = (List.exists (fun comp_el ->
- (match comp_el with
- IncludeInputSection(retain_pol,(* fname, linkable_idx, shndx, isec, img *) irec) ->
- flag_is_set shf_execinstr irec.isec.elf64_section_flags
- | IncludeCommonSymbol(retain_pol, fname1, linkable_idx, def, img2) ->
- (* assume common symbols are not executable, since they're zeroed *) false
- | _ -> (* padding and symdefs do not make a section executable -- HMM *) false
- )) comp)
- in
- let alloc = (List.exists (fun comp_el ->
- (match comp_el with
- IncludeInputSection(retain_pol, (* fname, linkable_idx, shndx, isec, img *) irec) ->
- flag_is_set shf_alloc irec.isec.elf64_section_flags
- | IncludeCommonSymbol(retain_pol, fname1, linkable_idx, def, img2) ->
- (* common symbols are allocatable *) true
- | ProvideSymbol(pol, name1, spec) ->
- (* symbols make a section allocatable? HMM *) true
- | _ -> (* padding does not make a section allocatable *) false
- )) comp)
- in
- let is_thread_local_yesnomaybe = (fun comp_el ->
- (match comp_el with
- IncludeInputSection(retain_pol, (* fname, linkable_idx, shndx, isec, img *) irec) ->
- Some(flag_is_set shf_tls irec.isec.elf64_section_flags)
- | IncludeCommonSymbol(retain_pol, fname1, linkable_idx, def, img2) ->
- (* FIXME: support tcommon *) Some(false)
- | ProvideSymbol(pol, name1, spec) ->
- (* linker script symbols shouldn't be defined here, unless they can be declared thread-local (FIXME: can they?) *)
- Some false
- | _ -> (* padding does not make a section thread-local, or non-. *) None
- )
- )
- in
- let thread_local = (
- (* Is any element positively thread-local? *)
- let v = (List.fold_left (fun acc_ynm -> fun comp_el ->
- let new_ynm = (is_thread_local_yesnomaybe comp_el)
- in
- (match (acc_ynm, new_ynm) with
- (None, None) -> None
- | (None, Some x) -> Some x
- | (Some x, None) -> Some x
- | (Some true, Some false) -> Some true
- | (Some true, Some true) -> Some true
- | (Some false, Some false) -> Some false
- | (Some true, Some false) -> Some true
- )) None comp)
- in
- if (Lem.option_equal (=) v (Some(true))) && not ( (Lem.option_equal (=)(Some(true)) (* are *all* either don't-care or positively thread-local? *)
- (List.fold_left (fun acc_ynm -> fun comp_el ->
- let new_ynm = (is_thread_local_yesnomaybe comp_el)
- in
- (match (acc_ynm, new_ynm) with
- (None, None) -> None
- | (None, Some x) -> Some x
- | (Some x, None) -> Some x
- | (Some true, Some false) -> Some false
- | (Some true, Some true) -> Some true
- | (Some false, Some false) -> Some false
- | (Some true, Some false) -> Some false
- )) None comp))) then failwith "error: section mixes thread-local and non-thread-local inputs"
- else (match v with
- None -> false
- | Some x -> x
- )
- )
- in
- Nat_big_num.bitwise_or
- (if thread_local then shf_tls else Nat_big_num.of_int 0)
- (Nat_big_num.bitwise_or
- (if executable then shf_execinstr else Nat_big_num.of_int 0)
- (Nat_big_num.bitwise_or
- (if writable then shf_write else Nat_big_num.of_int 0)
- (if alloc then shf_alloc else Nat_big_num.of_int 0)
- )
- ))
-
-let symbol_def_for_provide_symbol name1 size2 info other control_script_linkable_idx:symbol_definition=
- ({
- def_symname = (*let _ = errln ("Linker script is defining symbol called `" ^ name ^ "'") in*) name1
- ; def_syment = ({
- elf64_st_name = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (* ignored *)
- ; elf64_st_info = info
- ; elf64_st_other = other
- ; elf64_st_shndx = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0)))
- ; 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 size2))
- })
- ; def_sym_scn =(Nat_big_num.of_int 0)
- ; def_sym_idx =(Nat_big_num.of_int 0)
- ; def_linkable_idx = control_script_linkable_idx
- })
-
-(*val assign_dot_to_itself : natural -> address_expr_fn_map allocated_sections_map -> (natural * address_expr_fn_map allocated_sections_map * address_expr_fn)*)
-let assign_dot_to_itself fresh alloc_map:Nat_big_num.num*((Nat_big_num.num),(Nat_big_num.num ->allocated_sections_map ->Nat_big_num.num))Pmap.map*address_expr_fn=
- (let fn = (fun dot -> fun _ -> dot) in
- let alloc_map' = (Pmap.add fresh fn alloc_map) in
- let fresh' = (Nat_big_num.add(Nat_big_num.of_int 1) fresh) in
- (fresh', alloc_map', AddressExprFn fresh))
-
-(*val build_image :
- address_expr_fn_map allocated_sections_map -> (* global dictionary of address_expr_fn_ref -> address_expr_fn *)
- elf_memory_image -> (* accumulator *)
- natural -> (* location counter *)
- allocated_sections_map -> (* outputs constructed earlier *)
- (Map.map string (list (natural * binding))) -> (* bindings_by_name *)
- labelled_linker_control_script ->
- natural -> (* control_script_linkable_idx *)
- (Map.map string (list symbol_definition)) -> (* linker_defs_by_name *)
- (elf_memory_image * allocated_sections_map)*) (* accumulated result *)
-let rec build_image alloc_map acc pos (AllocatedSectionsMap outputs_by_name) bindings_by_name script1 control_script_linkable_idx linker_defs_by_name:(any_abi_feature)annotated_memory_image*allocated_sections_map=
- (let (add_output_section : (Nat_big_num.num * elf_memory_image) -> output_section_spec -> (Nat_big_num.num * elf_memory_image * Nat_big_num.num * output_section_spec))
- = (fun ((*scn_idx, *)pos, acc_img) ->
- (fun (OutputSectionSpec (guard, addr, secname1, comp)) ->
- (*let _ = errln ("Computing composition of output section `" ^ secname ^ "' from " ^ (show (length comp)) ^ " elements")
- in*)
- let unaligned_start_addr = ((match addr with
- Some a -> failwith ("internal error: section " ^ (secname1 ^ ": did not expect address to be assigned yet"))
- | None -> pos
- ))
- in
- let align = (alignof_output_section comp)
- in
- (*let _ = errln ("Aligning start of output section " ^ secname ^ " up to a " ^ (show align) ^ "-byte address boundary")
- in*)
- let output_section_start_addr = (align_up_to align unaligned_start_addr)
- in
- let (end_addr, comp_addrs) = (do_output_section_layout_starting_at_addr output_section_start_addr (AllocatedSectionsMap outputs_by_name) comp)
- in
- let size2 = (Nat_big_num.sub_nat end_addr output_section_start_addr)
- in
- (*let _ = Missing_pervasives.outln (
- if List.null comp then secname else (
- ((space_padded_and_maybe_newline 16 secname) ^
- ("0x" ^ (left_zero_padded_to 16 (hex_string_of_natural output_section_start_addr))) ^ " " ^
- (left_space_padded_to 10 ("0x" ^ (hex_string_of_natural size))))
- )
- )
- in*)
- let (concatenated_content, final_addr, new_range_tag_pairs) = (List.fold_left (fun (accum_pat, accum_current_addr, accum_meta) -> (fun (comp_el, comp_addr) ->
- (*let _ = errln ("Adding an element to composition of output section `" ^ secname ^ "', current address 0x" ^ (hex_string_of_natural accum_current_addr))
- in*)
- let make_line = (fun namestr -> (fun addrstr -> (fun szstr -> (fun rhs -> (
- (space_padded_and_maybe_newline(Nat_big_num.of_int 16) (" " ^ namestr)) ^
- (("0x" ^ (left_zero_padded_to(Nat_big_num.of_int 16) addrstr)) ^ (" " ^
- ((left_space_padded_to(Nat_big_num.of_int 10) ("0x" ^ szstr)) ^ (" " ^ rhs))))
- )))))
- in
- let (sz, comp_el_pat, this_el_meta) = ((match comp_el with
- | IncludeInputSection(retainpolicy, (* fname, linkable_idx, shndx, isec, img *) irec) ->
- (* We want to get the input section as a byte pattern *)
- (*let _ = errln ("Processing inclusion of input section `" ^ irec.isec.elf64_section_name_as_string
- ^ "' from file `" ^ irec.fname
- ^ "' into output section `" ^ secname
- ^ "'")
- in*)
- let maybe_secname = (elf_memory_image_element_coextensive_with_section irec.shndx irec.img)
- in
- (match maybe_secname with
- None -> failwith ("impossible: no such section" (*(matching irec.shndx " ^ (show irec.shndx) ^ ")""*))
- | Some idstr ->
- (*let _ = errln ("Found element named " ^ idstr ^ " coextensive with section named " ^
- irec.isec.elf64_section_name_as_string ^ " in file " ^ irec.fname)
- in*)
- (match Pmap.lookup idstr irec.img.elements with
- Some el ->
- (*let _ = Missing_pervasives.outln (make_line irec.isec.elf64_section_name_as_string
- (hex_string_of_natural comp_addr) (hex_string_of_natural irec.isec.elf64_section_size)
- irec.fname)
- in*)
- let section_el_name = (get_unique_name_for_section_from_index irec.shndx irec.isec irec.img)
- in
- (*let _ = errln ("Copying metadata for output section `" ^ section_el_name ^ "'") in*)
- let range_or_sym_is_in_this_sec = (fun maybe_range -> (fun tag ->
- (* is it within the section we're outputting?
- * first we needs its element name. *)
- (* filter out ones that don't overlap *)
- (match maybe_range with
- Some(el_name, (start, len)) ->
- (* img and shndx came as a unit, so they're definitely
- * talking about the same file *)
- (* shndx = sym_shndx *)
- section_el_name = el_name
- | None ->
- (* ABS symbols have this property *)
- (match tag with
- SymbolDef(def) ->
- (* don't match section symbols, or we'll be inundated *)
- let sym_shndx = (Nat_big_num.of_string (Uint32.to_string def.def_syment.elf64_st_shndx))
- in
- if not (Nat_big_num.equal sym_shndx shn_abs) || ( not (Nat_big_num.equal (get_elf64_symbol_type def.def_syment) stt_section)) then false
- else (
- let abs_address = (Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_value)
- in
- (* check it against our section *)
- let section_end_addr = (Nat_big_num.add accum_current_addr irec.isec.elf64_section_size)
- in
- ( Nat_big_num.greater_equal abs_address accum_current_addr
- && Nat_big_num.less abs_address section_end_addr)
- (* FIXME: argument that this should be <=, i.e. can mark end addr *)
- (* PROBLEM: this is all very well, but there's no reason why
- * ABS symbols need to point at an address within some output
- * section. They can just be arbitrary values. This is a bit of an
- * abuse if we do it within the C language (to get the value, you
- * have to do "(int) &sym", i.e. create a meaningless pointer
- * intermediate) but arguably is okay in an impl-def way.
- *
- * WHAT to do? well, just always output the ABS symbols, for now.
- *
- * The example that provoked this is in glibc's
- * locale/lc-address.c, which compiles down to create
- * the following ABS symbol:
- *
- * 0000000000000001 g *ABS* 0000000000000000 _nl_current_LC_ADDRESS_used
- *
- * ... i.e. the _nl_current_LC_ADDRESS_used appears to be just a flag.
- *
- * Where can we handle this? We don't see ABS symbols since they
- * aren't associated with sections. We simply need to copy over
- * all the ABS symbols appearing in included input objects.
- * That means there's no point doing anything with them here
- * while we're fiddling with sections. Do it later in a whole-
- * -image pass.
- *)
- && false (* ... at least until we see a better way *)
- )
- | _ -> false
- )
- )
- ))
- in
- let ranges_and_tags = (let x2 =
- ([]) in List.fold_right
- (fun(maybe_range, tag) x2 ->
- if range_or_sym_is_in_this_sec maybe_range tag then
- (maybe_range, tag) :: x2 else x2) (Pset.elements irec.img.by_range)
- x2)
- in
- let included_defs = (let x2 =
- ([]) in List.fold_right
- (fun(maybe_range, def) x2 ->
- if range_or_sym_is_in_this_sec maybe_range (SymbolDef (def)) then
- def :: x2 else x2)
- (elf_memory_image_defined_symbols_and_ranges irec.img) x2)
- in
- let included_global_defs = (let x2 =
- ([]) in List.fold_right
- (fun def x2 ->
- if not
- (Nat_big_num.equal
- (
- (* filter out locals *) get_elf64_symbol_binding def.def_syment)
- stb_local) then def :: x2 else x2) included_defs x2)
- in
- (* What symbol defs are being included? *)
- (* For each global symbol defined in the section, output a line. *)
- (*let _ = Missing_pervasives.outs (List.foldl (^) "" (
- List.map (fun def -> (make_line ""
- (hex_string_of_natural (comp_addr + (natural_of_elf64_addr def.def_syment.elf64_st_value)))
- (hex_string_of_natural (natural_of_elf64_xword def.def_syment.elf64_st_size))
- (" " ^ def.def_symname)) ^ "\n"
- ) included_global_defs
- ))
- in*)
- let (new_ranges_and_tags : (( element_range option) * ( any_abi_feature range_tag)) Pset.set)
- = (Lem_set.setMapMaybe
- (instance_Basic_classes_SetType_tup2_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)))
- instance_Basic_classes_SetType_var_dict) (instance_Basic_classes_SetType_tup2_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)))
- instance_Basic_classes_SetType_var_dict) (fun (maybe_range, tag) ->
- (* How do we update existing metadata? In general,
- * we get a new range. *)
- let new_range = ((match maybe_range with
- None -> None
- | Some(el_name, (start, len)) ->
- Some(secname1,
-( (* FIXME: pass this through a section-to-element gensym.
- We can just (for now) define output element names
- to equal the section names, since we have no unnamed
- output sections and no output common symbols. *)let new_start_off = (Nat_big_num.add start ( Nat_big_num.sub_nat comp_addr output_section_start_addr))
- in
- (*let _ = errln ("Calculated element offset 0x" ^ (hex_string_of_natural new_start_off) ^
- " in element " ^ secname ^ " for tag at address 0x" ^ (hex_string_of_natural accum_current_addr) ^
- " , start offset 0x" ^ (hex_string_of_natural start) ^ ", output section start addr 0x" ^
- (hex_string_of_natural output_section_start_addr) ^ ", comp_addr 0x" ^ (hex_string_of_natural comp_addr))
- in*)
- (new_start_off,
- len)))
- ))
- in
- (match tag with
- (* If it's a section, we discard it.
- * We will add a new section record at the end. (FIXME) *)
- | FileFeature(ElfSection(idx1, isec1)) -> None
- (* If it's a symbol def, we propagate it.
- * We record its linkable idx, so we can
- * match it later with the bindings we formed
- * earlier.
- * FIXME: this is a bit nasty. Perhaps we
- * should replace syment with a minimal structure
- * that avoids duplication. Same for isecs. *)
- | SymbolDef(def) ->
- (* if get_elf64_symbol_type def.def_syment = stt_section
- then Nothing FIXME: also re-create the section symbol when we create the ElfSection
- else *) (* This doesn't work -- some refs might be bound to this symbol.
- Instead, strip the symbol when we generate the output symtab (FIXME). *)
- (*let _ = errln ("Copying symbol named `" ^ def.def_symname ^ "'")
- in*)
- Some(new_range, SymbolDef({
- def_symname = (def.def_symname)
- ; def_syment = (def.def_syment)
- ; def_sym_scn = (def.def_sym_scn)
- ; def_sym_idx = (def.def_sym_idx)
- ; def_linkable_idx = (irec.idx)
- }))
- | AbiFeature(x) -> Some(new_range, AbiFeature(x))
- (* If it's a symbol ref with no reloc site, we discard it? *)
- | SymbolRef(r) ->
- (*let _ = if r.ref.ref_symname = "_start" then errln ("Saw ref to _start, "
- ^ "in section " ^ irec.isec.elf64_section_name_as_string ^ " of linkable " ^ (show irec.idx))
- else ()
- in*)
- let get_binding_for_ref = (fun symref -> (fun linkable_idx -> (fun fname1 ->
- let name_matches1 = ((match Pmap.lookup symref.ref_symname bindings_by_name with Some x -> x | None -> [] ))
- in
- (match List.filter (fun (bi, ((r_idx, r, r_item), m_d)) -> Nat_big_num.equal r_idx linkable_idx && (r = symref)) name_matches1 with
- [(b_idx, b)] -> (b_idx, b)
- | [] -> failwith "no binding found"
- | _ -> failwith ("ambiguous binding found for symbol `" ^ (symref.ref_symname ^ ("' in file " ^ fname1)))
- )
- )))
- in
- let (bi, b) = (get_binding_for_ref r.ref irec.idx irec.fname)
- in
- let ((ref_idx, ref1, ref_linkable), maybe_def) = b
- in
- (match r.maybe_reloc with
- None -> None
- (* If it's a reloc site, we need to somehow point it
- * at the *definition* that it was bound to. YES.
- * reloc_sites are
-
- type reloc_site = <|
- ref_relent : elf64_relocation_a
- ; ref_rel_scn : natural --the relocation section idx
- ; ref_rel_idx : natural --the index of the relocation rec
- ; ref_src_scn : natural --the section *from which* the reference logically comes
- |>
-
- type elfNN_relocation_a =
- <| elfNN_ra_offset : elf32_addr --Address at which to relocate
- ; elfNN_ra_info : elf32_word --Symbol table index/type of relocation to apply
- ; elfNN_ra_addend : elf32_sword --Addend used to compute value to be stored
- |>
-
- * ... of which ref_src_scn, ref_rel_idx,
- * ref_rel_scn and elfNN_ra_offset can be ignored.
- *
- * What *is* important is that we somehow point at
- * the symbol definition (or perhaps *un*definition,
- * if we're generating a shared library) that it
- * refers to.
- *
- * For that, we update ra_info use the 1 + binding_idx,
- * i.e. consider that there is a fresh symbol table
- * and that it has a distinct entry for each binding.
- *
- * FIXME: we also need to account for
- * reloc decisions -- MakePIC etc.
- *)
- | Some(rs) -> Some(new_range, SymbolRef(
- { ref = ({
- (* This is not the place to be fixing up
- * symbol references. We can't yet patch the element content,
- * because we haven't yet decided on the address of everything.
- *
- * That said, we *do* need to represent the old ref in the new
- * linked-image context. That's *all* we should be doing, right now.
- *
- *)
- ref_symname = (ref1.ref_symname)
- ; ref_syment =
- ({ elf64_st_name = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (* unused *)
- ; elf64_st_info = (ref1.ref_syment.elf64_st_info)
- ; elf64_st_other = (ref1.ref_syment.elf64_st_other)
- ; elf64_st_shndx = (Uint32.of_string (Nat_big_num.to_string (Nat_big_num.of_int (* shn_abs *)0)))
- ; elf64_st_value = (Uint64.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0)))
- ; elf64_st_size = (Uint64.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0)))
- })
- ; ref_sym_scn =(Nat_big_num.of_int 0)
- ; ref_sym_idx =(Nat_big_num.of_int 0)
- (* match maybe_def with Just _ -> 1+bi | Nothing -> 0 end *)
- })
- ; maybe_reloc = (Some {
- ref_relent = ({
- elf64_ra_offset = (Uint64.of_string (Nat_big_num.to_string (Nat_big_num.of_int 0))) (* ignored *)
- ; elf64_ra_info = (Uint64.logor
- (* HACK: use bi as the symbol index. *)
- (Uint64.of_string (Nat_big_num.to_string (get_elf64_relocation_a_type rs.ref_relent)))
- (Uint64.shift_left
- (* ... actually, don't, now we have maybe_def_bound_to *)
- (Uint64.of_string (Nat_big_num.to_string (Nat_big_num.of_int (* (1+bi) *)0)))( 32)
- )
- )
- ; elf64_ra_addend = (rs.ref_relent.elf64_ra_addend)
- })
- ; ref_rel_scn =(Nat_big_num.of_int 0)
- ; ref_rel_idx =(Nat_big_num.of_int 0)
- ; ref_src_scn =(Nat_big_num.of_int 0)
- })
- ; maybe_def_bound_to =
-(
- (* Re-search the bindings list for a match, because we might have
- * re-bound this symbol since we created the image. FIXME: since
- * we do this, is there anything gained from populating this field
- * earlier? Probably best not to. *)let (possible_bindings : (Nat_big_num.num * binding) list)
- = ((match Pmap.lookup ref1.ref_symname bindings_by_name with
- Some l -> if ref1.ref_symname = "__fini_array_end" then
- (*let _ = errln ("Found " ^ (show (length l)) ^ " bindings for __fini_array_end, of which " ^
- (show (length (List.filter (fun (bi, (r, maybe_d)) -> maybe_d <> Nothing) l))) ^
- " are with definition")
- in*) l
- else l
- | None -> []
- ))
- in
- (* what's the actual binding? *)
- (match r.maybe_def_bound_to with
- None -> failwith ("at this stage, all references must have a decision: `" ^ (ref1.ref_symname ^ "'"))
- | Some(decision, _) ->
- (* Search the list of bindings for a possibly-updated
- * binding for this reference. *)
- let matching_possibles = (List.filter (fun (bi, ((ref_idx, ref1, ref_item), maybe_d)) ->
- (match maybe_d with
- None -> false
- | Some (def_idx, def, def_item) -> Nat_big_num.equal
- (* match the *reference*, whose linkable we're processing now *)
- irec.idx ref_idx
- && (Nat_big_num.equal r.ref.ref_sym_scn ref1.ref_sym_scn
- && Nat_big_num.equal r.ref.ref_sym_idx ref1.ref_sym_idx)
-
- (*
- def.def_syment = sd.def_syment
- && def.def_sym_scn = sd.def_sym_scn
- && def.def_sym_idx = sd.def_sym_idx
- && def_idx = sd.def_linkable_idx *)
- )
- ) possible_bindings)
- in
- (*let _ = errln ("For a ref to `" ^ ref.ref_symname ^
- "', possibles list is: " ^ (
- List.foldl (fun x -> fun y -> x ^ ", " ^ y) "" (List.map (fun (bi, ((_, _, _), maybe_d)) ->
- match maybe_d with
- Just(def_idx, def, def_item) ->
- "`" ^ def.def_symname ^ "' " ^
- "in linkable " ^ (show def_idx) ^
- ", section " ^ (show def.def_sym_scn) ^
- ", sym idx " ^ (show def.def_sym_idx)
- | _ -> failwith "impossible: just filtered out no-def bindings"
- end
- ) matching_possibles)
- ))
- in*)
- let new_bound_to = ((match matching_possibles with
- [] -> Some(ApplyReloc, None)
- | [(bi, ((rl, r, ri), maybe_d))] ->
- Some(decision,
- (match maybe_d with
- Some (def_idx, def, def_item) -> Some {
- def_symname = (def.def_symname)
- ; def_syment = (def.def_syment)
- ; def_sym_scn = (def.def_sym_scn)
- ; def_sym_idx = (def.def_sym_idx)
- ; def_linkable_idx = def_idx
- }
- | None -> None
- ))
- | _ -> failwith ("After linker script, ambiguous bindings for `" ^ (ref1.ref_symname ^ "'"))
- ))
- in
- if not ((Lem.option_equal (Lem.pair_equal (=) (Lem.option_equal (=))) new_bound_to r.maybe_def_bound_to)) then
- (*let _ = errln ("Changed binding for reference to `" ^ ref.ref_symname ^
- "' in linkable " ^ (show irec.idx))
- in*)
- new_bound_to
- else if (Lem.option_equal (Lem.pair_equal (=) (Lem.option_equal (=))) new_bound_to None) then failwith "really need a decision by now"
- else new_bound_to
- ))
-
- (* if irec.fname = "libc.a(__uClibc_main.os)"
- && irec.isec.elf64_section_name_as_string = ".data.rel.local"
- then
- let _ = errln ("Saw the bugger: " ^ (match r.maybe_def_bound_to with
- Just(decision, Just(sd)) -> show sd.def_syment
- | _ -> "(not complete)"
- end))
- in r.maybe_def_bound_to
- else r.maybe_def_bound_to
- *)
- }
- ))
- ) (* match maybe_reloc *)
- ) (* match tag *)
- ) ((Pset.from_list (pairCompare (maybeCompare (pairCompare compare (pairCompare Nat_big_num.compare Nat_big_num.compare))) compare) ranges_and_tags))) (* end mapMaybe fn *)
- in
- let isec_sz = (irec.isec.elf64_section_size) in
- let maybe_el_sz = (el.length1) in
- let contents_sz = (length el.contents) in
- let (actual_sz, padded_contents) =
- ((match maybe_el_sz with
- Some el_sz ->
- let diff = (Nat_big_num.sub_nat el_sz contents_sz) in
- if Nat_big_num.less diff(Nat_big_num.of_int 0) then
- (* contents greater than what the el says, so chop the end off *)
- (*let _ = Missing_pervasives.errln ("Warning: size mismatch for section " ^ irec.isec.elf64_section_name_as_string ^
- " from " ^ irec.fname)
- in*)
- (el_sz, take0 el_sz el.contents)
- else (el_sz, List.rev_append (List.rev el.contents) (replicate0 diff None))
- | None ->
- if not (Nat_big_num.equal (length el.contents) isec_sz)
- then failwith "input section size not equal to its content pattern length"
- else (isec_sz, el.contents)
- ))
- in
- (*let _ = errln ("Saw first 20 bytes of section " ^ irec.isec.elf64_section_name_as_string ^
- " from " ^ irec.fname ^ " as " ^ (show (take 20 padded_contents)))
- in*)
- (actual_sz, padded_contents, new_ranges_and_tags)
- | _ -> failwith "impossible: no such element"
- ) (* match Map.lookup idstr img.elements *)
- ) (* match maybe_secname *)
- | IncludeCommonSymbol(retain_pol, fname1, linkable_idx, def, img2) ->
- (*let _ = errln ("Including common symbol called `" ^ def.def_symname ^ "'")
- in*)
- (* We want to get the common symbol as a byte pattern *)
- let sz = (Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_size)
- in
- let content = (Missing_pervasives.replicate0 sz (Some(Char.chr (Nat_big_num.to_int (Nat_big_num.of_int 0)))))
- in
- (*let _ = Missing_pervasives.outln (make_line "COMMON" (hex_string_of_natural comp_addr)
- (hex_string_of_natural sz) fname)
- in*)
- (sz, content,(Pset.from_list (pairCompare (maybeCompare (pairCompare compare (pairCompare Nat_big_num.compare Nat_big_num.compare))) compare) [(Some(secname1, ( Nat_big_num.sub_nat comp_addr output_section_start_addr, sz)), SymbolDef({
- def_symname = (def.def_symname)
- ; def_syment = (def.def_syment)
- ; def_sym_scn = (def.def_sym_scn)
- ; def_sym_idx = (def.def_sym_idx)
- ; def_linkable_idx = linkable_idx
- }))]))
-(* | Hole(AddressExprFn f) ->
- let next_addr = f addr (AllocatedSectionsMap outputs_by_name)
- in
- let n = next_addr - addr
- in
- let content = Missing_pervasives.replicate n Nothing
- in
- let _ = Missing_pervasives.outln (make_line "*fill*" (hex_string_of_natural comp_addr)
- (hex_string_of_natural n)
- "")
- in
- (next_addr - addr, content, {}) *)
- | ProvideSymbol(pol, name1, (size2, info, other)) ->
- (*let _ = errln ("Creating symbol definition named `" ^ name ^ "' in output section `" ^ secname ^ "'")
- in*)
- let symaddr = accum_current_addr (* FIXME: support others *)
- in
- (*let _ = Missing_pervasives.outln (make_line "" (hex_string_of_natural symaddr) "" ("PROVIDE (" ^ name ^ ", .)"))
- in*)
- (Nat_big_num.of_int (* sz *)0, (* comp_el_pat *) [],(Pset.from_list (pairCompare (maybeCompare (pairCompare compare (pairCompare Nat_big_num.compare Nat_big_num.compare))) compare) [(
- Some(secname1, (( Nat_big_num.sub_nat symaddr output_section_start_addr),Nat_big_num.of_int 0)),
- SymbolDef(symbol_def_for_provide_symbol name1 size2 info other control_script_linkable_idx)
- )])
- )
- )) (* match comp_el_pat *)
- in
- (*let _ = errln ("Appending byte pattern to section " ^ secname ^ ", first 20 bytes: " ^
- (show (take 20 comp_el_pat)))
- in*)
- let new_content = (append_to_byte_pattern_at_offset ( Nat_big_num.sub_nat comp_addr output_section_start_addr) accum_pat comp_el_pat)
- in
- let new_addr = (Nat_big_num.add comp_addr sz)
- in
- let new_meta = (Pset.(union) accum_meta this_el_meta)
- in
- (new_content, new_addr, new_meta)
- )) ([], output_section_start_addr,(Pset.from_list (pairCompare (maybeCompare (pairCompare compare (pairCompare Nat_big_num.compare Nat_big_num.compare))) compare) [])) (list_combine comp comp_addrs))
- in
- let concat_sec_el = ({
- Memory_image.startpos = (Some(output_section_start_addr))
- ; Memory_image.length1 = (Some(size2))
- ; Memory_image.contents = concatenated_content
- })
- in
- (*let _ = Missing_pervasives.outln "" in*)
- (* Make a new element in the image, also transferring metadata from input elements
- * as appropriate. *)
- let new_by_range_list =
- ((Some(secname1, (Nat_big_num.of_int 0, size2)), FileFeature(ElfSection(Nat_big_num.of_int (* We don't yet konw where this'll come in the output file, so ... *) (* scn_idx *)0,
- { elf64_section_name =(Nat_big_num.of_int 0) (* ignored *)
- ; elf64_section_type = (output_section_type comp)
- ; elf64_section_flags = (output_section_flags comp)
- ; 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.of_int 0) (* ignored *)
- ; elf64_section_link =(Nat_big_num.of_int 0) (* HMM *)
- ; elf64_section_info =(Nat_big_num.of_int 0) (* HMM *)
- ; elf64_section_align = (alignof_output_section comp)
- ; elf64_section_entsize =(Nat_big_num.of_int 0) (* HMM *)
- ; elf64_section_body = Byte_sequence.empty (* ignored *)
- ; elf64_section_name_as_string = secname1 (* can't rely on this being ignored *)
- }
- ))) :: Pset.elements new_range_tag_pairs)
- in
- (*let _ = errln ("Metadata for new section " ^ secname ^ " consists of " ^ (show (length new_by_range_list)) ^ " tags.")
- in*)
- let new_by_range = (List.fold_left (fun m -> fun (maybe_range, tag) ->
- let new_s = (Pset.add (maybe_range, tag) m)
- in
- (* let _ = errln ("Inserting an element into by_range; before: " ^ (show (Set.size m)) ^ "; after: " ^ (show (Set.size new_s)))
- in *)
- new_s
- ) acc_img.by_range new_by_range_list)
- in
- let new_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)
- in
- let _ =
- (let section_tags_bare = (List.filter (fun (maybe_range, tag) ->
- (match tag with
- | FileFeature(ElfSection(idx1, isec1)) -> true
- | _ -> false
- )) (Pset.elements new_by_range))
- in
- (* errln ("Total metadata now includes " ^ (show (length section_tags_bare)) ^ " sections; are by_range and "
- ^ "by_tag consistent? " ^ (show (new_by_tag = by_tag_from_by_range new_by_range))) *) ())
- in
- (* this expression is the return value of add_output_section *)
- ( Nat_big_num.add
- (* new_pos *) output_section_start_addr size2,
- (* new_acc *) {
- elements = (Pmap.add secname1 concat_sec_el acc_img.elements)
- (* tag it as a section, and transfer any tags *)
- ; by_range = (* let _ = errln ("Returning from add_output_section a by_range with " ^
- (show (Set.size new_by_range))) in *) new_by_range
- ; by_tag = new_by_tag
- },
- (* sec_sz *) size2,
- (* replacement_output_sec *) (OutputSectionSpec (guard, Some(output_section_start_addr), secname1, comp))
- )
- )) (* end add_output_section *)
- in
- (match script1 with
- [] -> (acc, (AllocatedSectionsMap outputs_by_name))
- | (element1, el_idx) :: more_elements_and_idx ->
- let do_nothing = (acc, pos, (AllocatedSectionsMap outputs_by_name)) in
- let (new_acc, new_pos, new_outputs_by_name) =
- ((match element1 with
- DefineSymbol(symdefpol, name1, (symsize, syminfo, symother)) ->
- (* We've already added this to the output composition. *)
- do_nothing
- | AdvanceAddress(AddressExprFn advance_fn_ref) ->
- let advance_fn =
-((match Pmap.lookup advance_fn_ref alloc_map with
- | Some m -> m
- | None -> failwith "alloc_map invariant failure"
- ))
- in
- let new_pos = (advance_fn pos (AllocatedSectionsMap outputs_by_name))
- in
- (acc, new_pos, (AllocatedSectionsMap outputs_by_name))
- (* FIXME: the allocated sections map is the subset of the outputs_by_name map
- * that has been allocated -- meaning *both* sized *and* placed.
- * Since we're a multi-pass interpreter, we've sized everything already, but
- * only a subset has been placed. So we need to weed out all elements from
- * outputs_by_name that don't correspond to a section in the accumulated image.
- * We should probably include the section's range_tag in the allocated_sections_map,
- * which would force us to do this, but at the moment neither of these is done. *)
- | MarkAndAlignDataSegment(maxpagesize1, commonpagesize1) ->
- (* GNU linker manual says:
-
- "DATA_SEGMENT_ALIGN(MAXPAGESIZE, COMMONPAGESIZE)
- is equivalent to either
- (ALIGN(MAXPAGESIZE) + (. & (MAXPAGESIZE - 1)))
- or
- (ALIGN(MAXPAGESIZE) + (. & (MAXPAGESIZE - COMMONPAGESIZE)))
- depending on whether the latter uses fewer COMMONPAGESIZE sized
- pages for the data segment (area between the result of this
- expression and `DATA_SEGMENT_END') than the former or not. If the
- latter form is used, it means COMMONPAGESIZE bytes of runtime
- memory will be saved at the expense of up to COMMONPAGESIZE wasted
- bytes in the on-disk file."
-
- In other words, we're marking the beginning of the data segment
- by aligning our position upwards by an amount that
-
- - guarantees we're on a new page...
-
- - ... but (option 1) at an address that's congruent, modulo the max page size
- (e.g. for 64kB maxpage, 4kB commonpage, we AND with 0xffff)
-
- - ... (option 2) at an offset that's at the commonpagesize boundary
- immediately preceding the lowest congruent address
- (e.g. for 64kB maxpage, 4kB commonpage, we AND with 0xf000,
- so if we're at pos 0x1234, we bump up to 0x11000).
-
- FIXME:
-
- The GNU linker seems to bump up to 0x12000 here, not 0x11000.
- Specifically,
-
- DATA_SEGMENT_ALIGN (0x200000, 0x1000)
-
- bumps 0x4017dc up to 0x602000.
-
- This is indeed better, because it allows the next section
- to be output without a big gap in the file.
-
- LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
- 0x00000000000017dc 0x00000000000017dc R E 200000
- LOAD 0x0000000000002000 0x0000000000602000 0x0000000000602000
- 0x0000000000000120 0x0000000000000ce8 RW 200000
-
- ... whereas if the second LOAD began at address 0x601000,
- the file offset of its first section would have to be 0x11000.
-
- So what *should* the formula be?
- It needs to calculate the next address which
-
- - is a commonpagesize boundary;
-
- - is minimally >= the current address, modulo the commonpagesize
-
- - is minimally >= the current address, modulo the maxpagesize.
-
- The AND operation gives us something that is minimally *below*
- the commonpagesize boundary. I think we need to add COMMONPAGESIZE.
-
- The code does this (in ldexp.c around line 478 as of binutils 2.25):
-
- expld.result.value = align_n (expld.dot, maxpage);
- /* omit relro phase */
- if (expld.dataseg.phase == exp_dataseg_adjust)
- {
- if (commonpage < maxpage)
- expld.result.value += ((expld.dot + commonpage - 1)
- & (maxpage - commonpage));
- }
- else
- {
- expld.result.value += expld.dot & (maxpage - 1);
-
- Which amounts to:
-
- 1. first, align up to maxpage. So for our example, we're now 0x10000.
- or for our real example, we're now 0x600000
-
- THEN since the first phase (expld_dataseg_none)
- hits the final "else" case,
- we immediately restore the modulus of the address,
- giving 0x60188c.
- or 0x6019ac the second time around (FIXME: why two?)
-
- 2. next, on the relevant phase (pass) of the script interpreter,
- i.e. OPTION 2
- if commonpage < maxpage,
- bump up the *non-maxpage-aligned non-modulo-restored* address
- by
- (. + commonpage - 1) & (maxpage - commonpage)
-
- i.e. for our example earlier
- (0x01234 + 0x1000 - 1) & (0xf000)
- =
- 0x02233 & 0xf000
- =
- 0x02000
-
- i.e. for our real example
- (0x4019ac + 0x1000 - 1) & (0x1ff000)
- =
- 0x4019ac + 0x1000 - 1) & 0x1ff000
- =
- 0x002000
-
- 3. OPTION 1 is implemented by the trailing "else {"
- -- it restores the modulus.
-
- So the problem with our original logic (below) was that
- it did what the manual says, not what the code does.
- Specifically, the code for option 2 does
-
- (. + commonpagesize - 1) & (maxpagesize - commonpagesize)
-
- and NOT simply
-
- . & (maxpagesize - commonpagesize).
-
- FIXME: report this bug.
-
-
- Note that intervening commands can do arbitrary things to the location
- counter, so we can't do any short-cut arithmetic based on section sizes;
- we actually have to run the layout procedure til we hit the end of the
- data segment, and then see how we do.
-
- We run this function *forward* with the first option on a subset
- of the script ending with the end of the data segment.
- We then see what comes back.
-
- *)
- (* let num_pages_used *)
- (*let _ = errln ("Option 1 congruence add-in from pos 0x" ^ (hex_string_of_natural pos) ^ ", maxpagesize 0x" ^
- (hex_string_of_natural maxpagesize) ^ " is 0x" ^ (hex_string_of_natural (natural_land pos (maxpagesize - 1))))
- in*)
- let option1 = (Nat_big_num.add (align_up_to maxpagesize1 pos) (Nat_big_num.bitwise_and pos ( Nat_big_num.sub_nat maxpagesize1(Nat_big_num.of_int 1))))
- in
- (*let _ = errln ("Mark/align data segment: option 1 is to bump pos to 0x" ^ (hex_string_of_natural option1))
- in*)
- let option2 = (Nat_big_num.add (align_up_to maxpagesize1 pos) (Nat_big_num.bitwise_and ( Nat_big_num.sub_nat (Nat_big_num.add pos commonpagesize1)(Nat_big_num.of_int 1)) ( Nat_big_num.sub_nat maxpagesize1 commonpagesize1)))
- in
- (*let _ = errln ("Mark/align data segment: option 2 is to bump pos to 0x" ^ (hex_string_of_natural option2))
- in*)
- let data_segment_endpos = (fun startpos1 ->
- (* run forward from here until MarkDataSegmentEnd,
- * accumulating the actually-made outputs by name and their sizes *)
- let (endpos, _) = (List.fold_left (fun (curpos, seen_end) -> fun (new_script_item, new_script_item_idx) ->
- (*let _ = errln ("Folding at pos 0x" ^ (hex_string_of_natural curpos))
- in*)
- if seen_end
- then (curpos, true)
- else let (newpos, new_seen) = ((match new_script_item with
- | MarkDataSegmentEnd ->
- (*let _ = errln "data segment end"
- in*)
- (* break the loop early here *)
- (curpos, true)
- | OutputSection(outputguard, maybe_expr, name1, sub_elements) ->
- (*let _ = errln ("output section " ^ name)
- in*)
- let maybe_found = (Pmap.lookup name1 outputs_by_name)
- in
- let (OutputSectionSpec (guard, addr, secname1, comp), seen_script_el_idx) = ((match maybe_found with
- Some (f, seen_script_el_idx) -> (f, seen_script_el_idx)
- | None -> failwith "internal error: output section not found"
- ))
- in
- (* Sometimes a given output section name, say .eh_frame, can come from multiple
- * script elements with disjoint guard conditions (only_if_ro and only_if_rw, say).
- * Only one of them will actually be selected when the guard is being evaluated.
- * So when we "replay" the sections' output here, we want to skip the ones whose
- * guards were false. The way we implement this is to store the originating script
- * element idx in the allocated_output_sections map. We can test that against our
- * current script element_idx here *)
- let replay_output = ( Nat_big_num.equal seen_script_el_idx el_idx)
- in
- if replay_output
- then (
- let unaligned_start_addr = curpos
- in
- let start_addr = (align_up_to (alignof_output_section comp) unaligned_start_addr)
- in
- let (end_addr, comp_addrs) = (do_output_section_layout_starting_at_addr start_addr (AllocatedSectionsMap outputs_by_name) comp)
- in
- let size2 = (Nat_big_num.sub_nat end_addr start_addr)
- in
- (end_addr, (* seen_end *) false)
- )
- else (curpos, (* seen_end *) false)
- | AdvanceAddress(AddressExprFn advance_fn_ref) ->
- (*let _ = errln "Advance address"
- in*)
- let advance_fn =
-((match Pmap.lookup advance_fn_ref alloc_map with
- | Some m -> m
- | None -> failwith "alloc_map invariant failed"
- ))
- in
- let new_pos = (advance_fn curpos (AllocatedSectionsMap outputs_by_name))
- in
- (new_pos, false)
- | _ -> (curpos, seen_end)
- ))
- in
- if Nat_big_num.less newpos curpos then failwith "went backwards" else (newpos, new_seen)
- ) (startpos1, false) more_elements_and_idx)
- in endpos
- )
- in
- let endpos_option1 = (data_segment_endpos option1)
- in
- let endpos_option2 = (data_segment_endpos option2)
- in
- (*let _ = errln ("Mark/align data segment: option 1 gives an endpos of 0x" ^ (hex_string_of_natural endpos_option1))
- in*)
- (*let _ = errln ("Mark/align data segment: option 2 gives an endpos of 0x" ^ (hex_string_of_natural endpos_option2))
- in*)
- let npages = (fun startpos1 -> (fun endpos -> Nat_big_num.div
- ( Nat_big_num.sub_nat(align_up_to commonpagesize1 endpos)
- (round_down_to commonpagesize1 startpos1)) commonpagesize1
- ))
- in
- let npages_option1 = (npages option1 endpos_option1)
- in
- let npages_option2 = (npages option2 endpos_option1)
- in
- (*let _ = errln ("Mark/align data segment: option 1 uses " ^ (show npages_option1) ^ " COMMONPAGESIZE-sized pages")
- in*)
- (*let _ = errln ("Mark/align data segment: option 2 uses " ^ (show npages_option2) ^ " COMMONPAGESIZE-sized pages")
- in*)
- if Nat_big_num.less npages_option1 npages_option2
- then (*let _ = errln "Choosing option 1" in*) (acc, option1, (AllocatedSectionsMap outputs_by_name))
- else (*let _ = errln "Choosing option 2" in*) (acc, option2, (AllocatedSectionsMap outputs_by_name))
- | MarkDataSegmentEnd -> do_nothing
- | MarkDataSegmentRelroEnd(*(fun_from_secs_to_something)*) -> do_nothing
- | OutputSection(outputguard, maybe_expr, name1, sub_elements) ->
- (* Get the composition we computed earlier, and actually put it in
- * the image, assigning an address to it. *)
- let maybe_found = (Pmap.lookup name1 outputs_by_name)
- in
- let (found, seen_script_el_idx) = ((match maybe_found with
- Some (f, saved_idx) -> (f, saved_idx)
- | None -> failwith "internal error: output section not found"
- ))
- in
- let (OutputSectionSpec (guard, addr, secname1, comp)) = found
- in
- (* let next_free_section_idx = 1 + naturalFromNat (Map.size outputs_by_name)
- in *)
- let count_sections_in_image = (fun img2 -> (
- let (section_tags, section_ranges) = (elf_memory_image_section_ranges img2)
- in
- let section_tags_bare = (Lem_list.map (fun tag ->
- (match tag with
- | FileFeature(ElfSection(idx1, isec1)) -> true
- | _ -> false
- )) section_tags)
- in
- length section_tags_bare
- ))
- in
- (* Do we actually want to add an output section? Skip empty sections.
- * CARE: we actually want to heed the proper ld semantics for empty sections
- * (e.g. ". = ." will force output). From the GNU ld manual:
-
- The linker will not normally create output sections with no contents.
- This is for convenience when referring to input sections that may or
- may not be present in any of the input files. For example:
- .foo : { *(.foo) }
- will only create a `.foo' section in the output file if there is a
- `.foo' section in at least one input file, and if the input sections
- are not all empty. Other link script directives that allocate space in
- an output section will also create the output section. So too will
- assignments to dot even if the assignment does not create space, except
- for `. = 0', `. = . + 0', `. = sym', `. = . + sym' and `. = ALIGN (. !=
- 0, expr, 1)' when `sym' is an absolute symbol of value 0 defined in the
- script. This allows you to force output of an empty section with `. =
- .'.
-
- The linker will ignore address assignments ( *note Output Section
- Address::) on discarded output sections, except when the linker script
- defines symbols in the output section. In that case the linker will
- obey the address assignments, possibly advancing dot even though the
- section is discarded.
-
- * It follows that we might discard the output section,
- * but *retain* the symbol definitions within it,
- * and keep the dot-advancements that
- * In other words, we care about two things:
- *
- * -- whether there are any non-empty input sections, *or*
- * non-excluded assignments to dot, inside the composition:
- * this controls whether the section is output
-
- * -- whether the script defines symbols in the section; if so
- * then *even if the section is discarded*
- * we must honour the address assignments,
- * which means using the ending address of do_output_section_layout_starting_at_addr,
- * *and*
- * we must retain the symbol definitions (which now could
- * end up going in some other section? HMM...)
- *)
- let comp_element_allocates_space = (fun comp_el -> (match comp_el with
- IncludeInputSection(_, irec) -> Nat_big_num.greater
- (*let _ = errln ("Saw an input section named `" ^ irec.isec.elf64_section_name_as_string ^
- "' of size " ^ (show irec.isec.elf64_section_size))
- in*)
- irec.isec.elf64_section_size(Nat_big_num.of_int 0)
- | IncludeCommonSymbol(retain_pol, fname1, idx1, def, img2) -> Nat_big_num.greater
-(Ml_bindings.nat_big_num_of_uint64 def.def_syment.elf64_st_size)(Nat_big_num.of_int 0)
- | ProvideSymbol(pol, name1, spec) -> true (* HACK: what else makes sense here? *)
- | Hole(AddressExprFn(address_fn_ref)) ->
- let address_fn =
-((match Pmap.lookup address_fn_ref alloc_map with
- | Some m -> m
- | None -> failwith "alloc_map invariant failed"
- ))
- in
- let assignment_is_excluded = (fun f ->
- (* really makes you wish you were programming in Lisp *)
- let always_gives_0 =
- ( Nat_big_num.equal(f(Nat_big_num.of_int 0) (AllocatedSectionsMap outputs_by_name))(Nat_big_num.of_int 0)
- && Nat_big_num.equal (f(Nat_big_num.of_int 42) (AllocatedSectionsMap outputs_by_name))(Nat_big_num.of_int 0)) (* FIXME: this is wrong *)
- in
- let always_gives_dot =
- ( Nat_big_num.equal(f(Nat_big_num.of_int 0) (AllocatedSectionsMap outputs_by_name))(Nat_big_num.of_int 0)
- && Nat_big_num.equal (f(Nat_big_num.of_int 42) (AllocatedSectionsMap outputs_by_name))(Nat_big_num.of_int 42)) (* FIXME: this is wrong *)
- in
- (* FIXME: what are the semantics of function equality in Lem? *)
- always_gives_0 || (always_gives_dot (*&& (AddressExprFn(f)) <> assign_dot_to_itself*) (* FIXME DPM: almost certainly not what is meant... *)))
- in
- not (assignment_is_excluded address_fn)
- ))
- in
- let section_contains_non_empty_inputs =
-(List.exists comp_element_allocates_space comp)
- in
- (* See note in MarkDataSegmentEnd case about script element idx. Short version:
- * multiple output section stanzas, for a given section name, may be in the script,
- * but only one was activated by the section composition pass. Ignore the others. *)
- let do_output = (( Nat_big_num.equal seen_script_el_idx el_idx) && section_contains_non_empty_inputs)
- in
- if not do_output then
- (*let _ = errln ("At pos 0x" ^ (hex_string_of_natural pos) ^ ", skipping output section " ^ name ^
- " because " ^ (if not section_contains_non_empty_inputs
- then "it contains no non-empty inputs"
- else "it was excluded by its output guard"))
- in*)
- (acc, pos, (AllocatedSectionsMap outputs_by_name))
- else (
- (* let _ = errln ("Before adding output section, we have " ^ (show (count_sections_in_image acc))
- ^ " sections.")
- in *)
- let (new_pos, new_acc, sec_sz, replacement_output_sec)
- = (add_output_section ((* next_free_section_idx, *) pos, acc) found)
- in
- (*let _ = errln ("At pos 0x" ^ (hex_string_of_natural pos) ^ ", adding output section " ^ name ^
- " composed of " ^ (show (length comp)) ^ " items, new pos is 0x" ^ (hex_string_of_natural new_pos))
- in*)
- (* let _ = errln ("Received from add_output_section a by_range with " ^ (show (Set.size new_acc.by_range))
- ^ " metadata records of which " ^ (show (Set.size {
- (r, t)
- | forall ((r, t) IN new_acc.by_range)
- | match t with FileFeature(ElfSection(x)) -> true | _ -> false end
- }
- )) ^ " are ELF sections; one more time: " ^ (show (Set.size {
- (t, r)
- | forall ((t, r) IN new_acc.by_tag)
- | match t with FileFeature(ElfSection(x)) -> true | _ -> false end
- }
- )) ^ "; count_sections_in_image says " ^ (show (
- length (Multimap.lookupBy Memory_image_orderings.tagEquiv (FileFeature(ElfSection(0, null_elf64_interpreted_section))) new_acc.by_tag)
- ))
- )
- in *)
- (* let _ = errln ("After adding output section, we have " ^ (show (count_sections_in_image new_acc))
- ^ " sections.")
- in *)
- (new_acc, new_pos, (AllocatedSectionsMap (Pmap.add name1 (replacement_output_sec, el_idx) (Pmap.remove name1 outputs_by_name))))
- )
- | DiscardInput(selector) -> do_nothing
- | InputQuery(retainpol, sortpol, selector) -> do_nothing
- ))
- in
- (* recurse *)
- build_image alloc_map new_acc new_pos new_outputs_by_name bindings_by_name more_elements_and_idx control_script_linkable_idx linker_defs_by_name
- ))
-
-(*
-let rec consecutive_commons rev_acc l =
- match l with
- [] -> reverse rev_acc
- | IncludeCommonSymbol(pol, fname, def, img) :: rest ->
- consecutive_commons ((pol, fname, def, img) :: rev_acc) rest
- | _ -> reverse rev_acc
-end
-*)
-
-(*val default_place_orphans : input_output_assignment -> list input_spec -> input_output_assignment*)
-let default_place_orphans (discards, outputs) inputs:(input_spec)list*(output_section_spec*Nat_big_num.num)list=
-(
- (* Try to emulate the GNU linker.
- * Its docs say:
-
- "It attempts to place orphan sections after
- non-orphan sections of the same attribute, such as code vs data,
- loadable vs non-loadable, etc. If there is not enough room to do this
- then it places at the end of the file.
-
-
- For ELF targets, the attribute of the section includes section type
- as well as section flag."
-
- * It places the .tm_clone_table orphan
-
- [ 9] .tm_clone_table PROGBITS 0000000000000000 00000160
- 0000000000000000 0000000000000000 WA 0 0 8
-
- as
-
- .data 0x0000000000602120 0x0 crtend.o
- .data 0x0000000000602120 0x0 crtn.o
-
- .tm_clone_table
- 0x0000000000602120 0x0
- .tm_clone_table
- 0x0000000000602120 0x0 crtbeginT.o
- .tm_clone_table
- 0x0000000000602120 0x0 crtend.o
-
- .data1
- *(.data1)
- 0x0000000000602120 _edata = .
-
- i.e. between .data and .data1. In the script:
-
- .got.plt : { *(.got.plt) *(.igot.plt) }
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.* )
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- _edata = .; PROVIDE (edata = .);
- . = .;
- __bss_start = .;
-
- i.e. no clear reason for why between .data and .data1. In the code:
-
- (see elf32em.c line 1787 in binutils 2.25)
-
- ... the key bit of code is as follows.
-
- place = NULL;
- if ((s->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
- place = &hold[orphan_nonalloc];
- else if ((s->flags & SEC_ALLOC) == 0)
- ;
- else if ((s->flags & SEC_LOAD) != 0
- && ((iself && sh_type == SHT_NOTE)
- || (!iself && CONST_STRNEQ (secname, ".note"))))
- place = &hold[orphan_interp];
- else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) == 0)
- place = &hold[orphan_bss];
- else if ((s->flags & SEC_SMALL_DATA) != 0)
- place = &hold[orphan_sdata];
- else if ((s->flags & SEC_THREAD_LOCAL) != 0)
- place = &hold[orphan_tdata];
- else if ((s->flags & SEC_READONLY) == 0)
- place = &hold[orphan_data];
- else if (((iself && (sh_type == SHT_RELA || sh_type == SHT_REL))
- || (!iself && CONST_STRNEQ (secname, ".rel")))
- && (s->flags & SEC_LOAD) != 0)
- place = &hold[orphan_rel];
- else if ((s->flags & SEC_CODE) == 0)
- place = &hold[orphan_rodata];
- else
- place = &hold[orphan_text];
-
-
- .. we replicate it here.
- *)let output_irecs = (List.fold_left (fun acc -> fun outp -> ((match outp with
- (OutputSectionSpec(guard, maybe_addr, name1, comp), script_el_idx) ->
- let all_irecs = (List.fold_left (fun inner_acc -> fun comp_el -> (match comp_el with
- IncludeInputSection(_, irec) -> Pset.add irec inner_acc
- | _ -> inner_acc
- ))(Pset.from_list compare []) comp)
- in
- Pset.(union) all_irecs acc
- | _ -> acc
- )))(Pset.from_list compare []) outputs)
- in
- let (orphans : input_spec list) = (List.filter (fun inp -> (match inp with
- InputSection(irec) -> let v = (not ( Pset.mem irec output_irecs))
- in (*let _ = if v then errln ("Saw an orphan input section: " ^
- irec.secname ^ " in " ^ irec.fname) else ()
- in*) v
- | _ -> false
- )) inputs)
- in
- let place_one_orphan = (fun acc -> fun input -> (
- let irec = ((match input with
- InputSection(irec) -> irec
- | _ -> failwith "impossible: orphan section is not a section"
- ))
- in
- let (discards, outputs) = acc in
- let find_output = (fun maybe_name -> fun maybe_type -> fun flags_must_have -> fun flags_must_not_have -> (
- Missing_pervasives.find_index0 (fun (OutputSectionSpec (guard, maybe_addr, name1, comp), script_el_idx) ->
- let flags = (output_section_flags comp) in
- (match maybe_name with Some n -> n = name1 | None -> true )
- && ((match maybe_type with Some t -> Nat_big_num.equal (output_section_type comp) t | None -> true )
- && (Pset.for_all (fun x -> flag_is_set x flags) flags_must_have
- && Pset.for_all (fun x -> not (flag_is_set x flags)) flags_must_not_have))
- ) outputs
- ))
- in
- let place_after_nonalloc = (find_output None None(Pset.from_list Nat_big_num.compare [])(Pset.from_list Nat_big_num.compare [ shf_alloc ])) in
- let place_after_interp = (find_output (Some(".interp")) (Some(sht_progbits))(Pset.from_list Nat_big_num.compare [ shf_alloc ])(Pset.from_list Nat_big_num.compare [])) in
- let place_after_bss = (find_output (Some(".bss")) (Some(sht_nobits))(Pset.from_list Nat_big_num.compare [ shf_alloc; shf_write])(Pset.from_list Nat_big_num.compare [])) in
- let place_after_rodata = (find_output (Some(".rodata")) (Some(sht_progbits))(Pset.from_list Nat_big_num.compare [ shf_alloc ])(Pset.from_list Nat_big_num.compare [ shf_write ])) in
- let place_after_rel = (find_output (Some(".rela.dyn")) (Some(sht_rela))(Pset.from_list Nat_big_num.compare [])(Pset.from_list Nat_big_num.compare [])) in
- let place_after_data = (find_output (Some(".data")) (Some(sht_progbits))(Pset.from_list Nat_big_num.compare [ shf_alloc; shf_write ])(Pset.from_list Nat_big_num.compare [])) in
- let place_after_text = (find_output (Some(".text")) (Some(sht_progbits))(Pset.from_list Nat_big_num.compare [ shf_alloc; shf_execinstr ])(Pset.from_list Nat_big_num.compare [])) in
- let (place_after : Nat_big_num.num option) = ((match input with
- InputSection(irec) ->
- (* HACK: simulates GNU linker, but this logic ought to go elsewhere *)
- if irec.isec.elf64_section_name_as_string = ".note.GNU-stack" then None
- else
- if not (flag_is_set shf_alloc irec.isec.elf64_section_flags)
- && (* not flag_is_set shf_alloc irec.isec.elf64_section_flags *) (* no debugging, for now *) true
- then place_after_nonalloc
- else (* FIXME: reinstate alloc-debugging case *)
- if Nat_big_num.equal irec.isec.elf64_section_type sht_note (* FIXME: replicate iself logic *)
- || (irec.isec.elf64_section_name_as_string = ".note")
- then place_after_interp
- else if Nat_big_num.equal irec.isec.elf64_section_type sht_nobits
- then place_after_bss
- else (* FIXME: implement thread-local case *)
- if not (flag_is_set shf_write irec.isec.elf64_section_flags)
- && not (flag_is_set shf_execinstr irec.isec.elf64_section_flags)
- then place_after_rodata
- else if flag_is_set shf_write irec.isec.elf64_section_flags
- && not (flag_is_set shf_execinstr irec.isec.elf64_section_flags)
- then place_after_data
- else place_after_text
- ))
- in
- let (discards, outputs) = acc in
- (match place_after with
- Some idx1 -> (* The section exists and has the flags we expected, and is at output idx *)
- (discards, mapi (fun i -> fun output ->
- (* FIXME: also fix up flags, alignment etc. *)
- let (OutputSectionSpec (guard, maybe_addr, name1, comp), script_el_idx) = output in
- if Nat_big_num.equal (Nat_big_num.of_int i) idx1 then (OutputSectionSpec(guard, maybe_addr, name1, List.rev_append (List.rev comp) [IncludeInputSection(DefaultKeep, irec)]), script_el_idx) else output
- ) outputs
- )
- | None ->
- (*let _ = errln ("Warning: discarding orphan section `" ^ irec.isec.elf64_section_name_as_string
- ^ "' from file `" ^ irec.fname ^ "'")
- in*)
- ( List.rev_append (List.rev discards) [input], outputs)
- )
- ))
- in
- List.fold_left place_one_orphan (discards, outputs) orphans)
-
-(*val interpret_linker_control_script :
- address_expr_fn_map allocated_sections_map ->
- linker_control_script
- -> linkable_list
- -> natural (* control_script_linkable_idx *)
- -> abi any_abi_feature
- -> list input_spec
- -> (input_spec -> input_spec -> ordering) (* seen ordering *)
- -> (input_output_assignment -> list input_spec -> input_output_assignment) (* place orphans *)
- -> (Map.map string (list (natural * binding))) (* initial_bindings_by_name *)
- -> (elf_memory_image * Map.map string (list (natural * binding)))*)
-let interpret_linker_control_script alloc_map script1 linkables control_script_linkable_idx a inputs seen_ordering place_orphans initial_bindings_by_name:(any_abi_feature)annotated_memory_image*((string),((Nat_big_num.num*binding)list))Pmap.map=
- (let labelled_script = (label_script script1)
- in
- (*let _ = List.mapi (fun i -> fun input ->
- errln ("Input " ^ (show i) ^ " is " ^
- match input with
- InputSection(inp) ->
- "input section, name `" ^ inp.secname ^
- "', from file `" ^ inp.fname ^ "' (linkable idx " ^ (show inp.idx) ^ ")"
- | Common(idx, symname, img, def) ->
- "common symbol `" ^ symname ^ "'"
- end
- )
- ) inputs
- in*)
- let (discards_before_orphans, outputs_before_orphans)
- = (assign_inputs_to_output_sections ([], [])(Pset.from_list (pairCompare Nat_big_num.compare Nat_big_num.compare) [])(Pset.from_list (tripleCompare Nat_big_num.compare Nat_big_num.compare Nat_big_num.compare) []) inputs None None seen_ordering labelled_script)
- in
- (* place orphans *)
- let (discards, outputs) = (place_orphans (discards_before_orphans, outputs_before_orphans) inputs)
- in
- (* In assigning inputs to outputs, we may also have defined some symbols. These affect the
- * bindings that are formed. So, we rewrite the bindings here. Note that we have to do so here,
- * not in the caller, because these extra bindings can affect the reachability calculation
- * during GC. *)
- let (linker_defs_by_name, (bindings_by_name : ( (string, ( (Nat_big_num.num * binding)list))Pmap.map))) = (
- let (script_defs_by_name : (string, ( (symbol_definition * symbol_def_policy)list)) Pmap.map)
- = (List.fold_left (fun acc -> (fun ((OutputSectionSpec (guard, maybe_addr, secname1, comp)), script_el_idx) ->
- List.fold_left (fun inner_acc -> fun comp_el -> (
- (match comp_el with
- ProvideSymbol(pol, name1, (size2, info, other)) ->
- (*let _ = errln ("Linker script defining symbol `" ^ name ^ "'")
- in*)
- let def = (symbol_def_for_provide_symbol name1 size2 info other control_script_linkable_idx)
- in
- let v = ((match Pmap.lookup name1 inner_acc with
- None -> [(def, pol)]
- | Some l -> (def, pol) :: l
- ))
- in
- Pmap.add name1 v inner_acc
- | _ -> inner_acc
- )
- )) (acc : (string, ( (symbol_definition * symbol_def_policy)list)) Pmap.map) comp
- )) (Pmap.empty compare) outputs)
- in
- (* Now that we've made these definitions, what bindings are affected?
- * We also use this opportunity to bind references to linker-generated symbols,
- * such as _GLOBAL_OFFSET_TABLE_, since any definitions of these should now be merged
- * into our inputs. *)
- (* bit of a HACK: reconstruct the linkable img and idx from the input items *)
- let idx_to_img = (List.fold_left (fun acc_m -> fun item ->
- (match item with
- Common(idx1, _, img2, symdef) -> Pmap.add idx1 img2 (Pmap.remove idx1 acc_m)
- | InputSection(irec) -> Pmap.add irec.idx irec.img (Pmap.remove irec.idx acc_m)
- )
- ) (Pmap.empty Nat_big_num.compare) inputs)
- in
- let (lowest_idx : Nat_big_num.num) = ((match Pset.min_elt_opt (Pmap.domain idx_to_img)
- with Some x -> x
- | None -> failwith "internal error: no linkable items"
- ))
- in
- let first_linkable_item = ((match linkables with x :: more -> x | _ -> failwith "internal error: no linkables" ))
- in
- let (control_script_input_item : input_item) = (
- "(built-in control script)",
- ControlScript,
- (BuiltinControlScript, [Builtin])
- )
- in
- let (control_script_linkable_item : linkable_item) = (
- ControlScriptDefs, control_script_input_item,
- { item_fmt = ""
- ; item_check_sections = false
- ; item_copy_dt_needed = false
- ; item_force_output = true
- }
- )
- in
- let updated_bindings_and_new_defs = (Pmap.map (fun b_list_initial ->
- Lem_list.map (fun (b_idx, b_initial) ->
- let ((iref_idx, iref, iref_item), maybe_idef) = b_initial
- in
- (*let _ = errln ("Looking for linker script or linker-generated defs of symbol `" ^ iref.ref_symname ^ "'")
- in*)
- let possible_script_defs = ((match Pmap.lookup iref.ref_symname script_defs_by_name with
- Some l -> l
- | None -> []
- ))
- in
- let (possible_linker_generated_def : symbol_definition option) =
- (if a.symbol_is_generated_by_linker iref.ref_symname
- then (* can we find a definition by this name? *)
- ((match Pmap.lookup lowest_idx idx_to_img with
- None -> failwith "no lowest idx found"
- | Some img2 ->
- (match List.filter (fun def -> def.def_symname = iref.ref_symname) (defined_symbols
- instance_Basic_classes_Ord_Abis_any_abi_feature_dict instance_Abi_classes_AbiFeatureTagEquiv_Abis_any_abi_feature_dict img2) with
- [] -> None
- | [def] -> Some(def)
- | _ -> failwith ("first linkable has multiple defs of name `" ^ (iref.ref_symname ^ "'"))
- )
- ))
- else None)
- in
- (* If the binding has no def, we always use the def we have.
- * If the binding has a def, we use our def only if the policy is AlwaysDefine. *)
- (*let _ = errs ("Do we override binding " ^ (show b_idx) ^ ", symbol named `" ^
- iref.ref_symname ^ "'? ")
- in*)
- (* FIXME: check real semantics of defining symbols like '_GLOBAL_OFFSET_TABLE_' in linker script or input objects.
- * This is really just a guess. *)
- let new_b_and_maybe_new_def = ((match (maybe_idef, possible_script_defs, possible_linker_generated_def) with
- | (_, [], None) -> (*let _ = errln "no" in *)
- (((iref_idx, iref, iref_item), maybe_idef), None)
- | (None, [], Some(def)) -> (*let _ = errln "yes (was undefined)" in*)
- (((iref_idx, iref, iref_item), Some(lowest_idx, def, first_linkable_item)), Some(def))
- | (_, [(def, AlwaysDefine)], _) -> (*let _ = errln "yes (linker script provides unconditional def)" in*)
- (((iref_idx, iref, iref_item), Some (control_script_linkable_idx, def, control_script_linkable_item)), Some(def))
- | (Some existing_def, ([(def, ProvideIfUsed)]), _) -> (*let _ = errln "no" in*)
- (((iref_idx, iref, iref_item), Some existing_def), None)
- | (None, [(def, ProvideIfUsed)], _) -> (*let _ = errln "yes (linker script provides if-used def)" in*)
- (((iref_idx, iref, iref_item), Some (control_script_linkable_idx, def, control_script_linkable_item)), Some(def))
- | (_, pair1 :: pair2 :: more, _) -> (*let _ = errln "error" in*)
- failwith "ambiguous symbol binding in linker control script"
- ))
- in
- (b_idx, new_b_and_maybe_new_def)
- ) b_list_initial
- ) initial_bindings_by_name)
- in
- let (new_symbol_defs_map : (string, ( ( symbol_definition option)list)) Pmap.map)
- = (Pmap.map (fun b_pair_list -> Lem_list.map (fun (b_idx, (new_b, maybe_new_def)) -> maybe_new_def) b_pair_list) updated_bindings_and_new_defs)
- in
- let (new_symbol_defs_by_name : (string, ( symbol_definition list)) Pmap.map) = (Pmap.map
- (fun v -> Lem_list.mapMaybe id0 v) new_symbol_defs_map)
- in
- (* { List.mapMaybe id maybe_def_list | forall ((_, maybe_def_list) IN (Map.toSet new_symbol_defs_map)) | true }
- in*)
- (*let new_symbol_defs = List.concat (Set_extra.toList new_symbol_def_list_set)
- in*)
- let updated_bindings = (Pmap.map (fun b_pair_list -> Lem_list.map (fun (b_idx, (new_b, maybe_new_def)) -> (b_idx, new_b)) b_pair_list) updated_bindings_and_new_defs)
- in
- (new_symbol_defs_by_name, updated_bindings)
- )
- in
- (*let _ = errln ("For __fini_array_end, we have " ^
- (let all_bs = match Map.lookup "__fini_array_end" bindings_by_name with
- Just l -> l
- | Nothing -> []
- end
- in
- ((show (length all_bs)) ^
- " bindings, of which " ^
- (show (length (List.filter (fun (bi, ((ref_idx, ref, ref_item), maybe_def)) ->
- match maybe_def with
- Just _ -> true
- | _ -> false
- end
- ) all_bs))) ^ " have defs")))
- in*)
- let outputs_by_name =
- (let insert_fun = (fun m -> (fun (OutputSectionSpec(guard, maybe_addr, name1, compos), script_idx) -> Pmap.add name1 ((OutputSectionSpec (guard, maybe_addr, name1, compos)), script_idx) m))
- in
- List.fold_left insert_fun (Pmap.empty compare) outputs)
- in
- (* Print the link map's "discarded input sections" output. *)
- (*let _ = Missing_pervasives.outln "\nDiscarded input sections\n"
- in*)
- let discard_line = (fun i -> ((match i with
- InputSection(s) ->
- let lpadded_secname = (" " ^ s.secname)
- in
- lpadded_secname ^ ((space_padding_and_maybe_newline(Nat_big_num.of_int 16) lpadded_secname) ^ ("0x0000000000000000" (* FIXME *)
- ^ (" 0x" ^ ((hex_string_of_natural s.isec.elf64_section_size) ^ (" "
- ^ (s.fname ^ "\n"))))))
- | Common(idx1, fname1, img2, def) -> "" (* don't print discard lines for discarded commons *)
- )))
- in
- (*let _ = Missing_pervasives.outs (List.foldl (fun str -> (fun input -> (str ^ (discard_line input)))) "" (reverse discards))
- in*)
- let outputs_by_name_after_gc = (compute_def_use_and_gc (AllocatedSectionsMap outputs_by_name))
- in
- (*let _ = Missing_pervasives.outs "\nMemory Configuration\n\nName Origin Length Attributes\n*default* 0x0000000000000000 0xffffffffffffffff\n"
- in
- let _ = Missing_pervasives.outln "\nLinker script and memory map\n"
- in*)
- (* FIXME: print LOAD and START_GROUP trace *)
- let (img2, outputs_by_name_with_position)
- = (build_image alloc_map empty_elf_memory_image(Nat_big_num.of_int 0) outputs_by_name_after_gc bindings_by_name labelled_script control_script_linkable_idx linker_defs_by_name)
- in
- (*let _ = errln ("Final image has " ^ (show (Map.size img.elements)) ^ " elements and "
- ^ (show (Set.size img.by_tag)) ^ " metadata tags, of which " ^ (
- let (section_tags, section_ranges) = elf_memory_image_section_ranges img
- in
- let section_tags_bare = List.map (fun tag ->
- match tag with
- | FileFeature(ElfSection(idx, isec)) -> (idx, isec)
- | _ -> failwith "not section tag"
- end) section_tags
- in
- show (length section_tags_bare)
- ) ^ " are sections.")
- in*)
- (* The link map output for the section/address assignment basically mirrors our notion of
- * output section composition. In the following:
-
- 0x0000000000400000 PROVIDE (__executable_start, 0x400000)
- 0x0000000000400190 . = (0x400000 + SIZEOF_HEADERS)
-
-.interp
- *(.interp)
-
-.note.ABI-tag 0x0000000000400190 0x20
- .note.ABI-tag 0x0000000000400190 0x20 crt1.o
-
-.note.gnu.build-id
- 0x00000000004001b0 0x24
- *(.note.gnu.build-id)
- .note.gnu.build-id
- 0x00000000004001b0 0x24 crt1.o
-
-.hash
- *(.hash)
-
-.gnu.hash
- *(.gnu.hash)
-
-... we can see that
-
- - symbol provision, holes and output sections all get lines
-
- - each output section appears with its name left-aligned, and its address,
- if any, appearing afterwards; if so, the section's total size also follows.
-
- - each input query is printed verbatim, e.g. "*(.note.gnu.build-id)"
-
- - underneath this, a line is printed for each input section that was included,
- with its address and size. This can spill onto a second line in the usual way.
-
- - holes are shown as "*fill*"
-
- - provided symbols are shown as in the linker script source.
-
- PROBLEM: we don't have the script in source form, so we can't print the queries verbatim.
- I should really annotate each query with its source form; when the script is parsed from source,
- this can be inserted automatically. For the moment, what to do? I could annotate each script
- element manually. For the moment, for diffing purposes, filter out lines with asterisks.
-
- *)
- (img2, bindings_by_name))