summaryrefslogtreecommitdiff
path: root/lib/ocaml_rts/linksem/command_line.ml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ocaml_rts/linksem/command_line.ml')
-rw-r--r--lib/ocaml_rts/linksem/command_line.ml671
1 files changed, 671 insertions, 0 deletions
diff --git a/lib/ocaml_rts/linksem/command_line.ml b/lib/ocaml_rts/linksem/command_line.ml
new file mode 100644
index 00000000..62d4b87e
--- /dev/null
+++ b/lib/ocaml_rts/linksem/command_line.ml
@@ -0,0 +1,671 @@
+(*Generated by Lem from command_line.lem.*)
+open Lem_basic_classes
+open Lem_function
+open Lem_string
+open Lem_string_extra
+open Lem_tuple
+open Lem_bool
+open Lem_list
+open Lem_list_extra
+(*import Set*)
+(*import Set_extra*)
+open Lem_sorting
+open Lem_num
+open Lem_maybe
+open Lem_assert_extra
+
+open Byte_sequence
+open Default_printing
+open Error
+open Missing_pervasives
+open Show
+
+(* Here we try to model the command line of GNU ld.bfd.
+ *
+ * Some options are global modifiers affecting the link output.
+ * Others have effect only for some subset of input files.
+ * Typically some mutually-exclusive possibilities exist
+ * whereby each argument selects one such possibility for all subsequent input files,
+ * until a different argument selects another possibility for ensuring inputs.
+ *)
+
+type input_file_spec = Filename of string (* /path/to/file.{o,a,so,...} -- might be script! *)
+ | Libname of string (* -llib *)
+
+(*val string_of_input_file_spec : input_file_spec -> string*)
+let string_of_input_file_spec spec:string=
+ ((match spec with
+ Filename(s) -> "file `" ^ (s ^ "'")
+ | Libname(s) -> "library `" ^ (s ^ "'")
+ ))
+
+let instance_Show_Show_Command_line_input_file_spec_dict:(input_file_spec)show_class= ({
+
+ show_method = string_of_input_file_spec})
+
+type input_file_options = { input_fmt : string
+ ; input_libpath : string list
+ ; input_link_sharedlibs : bool (* -Bstatic *)
+ ; input_check_sections : bool
+ ; input_copy_dt_needed : bool
+ ; input_whole_archive : bool
+ ; input_as_needed : bool
+ }
+
+(*val null_input_file_options : input_file_options*)
+let null_input_file_options:input_file_options=
+ ({ input_fmt = ""
+ ; input_libpath = ([])
+ ; input_link_sharedlibs = false
+ ; input_check_sections = false
+ ; input_copy_dt_needed = false
+ ; input_whole_archive = false
+ ; input_as_needed = false
+ })
+
+type output_kind = Executable
+ | SharedLibrary
+
+type link_option = OutputFilename of string
+ | OutputKind of output_kind
+ | ForceCommonDefined of bool (* -d, -dc, -dp *)
+ | Soname of string (* -soname *)
+ | EntryAddress of Nat_big_num.num
+ | TextSegmentStart of Nat_big_num.num
+ | RodataSegmentStart of Nat_big_num.num
+ | LdataSegmentStart of Nat_big_num.num
+ | BindFunctionsEarly (* -Bsymbolic-functions *)
+ | BindNonFunctionsEarly (* the remainder of -Bsymbolic *)
+ (* more here! *)
+
+(*val tagEqual : link_option -> link_option -> bool*)
+let tagEqual opt1 opt2:bool= ((match (opt1, opt2) with
+ (* FIXME: Lem BUG here! says "duplicate binding" *)
+ (OutputFilename(_), OutputFilename(_)) -> true
+ | (OutputKind(_), OutputKind(_)) -> true
+ (* | (ForceCommonDefined, ForceCommonDefined) -> true *)
+ | (Soname(_), Soname(_)) -> true
+ (* | (EntryAddress, EntryAddress) -> true *)
+ | (TextSegmentStart(_), TextSegmentStart(_)) -> true
+ | (RodataSegmentStart(_), RodataSegmentStart(_)) -> true
+ | (LdataSegmentStart(_), LdataSegmentStart(_)) -> true
+ (* | (BindFunctionsEarly, BindFunctionsEarly) -> true *)
+ (* | (BindNonFunctionsEarly, BindNonFunctionsEarly) -> true *)
+ | _ -> false
+))
+
+(* To allow filtering out a previous setting for a given option, we define
+ * an equality relation that is true if options are of the same constructor.
+ * Seems like a bit of a HACK. *)
+let instance_Basic_classes_Eq_Command_line_link_option_dict:(link_option)eq_class= ({
+
+ isEqual_method = (fun opt1 ->
+ (fun opt2 ->
+ (match (opt1, opt2) with
+ | (OutputFilename(_), OutputFilename(_)) -> true
+ | (ForceCommonDefined(_), ForceCommonDefined(_)) -> true
+ | (Soname(_), Soname(_)) -> true
+ | (EntryAddress(_), EntryAddress(_)) -> true
+ | _ -> false
+ )
+ ));
+
+ isInequal_method = (fun opt1 -> (fun opt2 -> not ( ((fun opt1 ->
+ (fun opt2 ->
+ (match (opt1, opt2) with
+ | (OutputFilename(_), OutputFilename(_)) -> true
+ | (ForceCommonDefined(_), ForceCommonDefined(_)) -> true
+ | (Soname(_), Soname(_)) -> true
+ | (EntryAddress(_), EntryAddress(_)) -> true
+ | _ -> false
+ )
+ ))opt1 opt2))))})
+
+type input_file_and_options = input_file_spec * input_file_options
+type input_unit = File of input_file_and_options
+ | Group of (input_file_and_options) list (* NOT recursive *)
+ | BuiltinControlScript (* for uniformity when processing script defs *)
+
+(*val string_of_input_unit : input_unit -> string*)
+let string_of_input_unit u:string=
+ ((match u with
+ File(spec, opts) ->
+ "single " ^ (string_of_input_file_spec spec)
+ | Group(spec_opt_list) ->
+ "group: [" ^ ((string_of_list
+ instance_Show_Show_Command_line_input_file_spec_dict (Lem_list.map (fun (spec, opts) -> spec) spec_opt_list)) ^ "]")
+ | BuiltinControlScript -> "(built-in control script)"
+ ))
+
+let instance_Show_Show_Command_line_input_unit_dict:(input_unit)show_class= ({
+
+ show_method = string_of_input_unit})
+
+(* Reading the command-line:
+ * we encode the meaning of a linker command token
+ * using a reader function interpreting a list of argument definitions.
+ * Lookahead is necessary: sometimes the interpretation of an option
+ * depends on the next argument (e.g. whether it's a file, directory or another option).
+ * The list of argument definitions is from lists of strings to constructor function invocations.
+ * We use lists of strings since many options have synonyms.
+ * The strings are interpreted as regular expressions and any matched groups are collected together
+ * as a second argument list; this is because some arguments are of the form --blah=NUM or similar. *)
+
+(* As we read the command line, we keep a current state which is the collection
+ * of seen input files, seen whole-link options, and input file options that will
+ * apply to any input files we add subsequently. *)
+type command_state = { input_units : input_unit list
+ ; link_options : link_option Pset.set
+ ; current_input_options : input_file_options
+ ; current_group : ( input_file_and_options list)option
+ }
+
+(* This is the "default state" when we start reading input options *)
+(*val initial_state : list command_state*) (* the stack *)
+let initial_state0:(command_state)list= ([{ input_units = ([])
+ ; link_options =(Pset.from_list compare [OutputFilename("a.out"); OutputKind(Executable)])
+ ; current_input_options = ({ input_fmt = "elf64-x86-64" (* FIXME *)
+ ; input_libpath = (["/usr/lib"]) (* FIXME: this probably isn't the right place to supply the default search path *)
+ ; input_link_sharedlibs = true
+ ; input_check_sections = true
+ ; input_copy_dt_needed = false
+ ; input_whole_archive = false
+ ; input_as_needed = true (* FIXME *)
+ })
+ ; current_group = None
+ }])
+
+type interpreted_command_line = input_unit list * link_option Pset.set
+
+(*val add_input_file : list command_state -> string -> list command_state*)
+let add_input_file (state1 :: more) s:(command_state)list=
+ (let chars = (Xstring.explode s)
+ in
+ let spec = ((match chars with
+ '-' :: 'l' :: more -> Libname(Xstring.implode more)
+ | '-' :: more -> failwith ("not a valid option or input file: " ^ s)
+ | _ -> Filename(s)
+ ))
+ in
+ if (Lem.option_equal (listEqualBy (Lem.pair_equal (=) (=))) state1.current_group None)
+ then
+ { input_units = (List.rev_append (List.rev state1.input_units) [File(spec, state1.current_input_options)])
+ ; link_options = (state1.link_options)
+ ; current_input_options = (state1.current_input_options)
+ ; current_group = (state1.current_group)
+ } :: more
+ else
+ { input_units = (state1.input_units)
+ ; link_options = (state1.link_options)
+ ; current_input_options = (state1.current_input_options)
+ ; current_group = (let toAppend = ([(spec, state1.current_input_options)]) in
+ (match state1.current_group with Some l -> Some( List.rev_append (List.rev l) toAppend) | None -> Some(toAppend)
+ ))
+ } :: more)
+
+(*val start_group : list command_state -> list command_state*)
+let start_group (state1 :: more):(command_state)list= ({
+ input_units = (state1.input_units)
+ ; link_options = (state1.link_options)
+ ; current_input_options = (state1.current_input_options)
+ ; current_group = ((match state1.current_group with
+ None -> Some []
+ | _ -> failwith "cannot nest groups"
+ ))
+ } :: more)
+
+(*val end_group : list command_state -> list command_state*)
+let end_group (state1 :: more):(command_state)list= ({
+ input_units = (List.rev_append (List.rev state1.input_units) ((match state1.current_group with
+ Some l -> [Group(l)]
+ | None -> failwith "end group without start group"
+ )))
+ ; link_options = (state1.link_options)
+ ; current_input_options = (state1.current_input_options)
+ ; current_group = None
+ } :: more)
+
+type option_token = string
+type option_argspecs = string list * string list
+type option_argvals = string list * string list
+
+(*val set_or_replace_option : link_option -> list command_state -> list command_state*)
+let set_or_replace_option opt state_list:(command_state)list=
+ ((match state_list with
+ [] -> failwith "error: no state"
+ | state1 :: more ->
+ { input_units = (state1.input_units)
+ ; link_options = (Pset.add opt (Pset.filter (fun existing -> ((fun opt1 -> (fun opt2 -> not ( ((fun opt1 ->
+ (fun opt2 ->
+ (match (opt1, opt2) with
+ | (OutputFilename(_), OutputFilename(_)) -> true
+ | (ForceCommonDefined(_), ForceCommonDefined(_)) -> true
+ | (Soname(_), Soname(_)) -> true
+ | (EntryAddress(_), EntryAddress(_)) -> true
+ | _ -> false
+ )
+ ))opt1 opt2)))) existing opt)) state1.link_options))
+ ; current_input_options = (state1.current_input_options)
+ ; current_group = (state1.current_group)
+ } :: more
+ ))
+
+(*val find_option_matching_tag : link_option -> set link_option -> maybe link_option*)
+let rec find_option_matching_tag tag options:(link_option)option=
+ (Lem_list.list_find_opt (tagEqual tag) (Pset.elements options))
+
+(*val extract_hex_addend : char -> maybe natural*)
+let extract_hex_addend x:(Nat_big_num.num)option=
+ (if x = '0' then
+ Some(Nat_big_num.of_int 0)
+ else if x = '1' then
+ Some(Nat_big_num.of_int 1)
+ else if x = '2' then
+ Some(Nat_big_num.of_int 2)
+ else if x = '3' then
+ Some(Nat_big_num.of_int 3)
+ else if x = '4' then
+ Some(Nat_big_num.of_int 4)
+ else if x = '5' then
+ Some(Nat_big_num.of_int 5)
+ else if x = '6' then
+ Some(Nat_big_num.of_int 6)
+ else if x = '7' then
+ Some(Nat_big_num.of_int 7)
+ else if x = '8' then
+ Some(Nat_big_num.of_int 8)
+ else if x = '9' then
+ Some(Nat_big_num.of_int 9)
+ else if x = 'a' then
+ Some(Nat_big_num.of_int 10)
+ else if x = 'b' then
+ Some(Nat_big_num.of_int 11)
+ else if x = 'c' then
+ Some(Nat_big_num.of_int 12)
+ else if x = 'd' then
+ Some(Nat_big_num.of_int 13)
+ else if x = 'e' then
+ Some(Nat_big_num.of_int 14)
+ else if x = 'f' then
+ Some(Nat_big_num.of_int 15)
+ else
+ None)
+
+(*val accumulate_hex_chars : natural -> list char -> natural*)
+let rec accumulate_hex_chars acc chars:Nat_big_num.num=
+ ((match chars with
+ | [] -> acc
+ | x::xs ->
+ (match extract_hex_addend x with
+ | None -> acc
+ | Some addend ->
+ accumulate_hex_chars ( Nat_big_num.add (Nat_big_num.mul acc(Nat_big_num.of_int 16)) addend) xs
+ )
+ ))
+
+(*val extract_dec_addend : char -> maybe natural*)
+let extract_dec_addend x:(Nat_big_num.num)option=
+ (if x = '0' then
+ Some(Nat_big_num.of_int 0)
+ else if x = '1' then
+ Some(Nat_big_num.of_int 1)
+ else if x = '2' then
+ Some(Nat_big_num.of_int 2)
+ else if x = '3' then
+ Some(Nat_big_num.of_int 3)
+ else if x = '4' then
+ Some(Nat_big_num.of_int 4)
+ else if x = '5' then
+ Some(Nat_big_num.of_int 5)
+ else if x = '6' then
+ Some(Nat_big_num.of_int 6)
+ else if x = '7' then
+ Some(Nat_big_num.of_int 7)
+ else if x = '8' then
+ Some(Nat_big_num.of_int 8)
+ else if x = '9' then
+ Some(Nat_big_num.of_int 9)
+ else
+ None)
+
+(*val accumulate_dec_chars : natural -> list char -> natural*)
+let rec accumulate_dec_chars acc chars:Nat_big_num.num=
+ ((match chars with
+ | [] -> acc
+ | x::xs ->
+ (match extract_dec_addend x with
+ | None -> acc
+ | Some addend ->
+ accumulate_hex_chars ( Nat_big_num.add (Nat_big_num.mul acc(Nat_big_num.of_int 16)) addend) xs
+ )
+ ))
+
+(*val parse_address : string -> natural*)
+let parse_address s:Nat_big_num.num= ((match Xstring.explode s with
+ '0' :: 'x' :: more -> accumulate_hex_chars(Nat_big_num.of_int 0) more
+ | chars -> accumulate_dec_chars(Nat_big_num.of_int 0) chars
+))
+
+type option_def = ( option_token list) * option_argspecs * (option_argvals -> command_state list -> command_state list) * string
+
+(* the table is a list of: ... options and their arg names ... and the option's meaning as a function... and a help string *)
+(*val command_line_table : list option_def*)
+let command_line_table:((string)list*((string)list*(string)list)*((string)list*(string)list ->(command_state)list ->(command_state)list)*string)list= ([
+ (* per-input options *)
+ (["-b"; "--format"], (["TARGET"], []), (fun args -> (fun state1 -> state1)), "Specify target for following input files");
+ (["-L"; "--library-path"], (["DIRECTORY"], []), (fun args -> (fun state1 -> state1)), "Add DIRECTORY to library search path");
+ (["--as-needed"], ([], []), (fun _ -> (fun state1 -> state1)), "Only set DT_NEEDED for following dynamic libs if used");
+ (["--no-as-needed"], ([], []), (fun _ -> (fun state1 -> state1)), "Always set DT_NEEDED for dynamic libraries mentioned on the command line");
+ (["-Bdynamic"; "-dy"; "-call_shared"], ([], []), (fun _ -> (fun state1 -> state1)), "Link against shared libraries");
+ (["-Bstatic"; "-dn"; "-non_shared"; "-static"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not link against shared libraries");
+ (["--check-sections"], ([], []), (fun _ -> (fun state1 -> state1)), "Check section addresses for overlaps (default) **srk** not sure it's per-input!");
+ (["--no-check-sections"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not check section addresses for overlaps **srk** not sure it's per-input!");
+ (["--copy-dt-needed-entries"], ([], []), (fun _ -> (fun state1 -> state1)), "Copy DT_NEEDED links mentioned inside DSOs that follow");
+ (["--no-copy-dt-needed-entries"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not copy DT_NEEDED links mentioned inside DSOs that follow");
+ (["--no-whole-archive"], ([], []), (fun _ -> (fun state1 -> state1)), "Turn off --whole-archive");
+ (["-rpath-link"], (["PATH"], []), (fun _ -> (fun state1 -> state1)), "Set link time shared library search path **srk** not sure it's per-input!");
+ (["--whole-archive"], ([], []), (fun _ -> (fun state1 -> state1)), "Include all objects from following archives");
+ (* linker plugin control *)
+ (["-plugin"], (["PLUGIN"], []), (fun _ -> (fun state1 -> state1)), "Load named plugin");
+ (["-plugin-opt"], (["ARG"], []), (fun _ -> (fun state1 -> state1)), "Send arg to last-loaded plugin");
+ (* output / whole-job options (some may be repeated with different args, but most not): *)
+ (["-A"; "--architecture"], (["ARCH"], []), (fun _ -> (fun state1 -> state1)), "Set architecture");
+ (["-EB"], ([], []), (fun _ -> (fun state1 -> state1)), "Link big-endian objects");
+ (["-EL"], ([], []), (fun _ -> (fun state1 -> state1)), "Link little-endian objects");
+ (["-R"; "--just-symbols"], (["DIR"], []), (fun _ -> (fun state1 -> state1)), "**srk** (if directory, same as --rpath)");
+ (["-d"; "-dc"; "-dp"], ([], []), (fun _ -> (fun state1 -> state1)), "Force common symbols to be defined");
+ (["-e"; "--entry"], (["ADDRESS"], []), (fun _ -> (fun state1 -> state1)), "Set start address");
+ (["-E"; "--export-dynamic"], ([], []), (fun _ -> (fun state1 -> state1)), "Export all dynamic symbols");
+ (["--no-export-dynamic"], ([], []), (fun _ -> (fun state1 -> state1)), "Undo the effect of --export-dynamic");
+ (["-f"; "--auxiliary"], (["SHLIB"], []), (fun _ -> (fun state1 -> state1)), "Auxiliary filter for shared object symbol table");
+ (["-F"; "--filter"], (["SHLIB"], []), (fun _ -> (fun state1 -> state1)), "Filter for shared object symbol table");
+ (["-G"; "--gpsize"], (["SIZE"], []), (fun _ -> (fun state1 -> state1)), "Small data size (if no size, same as --shared) **srk NOTE this quirk!**");
+ (["-h"; "-soname"], (["FILENAME"], []), (fun _ -> (fun state1 -> state1)), "Set internal name of shared library");
+ (["-I"; "--dynamic-linker"], (["PROGRAM"], []), (fun _ -> (fun state1 -> state1)), "Set PROGRAM as the dynamic linker to use");
+ (["--sysroot="], ([], ["DIRECTORY"]), (fun _ -> (fun state1 -> state1)), "Override the default sysroot location");
+ (["-m"], (["EMULATION"], []), (fun _ -> (fun state1 -> state1)), "Set emulation");
+ (["-n"; "--nmagic"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not page align data");
+ (["-N"; "--omagic"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not page align data, do not make text readonly");
+ (["--no-omagic"], ([], []), (fun _ -> (fun state1 -> state1)), "Page align data, make text readonly");
+ (["-o"; "--output"], (["FILE"], []), (fun argvals -> set_or_replace_option (OutputFilename(List.hd (fst argvals)))), "Set output file name");
+ (["-O"], ([], []), (fun _ -> (fun state1 -> state1)), "Optimise output file");
+ (["-q"; "--emit-relocs"], ([], []), (fun _ -> (fun state1 -> state1)), "Generate relocations in final output");
+ (["-r"; "-i"; "--relocatable"], ([], []), (fun _ -> (fun state1 -> state1)), "Generate relocatable output");
+ (["-s"; "--strip-all"], ([], []), (fun _ -> (fun state1 -> state1)), "Strip all symbols");
+ (["-S"; "--strip-debug"], ([], []), (fun _ -> (fun state1 -> state1)), "Strip debugging symbols");
+ (["--strip-discarded"], ([], []), (fun _ -> (fun state1 -> state1)), "Strip symbols in discarded sections");
+ (["--no-strip-discarded"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not strip symbols in discarded sections");
+ (["--default-script"; "-dT"], (["FILE"], []), (fun _ -> (fun state1 -> state1)), "Read default linker script");
+ (["--unique="], ([], ["SECTION"]), (fun _ -> (fun state1 -> state1)), "Don't merge input [SECTION | orphan] sections");
+ (["-Ur"], ([], []), (fun _ -> (fun state1 -> state1)), "Build global constructor/destructor tables ( **srk**: like -r, but... )");
+ (["-x"; "--discard-all"], ([], []), (fun _ -> (fun state1 -> state1)), "Discard all local symbols");
+ (["-X"; "--discard-locals"], ([], []), (fun _ -> (fun state1 -> state1)), "Discard temporary local symbols (default)");
+ (["--discard-none"], ([], []), (fun _ -> (fun state1 -> state1)), "Don't discard any local symbols");
+ (["-Bsymbolic"], ([], []), (fun argvals -> (fun state1 -> set_or_replace_option BindFunctionsEarly (set_or_replace_option BindNonFunctionsEarly state1))), "Bind global references locally");
+ (["-Bsymbolic-functions"], ([], []), (fun argvals -> set_or_replace_option (BindFunctionsEarly)), "Bind global function references locally");
+ (["--force-exe-suffix"], ([], []), (fun _ -> (fun state1 -> state1)), "Force generation of file with .exe suffix");
+ (["--gc-sections"], ([], []), (fun _ -> (fun state1 -> state1)), "**srk: uncertain: can repeat?** Remove unused sections (on some targets)");
+ (["--no-gc-sections"], ([], []), (fun _ -> (fun state1 -> state1)), "**srk: uncertain: can repeat?** Don't remove unused sections (default)");
+ (["--hash-size="], ([], ["NUMBER"]), (fun _ -> (fun state1 -> state1)), "Set default hash table size close to <NUMBER>");
+ (["--no-define-common"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not define Common storage");
+ (["--no-undefined"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not allow unresolved references in object files");
+ (["--allow-shlib-undefined"], ([], []), (fun _ -> (fun state1 -> state1)), "Allow unresolved references in shared libraries");
+ (["--no-allow-shlib-undefined"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not allow unresolved references in shared libs");
+ (["--default-symver"], ([], []), (fun _ -> (fun state1 -> state1)), "Create default symbol version");
+ (["--default-imported-symver"], ([], []), (fun _ -> (fun state1 -> state1)), "Create default symbol version for imported symbols");
+ (["-nostdlib"], ([], []), (fun _ -> (fun state1 -> state1)), "Only use library directories specified on the command line");
+ (["--oformat"], (["TARGET"], []), (fun _ -> (fun state1 -> state1)), "Specify target of output file");
+ (["--relax"], ([], []), (fun _ -> (fun state1 -> state1)), "Reduce code size by using target specific optimisations");
+ (["--no-relax"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not use relaxation techniques to reduce code size");
+ (["--retain-symbols-file"], (["FILE"], []), (fun _ -> (fun state1 -> state1)), "Keep only symbols listed in FILE");
+ (["-rpath"], (["PATH"], []), (fun _ -> (fun state1 -> state1)), "Set runtime shared library search path");
+ (["-shared"; "-Bshareable"], ([], []), (fun argvals -> set_or_replace_option (OutputKind(SharedLibrary))), "Create a shared library");
+ (["-pie"; "--pic-executable"], ([], []), (fun _ -> (fun state1 -> state1)), "Create a position independent executable");
+ (["--sort-common="],(* (ascending|descending) *)([], ["order"]), (fun _ -> (fun state1 -> state1)), "Sort common symbols by alignment [in specified order]");
+ (["--sort-section="],(* (name|alignment) *) ([], ["key"]), (fun _ -> (fun state1 -> state1)), "Sort sections by name or maximum alignment");
+ (["--spare-dynamic-tags"], (["COUNT"], []), (fun _ -> (fun state1 -> state1)), "How many tags to reserve in .dynamic section");
+ (["--split-by-file="], ([], ["SIZE"]), (fun _ -> (fun state1 -> state1)), "Split output sections every SIZE octets");
+ (["--split-by-reloc="], ([], ["COUNT"]), (fun _ -> (fun state1 -> state1)), "Split output sections every COUNT relocs");
+ (["--traditional-format"], ([], []), (fun _ -> (fun state1 -> state1)), "Use same format as native linker");
+ (["--unresolved-symbols="], ([], ["method"]), (fun _ -> (fun state1 -> state1)), "How to handle unresolved symbols. <method> is: ignore-all, report-all, ignore-in-object-files, ignore-in-shared-libs");
+ (["--dynamic-list-data"], ([], []), (fun _ -> (fun state1 -> state1)), "Add data symbols to dynamic list");
+ (["--dynamic-list-cpp-new"], ([], []), (fun _ -> (fun state1 -> state1)), "Use C++ operator new/delete dynamic list");
+ (["--dynamic-list-cpp-typeinfo "], ([], []), (fun _ -> (fun state1 -> state1)), "Use C++ typeinfo dynamic list");
+ (["--dynamic-list"], (["FILE"], []), (fun _ -> (fun state1 -> state1)), "Read dynamic list");
+ (["--wrap"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Use wrapper functions for SYMBOL");
+ (* the following are specific to ELF emulations *)
+ (["--audit=(.*)"], ([], ["AUDITLIB"]), (fun _ -> (fun state1 -> state1)), "Specify a library to use for auditing");
+ (["-Bgroup"], ([], []), (fun _ -> (fun state1 -> state1)), "Selects group name lookup rules for DSO");
+ (["--build-id="], ([], ["STYLE"]), (fun _ -> (fun state1 -> state1)), "Generate build ID note");
+ (["-P"], (["AUDITLIB"], []), (fun _ -> (fun state1 -> state1)), "Specify a library to use for auditing dependencies");
+ (["--depaudit="], ([], ["AUDITLIB"]), (fun _ -> (fun state1 -> state1)), "Specify a library to use for auditing dependencies");
+ (["--disable-new-dtags"], ([], []), (fun _ -> (fun state1 -> state1)), "Disable new dynamic tags");
+ (["--enable-new-dtags"], ([], []), (fun _ -> (fun state1 -> state1)), "Enable new dynamic tags");
+ (["--eh-frame-hdr"], ([], []), (fun _ -> (fun state1 -> state1)), "Create .eh_frame_hdr section");
+ (["--exclude-libs="], ([], ["LIBS"]), (fun _ -> (fun state1 -> state1)), "Make all symbols in LIBS hidden");
+ (["--hash-style="], ([], ["STYLE"]), (fun _ -> (fun state1 -> state1)), "Set hash style to sysv, gnu or both");
+ (* NOTE: for these to work, we hack our word-splitter to merge -z options into a single word with a single space in *)
+ (["-z combreloc"], ([], []), (fun _ -> (fun state1 -> state1)), "Merge dynamic relocs into one section and sort");
+ (["-z common-page-size="], ([], ["SIZE"]), (fun _ -> (fun state1 -> state1)), "Set common page size to SIZE");
+ (["-z defs"], ([], []), (fun _ -> (fun state1 -> state1)), "Report unresolved symbols in object files.");
+ (["-z execstack"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark executable as requiring executable stack");
+ (["-z global"], ([], []), (fun _ -> (fun state1 -> state1)), "Make symbols in DSO available for subsequently loaded objects");
+ (["-z initfirst"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark DSO to be initialized first at runtime");
+ (["-z interpose"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark object to interpose all DSOs but executable");
+ (["-z lazy"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark object lazy runtime binding (default)");
+ (["-z loadfltr"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark object requiring immediate process");
+ (["-z max-page-size="], ([], ["SIZE"]), (fun _ -> (fun state1 -> state1)), "Set maximum page size to SIZE");
+ (["-z nocombreloc"], ([], []), (fun _ -> (fun state1 -> state1)), "Don't merge dynamic relocs into one section");
+ (["-z nocopyreloc"], ([], []), (fun _ -> (fun state1 -> state1)), "Don't create copy relocs");
+ (["-z nodefaultlib"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark object not to use default search paths");
+ (["-z nodelete"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark DSO non-deletable at runtime");
+ (["-z nodlopen"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark DSO not available to dlopen");
+ (["-z nodump"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark DSO not available to dldump");
+ (["-z noexecstack"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark executable as not requiring executable stack");
+ (["-z norelro"], ([], []), (fun _ -> (fun state1 -> state1)), "Don't create RELRO program header");
+ (["-z now"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark object non-lazy runtime binding");
+ (["-z origin"], ([], []), (fun _ -> (fun state1 -> state1)), "Mark object requiring immediate $ORIGIN processing at runtime");
+ (["-z relro"], ([], []), (fun _ -> (fun state1 -> state1)), "Create RELRO program header");
+ (["-z stacksize="], ([], ["SIZE"]), (fun _ -> (fun state1 -> state1)), "Set size of stack segment");
+ (["-z bndplt"], ([], []), (fun _ -> (fun state1 -> state1)), "Always generate BND prefix in PLT entries");
+ (["--ld-generated-unwind-info"], ([], []), (fun _ -> (fun state1 -> state1)), "Generate exception handling info for PLT.");
+ (["--no-ld-generated-unwind-info"], ([], []), (fun _ -> (fun state1 -> state1)), "Don't do so.");
+ (* quasi-input options (can be repeated): *)
+ (["-c"; "--mri-script"], (["FILE"], []), (fun _ -> (fun state1 -> state1)), "Read MRI format linker script");
+ (["-l"; "--library"], (["LIBNAME"], []), (fun _ -> (fun state1 -> state1)), "Search for library LIBNAME");
+ (* (["-R" ,"--just-symbols"], (["FILE"], []), fun _ -> (fun state -> state), "Just link symbols"), *) (* Handled above! *)
+ (["-T"; "--script"], (["FILE"], []), (fun _ -> (fun state1 -> state1)), "Read linker script");
+ (["-u"; "--undefined"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Start with undefined reference to SYMBOL");
+ (["-("; "--start-group"], ([], []), (fun _ -> (fun state1 -> start_group state1)), "Start a group");
+ (["-)"; "--end-group"], ([], []), (fun _ -> (fun state1 -> end_group state1)), "End a group");
+ (["--defsym"], (["SYMBOL=EXPRESSION"], []), (fun _ -> (fun state1 -> state1)), "Define a symbol");
+ (["-fini"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Call SYMBOL at unload-time");
+ (["-init"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Call SYMBOL at load-time");
+ (["--section-start"], (["SECTION=ADDRESS"], []), (fun _ -> (fun state1 -> state1)), "Set address of named section");
+ (["-Tbss"], (["ADDRESS"], []), (fun _ -> (fun state1 -> state1)), "Set address of .bss section");
+ (["-Tdata"], (["ADDRESS"], []), (fun _ -> (fun state1 -> state1)), "Set address of .data section");
+ (["-Ttext"], (["ADDRESS"], []), (fun _ -> (fun state1 -> state1)), "Set address of .text section");
+ (["-Ttext-segment"], (["ADDRESS"], []), (fun argvals -> set_or_replace_option (TextSegmentStart(parse_address (List.hd (fst argvals))))), "Set address of text segment");
+ (["-Trodata-segment"], (["ADDRESS"], []), (fun argvals -> set_or_replace_option (RodataSegmentStart(parse_address (List.hd (fst argvals))))), "Set address of rodata segment");
+ (["-Tldata-segment"], (["ADDRESS"], []), (fun argvals -> set_or_replace_option (LdataSegmentStart(parse_address (List.hd (fst argvals))))), "Set address of ldata segment");
+ (["--version-script"], (["FILE"], []), (fun _ -> (fun state1 -> state1)), "Read version information script");
+ (["--version-exports-section"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Take export symbols list from .exports, using SYMBOL as the version.");
+ (* linker internal debugging/diagnostics and performance tuning *)
+ (["-M"; "--print-map"], ([], []), (fun _ -> (fun state1 -> state1)), "Print map file on standard output");
+ (["-t"; "--trace"], ([], []), (fun _ -> (fun state1 -> state1)), "Trace file opens");
+ (["-v"; "--version"], ([], []), (fun _ -> (fun state1 -> state1)), "Print version information");
+ (["-V"], ([], []), (fun _ -> (fun state1 -> state1)), "Print version and emulation information");
+ (["-y"; "--trace-symbol"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Trace mentions of SYMBOL");
+ (["--cref"], ([], []), (fun _ -> (fun state1 -> state1)), "Output cross reference table");
+ (["--demangle="], ([], ["STYLE"]), (fun _ -> (fun state1 -> state1)), "Demangle symbol names [using STYLE]");
+ (["--print-gc-sections"], ([], []), (fun _ -> (fun state1 -> state1)), "List removed unused sections on stderr");
+ (["--no-print-gc-sections"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not list removed unused sections");
+ (["-Map"], (["FILE"], []), (fun _ -> (fun state1 -> state1)), "Write a map file");
+ (["-Map="], ([], ["FILE"]), (fun _ -> (fun state1 -> state1)), "Write a map file");
+ (["--help"], ([], []), (fun _ -> (fun state1 -> state1)), "Print option help");
+ (["--no-keep-memory"], ([], []), (fun _ -> (fun state1 -> state1)), "Use less memory and more disk I/O");
+ (["--no-demangle"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not demangle symbol names");
+ (["--print-output-format"], ([], []), (fun _ -> (fun state1 -> state1)), "Print default output format");
+ (["--print-sysroot"], ([], []), (fun _ -> (fun state1 -> state1)), "Print current sysroot");
+ (["--reduce-memory-overheads"], ([], []), (fun _ -> (fun state1 -> state1)), "Reduce memory overheads, possibly taking much longer");
+ (["--stats"], ([], []), (fun _ -> (fun state1 -> state1)), "Print memory usage statistics");
+ (["--target-help"], ([], []), (fun _ -> (fun state1 -> state1)), "Display target specific options");
+ (["--verbose="], ([], ["NUMBER"]), (fun _ -> (fun state1 -> state1)), "Output lots of information during link");
+ (* unknown *)
+ (["--embedded-relocs"], ([], []), (fun _ -> (fun state1 -> state1)), "Generate embedded relocs");
+ (["--task-link"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Do task level linking");
+ (* compatibility *)
+ (["-a"], (["KEYWORD"], []), (fun _ -> (fun state1 -> state1)), "Shared library control for HP/UX compatibility");
+ (["-Y"], (["PATH"], []), (fun _ -> (fun state1 -> state1)), "Default search path for Solaris compatibility");
+ (* permissiveness controls (tightening/loosening) *)
+ (["--accept-unknown-input-arch"], ([], []), (fun _ -> (fun state1 -> state1)), "Accept input files whose architecture cannot be determined");
+ (["--no-accept-unknown-input-arch"], ([], []), (fun _ -> (fun state1 -> state1)), "Reject input files whose architecture is unknown");
+ (["--fatal-warnings"], ([], []), (fun _ -> (fun state1 -> state1)), "Treat warnings as errors");
+ (["--no-fatal-warnings"], ([], []), (fun _ -> (fun state1 -> state1)), "Do not treat warnings as errors (default)");
+ (["--allow-multiple-definition"], ([], []), (fun _ -> (fun state1 -> state1)), "Allow multiple definitions");
+ (["--no-undefined-version"], ([], []), (fun _ -> (fun state1 -> state1)), "Disallow undefined version");
+ (["--noinhibit-exec"], ([], []), (fun _ -> (fun state1 -> state1)), "Create an output file even if errors occur");
+ (["--error-unresolved-symbols"], ([], []), (fun _ -> (fun state1 -> state1)), "Report unresolved symbols as errors");
+ (["--ignore-unresolved-symbol"], (["SYMBOL"], []), (fun _ -> (fun state1 -> state1)), "Unresolved SYMBOL will not cause an error or warning");
+ (* permissiveness, specific to ELF emulation *)
+ (["-z muldefs"], ([], []), (fun _ -> (fun state1 -> state1)), "Allow multiple definitions");
+ (* warnings (enabling/disabling) *)
+ (["--no-warn-mismatch"], ([], []), (fun _ -> (fun state1 -> state1)), "Don't warn about mismatched input files");
+ (["--no-warn-search-mismatch"], ([], []), (fun _ -> (fun state1 -> state1)), "Don't warn on finding an incompatible library");
+ (["--warn-common"], ([], []), (fun _ -> (fun state1 -> state1)), "Warn about duplicate common symbols");
+ (["--warn-constructors"], ([], []), (fun _ -> (fun state1 -> state1)), "Warn if global constructors/destructors are seen");
+ (["--warn-multiple-gp"], ([], []), (fun _ -> (fun state1 -> state1)), "Warn if the multiple GP values are used");
+ (["--warn-once"], ([], []), (fun _ -> (fun state1 -> state1)), "Warn only once per undefined symbol");
+ (["--warn-section-align"], ([], []), (fun _ -> (fun state1 -> state1)), "Warn if start of section changes due to alignment");
+ (["--warn-shared-textrel"], ([], []), (fun _ -> (fun state1 -> state1)), "Warn if shared object has DT_TEXTREL");
+ (["--warn-alternate-em"], ([], []), (fun _ -> (fun state1 -> state1)), "Warn if an object has alternate ELF machine code");
+ (["--warn-unresolved-symbols"], ([], []), (fun _ -> (fun state1 -> state1)), "Report unresolved symbols as warnings");
+ (* meta-options *)
+ (["--push-state"], ([], []), (fun _ -> (fun state1 -> state1)), "Push state of flags governing input file handling");
+ (["--pop-state"], ([], []), (fun _ -> (fun state1 -> state1)), "Pop state of flags governing input file handling")
+(*(["@FILE"], [], fun _ -> (fun state -> state), "Read options from FILE") *) (* processed during word-splitting phase *);
+])
+
+(*val delete_trailing_equals: string -> maybe string*)
+let delete_trailing_equals str:(string)option=
+ (let cs = (Xstring.explode str)
+ in
+ if (listEqualBy (=) ['='] (drop0 ( Nat_big_num.sub_nat(length cs)(Nat_big_num.of_int 1)) cs))
+ then Some (Xstring.implode ((take0 ( Nat_big_num.sub_nat(length cs)(Nat_big_num.of_int 1)) cs)))
+ else (* let _ = Missing_pervasives.errln ("No trailing equals: " ^ str)
+ in *)
+ None)
+
+(*val string_following_equals_at : nat -> string -> maybe string*)
+let string_following_equals_at pos str:(string)option=
+ (let (first, second) = (Lem_list.split_at pos (Xstring.explode str))
+ in (match second with
+ '=' :: rest -> Some (Xstring.implode rest)
+ | _ -> (* let _ = Missing_pervasives.errln ("No trailing equals at " ^ (show pos) ^ ": " ^ str)
+ in *)
+ None
+ ))
+
+(*val equal_modulo_trailing_equals : string -> string -> bool*)
+let equal_modulo_trailing_equals argstr argdef:bool=
+(
+ (* we allow argdef to have a trailing equals; if it does,
+ * we allow the argstring to have the equals (or not) and trailing stuff,
+ * which will become an arg *)let result = ((match (delete_trailing_equals argdef) with
+ Some matched ->
+ let following_equals = (string_following_equals_at (String.length matched) argstr)
+ in
+ (match following_equals with
+ Some following -> (* okay; does the pre-equals part match? *)
+ matched = Xstring.implode (Lem_list.take ( Nat_num.nat_monus(String.length argdef)( 1)) (Xstring.explode argstr))
+ | _ -> (* the argstr is allowed not to have a trailing equals *) argstr = matched
+ )
+ | None -> (* no trailing equals *) argdef = argstr
+ ))
+ in
+ (* let _ = Missing_pervasives.errln ("Do '" ^ argstr ^ "' and '" ^ argdef ^ "' match modulo trailing equals? " ^ (show result))
+ in *) result)
+
+
+(*val matching_arg_and_alias : string -> list option_def -> maybe (string * option_def)*)
+let rec matching_arg_and_alias arg options:(string*((string)list*((string)list*(string)list)*(option_argvals ->(command_state)list ->(command_state)list)*string))option= ((match options with
+ [] -> None
+ | (aliases, argspec, meaning, doc) :: more_opts ->
+ (match list_find_opt (fun alias -> equal_modulo_trailing_equals arg alias) aliases with
+ Some found_alias -> Some (found_alias, (aliases, argspec, meaning, doc))
+ | None -> matching_arg_and_alias arg more_opts
+ )
+ ))
+
+(* We don't try to convert from strings to other things here;
+ * everything we record is either a bool, meaning option -A was "present", for some A,
+ * or a string somearg, meaning option -A somearg was present, for some A. *)
+
+(* The above suffices to understand each concrete argument.
+ * Now we define an "interpreted command line" that includes
+ * some useful structure. *)
+
+(*val read_one_arg : list command_state -> list string -> (list command_state * list string)*)
+let read_one_arg state_stack args:(command_state)list*(string)list=
+(
+ (* Get the first string and look it up in our table. *)(match args with
+ [] -> (state_stack, [])
+ | some_arg :: more -> (match (matching_arg_and_alias some_arg command_line_table) with
+ (* We need to handle argdefs that have trailing equals. This means
+ * an extra arg might follow the equals. We need some helper functions. *)
+ Some (alias, (aliases, (argspec_extras, argspec_regex), meaning, doc)) ->
+ (* Return a new state, by applying the argument's meaning.
+ * We have to supply the option's argument strings to the meaning function. *)
+ let argstrings = (Lem_list.take (List.length argspec_extras) more)
+ in
+ let regex_matches = ((match delete_trailing_equals some_arg with
+ Some prefix ->
+ (match (string_following_equals_at ( Nat_num.nat_monus(String.length alias)( 1)) some_arg) with
+ Some following_equals -> [following_equals]
+ | None -> failwith "impossible: '=' not where it was a moment ago"
+ )
+ | None -> []
+ ))
+ in
+ let new_state_stack = (meaning (argstrings, regex_matches) state_stack)
+ in
+ (new_state_stack, drop0 (length argspec_extras) more)
+ | None ->
+ (* If we didn't match any args, we ought to be an input file. *)
+ (add_input_file state_stack some_arg, more)
+ )
+ ))
+
+(* To fold over the command-line arguments we need a fold that passes
+ * suffixes of the list, not individual elements, and gives us back
+ * the continuation that we need to fold over: a pair of folded-value, new-list. *)
+(*val foldl_suffix : forall 'a 'b. ('a -> list 'b -> ('a * list 'b)) -> 'a -> list 'b -> 'a*) (* originally foldl *)
+let rec foldl_suffix f a l:'a= ((match l with
+ | [] -> a
+ | x :: xs ->
+ let (new_a, new_list) = (f a l)
+ in foldl_suffix f new_a new_list
+))
+
+(* the word-splitting in argv needs a little fixing up. *)
+(*val cook_argv : list string -> list string -> list string*)
+let rec cook_argv acc args:(string)list=
+ ((match args with
+ [] -> acc
+ | "-z" :: more -> (match more with
+ [] -> failwith "-z must be followed by another argument"
+ | something :: yetmore -> cook_argv ( List.rev_append (List.rev acc) [("-z " ^ something)]) yetmore
+ )
+ | something :: more -> cook_argv ( List.rev_append (List.rev acc) [something]) more
+ ))
+
+(*val command_line : unit -> interpreted_command_line*)
+let command_line:unit ->(input_unit)list*(link_option)Pset.set= (fun _ -> (
+ let cooked_argv = (cook_argv [] (List.tl Ml_bindings.argv_list))
+ in
+ (* Now we use our fold-alike. *)
+ (match foldl_suffix read_one_arg initial_state0 cooked_argv with
+ state1 :: rest_of_stack -> (state1.input_units, state1.link_options)
+ | _ -> failwith "no command state left"
+ )
+))