123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671(*Generated by Lem from command_line.lem.*)openLem_basic_classesopenLem_functionopenLem_stringopenLem_string_extraopenLem_tupleopenLem_boolopenLem_listopenLem_list_extra(*import Set*)(*import Set_extra*)openLem_sortingopenLem_numopenLem_maybeopenLem_assert_extraopenByte_sequenceopenDefault_printingopenErroropenMissing_pervasivesopenShow(* 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.
*)typeinput_file_spec=Filenameofstring(* /path/to/file.{o,a,so,...} -- might be script! *)|Libnameofstring(* -llib *)(*val string_of_input_file_spec : input_file_spec -> string*)letstring_of_input_file_specspec:string=((matchspecwithFilename(s)->"file `"^(s^"'")|Libname(s)->"library `"^(s^"'")))letinstance_Show_Show_Command_line_input_file_spec_dict:(input_file_spec)show_class=({show_method=string_of_input_file_spec})typeinput_file_options={input_fmt:string;input_libpath:stringlist;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*)letnull_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})typeoutput_kind=Executable|SharedLibrarytypelink_option=OutputFilenameofstring|OutputKindofoutput_kind|ForceCommonDefinedofbool(* -d, -dc, -dp *)|Sonameofstring(* -soname *)|EntryAddressofNat_big_num.num|TextSegmentStartofNat_big_num.num|RodataSegmentStartofNat_big_num.num|LdataSegmentStartofNat_big_num.num|BindFunctionsEarly(* -Bsymbolic-functions *)|BindNonFunctionsEarly(* the remainder of -Bsymbolic *)(* more here! *)(*val tagEqual : link_option -> link_option -> bool*)lettagEqualopt1opt2: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. *)letinstance_Basic_classes_Eq_Command_line_link_option_dict:(link_option)eq_class=({isEqual_method=(funopt1->(funopt2->(match(opt1,opt2)with|(OutputFilename(_),OutputFilename(_))->true|(ForceCommonDefined(_),ForceCommonDefined(_))->true|(Soname(_),Soname(_))->true|(EntryAddress(_),EntryAddress(_))->true|_->false)));isInequal_method=(funopt1->(funopt2->not(((funopt1->(funopt2->(match(opt1,opt2)with|(OutputFilename(_),OutputFilename(_))->true|(ForceCommonDefined(_),ForceCommonDefined(_))->true|(Soname(_),Soname(_))->true|(EntryAddress(_),EntryAddress(_))->true|_->false)))opt1opt2))))})typeinput_file_and_options=input_file_spec*input_file_optionstypeinput_unit=Fileofinput_file_and_options|Groupof(input_file_and_options)list(* NOT recursive *)|BuiltinControlScript(* for uniformity when processing script defs *)(*val string_of_input_unit : input_unit -> string*)letstring_of_input_unitu:string=((matchuwithFile(spec,opts)->"single "^(string_of_input_file_specspec)|Group(spec_opt_list)->"group: ["^((string_of_listinstance_Show_Show_Command_line_input_file_spec_dict(Lem_list.map(fun(spec,opts)->spec)spec_opt_list))^"]")|BuiltinControlScript->"(built-in control script)"))letinstance_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. *)typecommand_state={input_units:input_unitlist;link_options:link_optionPset.set;current_input_options:input_file_options;current_group:(input_file_and_optionslist)option}(* This is the "default state" when we start reading input options *)(*val initial_state : list command_state*)(* the stack *)letinitial_state0:(command_state)list=([{input_units=([]);link_options=(Pset.from_listcompare[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}])typeinterpreted_command_line=input_unitlist*link_optionPset.set(*val add_input_file : list command_state -> string -> list command_state*)letadd_input_file(state1::more)s:(command_state)list=(letchars=(Xstring.explodes)inletspec=((matchcharswith'-'::'l'::more->Libname(Xstring.implodemore)|'-'::more->failwith("not a valid option or input file: "^s)|_->Filename(s)))inif(Lem.option_equal(listEqualBy(Lem.pair_equal(=)(=)))state1.current_groupNone)then{input_units=(List.rev_append(List.revstate1.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)}::moreelse{input_units=(state1.input_units);link_options=(state1.link_options);current_input_options=(state1.current_input_options);current_group=(lettoAppend=([(spec,state1.current_input_options)])in(matchstate1.current_groupwithSomel->Some(List.rev_append(List.revl)toAppend)|None->Some(toAppend)))}::more)(*val start_group : list command_state -> list command_state*)letstart_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=((matchstate1.current_groupwithNone->Some[]|_->failwith"cannot nest groups"))}::more)(*val end_group : list command_state -> list command_state*)letend_group(state1::more):(command_state)list=({input_units=(List.rev_append(List.revstate1.input_units)((matchstate1.current_groupwithSomel->[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)typeoption_token=stringtypeoption_argspecs=stringlist*stringlisttypeoption_argvals=stringlist*stringlist(*val set_or_replace_option : link_option -> list command_state -> list command_state*)letset_or_replace_optionoptstate_list:(command_state)list=((matchstate_listwith[]->failwith"error: no state"|state1::more->{input_units=(state1.input_units);link_options=(Pset.addopt(Pset.filter(funexisting->((funopt1->(funopt2->not(((funopt1->(funopt2->(match(opt1,opt2)with|(OutputFilename(_),OutputFilename(_))->true|(ForceCommonDefined(_),ForceCommonDefined(_))->true|(Soname(_),Soname(_))->true|(EntryAddress(_),EntryAddress(_))->true|_->false)))opt1opt2))))existingopt))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*)letrecfind_option_matching_tagtagoptions:(link_option)option=(Lem_list.list_find_opt(tagEqualtag)(Pset.elementsoptions))(*val extract_hex_addend : char -> maybe natural*)letextract_hex_addendx:(Nat_big_num.num)option=(ifx='0'thenSome((Nat_big_num.of_int0))elseifx='1'thenSome((Nat_big_num.of_int1))elseifx='2'thenSome((Nat_big_num.of_int2))elseifx='3'thenSome((Nat_big_num.of_int3))elseifx='4'thenSome((Nat_big_num.of_int4))elseifx='5'thenSome((Nat_big_num.of_int5))elseifx='6'thenSome((Nat_big_num.of_int6))elseifx='7'thenSome((Nat_big_num.of_int7))elseifx='8'thenSome((Nat_big_num.of_int8))elseifx='9'thenSome((Nat_big_num.of_int9))elseifx='a'thenSome((Nat_big_num.of_int10))elseifx='b'thenSome((Nat_big_num.of_int11))elseifx='c'thenSome((Nat_big_num.of_int12))elseifx='d'thenSome((Nat_big_num.of_int13))elseifx='e'thenSome((Nat_big_num.of_int14))elseifx='f'thenSome((Nat_big_num.of_int15))elseNone)(*val accumulate_hex_chars : natural -> list char -> natural*)letrecaccumulate_hex_charsaccchars:Nat_big_num.num=((matchcharswith|[]->acc|x::xs->(matchextract_hex_addendxwith|None->acc|Someaddend->accumulate_hex_chars(Nat_big_num.add(Nat_big_num.mulacc((Nat_big_num.of_int16)))addend)xs)))(*val extract_dec_addend : char -> maybe natural*)letextract_dec_addendx:(Nat_big_num.num)option=(ifx='0'thenSome((Nat_big_num.of_int0))elseifx='1'thenSome((Nat_big_num.of_int1))elseifx='2'thenSome((Nat_big_num.of_int2))elseifx='3'thenSome((Nat_big_num.of_int3))elseifx='4'thenSome((Nat_big_num.of_int4))elseifx='5'thenSome((Nat_big_num.of_int5))elseifx='6'thenSome((Nat_big_num.of_int6))elseifx='7'thenSome((Nat_big_num.of_int7))elseifx='8'thenSome((Nat_big_num.of_int8))elseifx='9'thenSome((Nat_big_num.of_int9))elseNone)(*val accumulate_dec_chars : natural -> list char -> natural*)letrecaccumulate_dec_charsaccchars:Nat_big_num.num=((matchcharswith|[]->acc|x::xs->(matchextract_dec_addendxwith|None->acc|Someaddend->accumulate_hex_chars(Nat_big_num.add(Nat_big_num.mulacc((Nat_big_num.of_int16)))addend)xs)))(*val parse_address : string -> natural*)letparse_addresss:Nat_big_num.num=((matchXstring.explodeswith'0'::'x'::more->accumulate_hex_chars((Nat_big_num.of_int0))more|chars->accumulate_dec_chars((Nat_big_num.of_int0))chars))typeoption_def=(option_tokenlist)*option_argspecs*(option_argvals->command_statelist->command_statelist)*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*)letcommand_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"],[]),(funargs->(funstate1->state1)),"Specify target for following input files");(["-L";"--library-path"],(["DIRECTORY"],[]),(funargs->(funstate1->state1)),"Add DIRECTORY to library search path");(["--as-needed"],([],[]),(fun_->(funstate1->state1)),"Only set DT_NEEDED for following dynamic libs if used");(["--no-as-needed"],([],[]),(fun_->(funstate1->state1)),"Always set DT_NEEDED for dynamic libraries mentioned on the command line");(["-Bdynamic";"-dy";"-call_shared"],([],[]),(fun_->(funstate1->state1)),"Link against shared libraries");(["-Bstatic";"-dn";"-non_shared";"-static"],([],[]),(fun_->(funstate1->state1)),"Do not link against shared libraries");(["--check-sections"],([],[]),(fun_->(funstate1->state1)),"Check section addresses for overlaps (default) **srk** not sure it's per-input!");(["--no-check-sections"],([],[]),(fun_->(funstate1->state1)),"Do not check section addresses for overlaps **srk** not sure it's per-input!");(["--copy-dt-needed-entries"],([],[]),(fun_->(funstate1->state1)),"Copy DT_NEEDED links mentioned inside DSOs that follow");(["--no-copy-dt-needed-entries"],([],[]),(fun_->(funstate1->state1)),"Do not copy DT_NEEDED links mentioned inside DSOs that follow");(["--no-whole-archive"],([],[]),(fun_->(funstate1->state1)),"Turn off --whole-archive");(["-rpath-link"],(["PATH"],[]),(fun_->(funstate1->state1)),"Set link time shared library search path **srk** not sure it's per-input!");(["--whole-archive"],([],[]),(fun_->(funstate1->state1)),"Include all objects from following archives");(* linker plugin control *)(["-plugin"],(["PLUGIN"],[]),(fun_->(funstate1->state1)),"Load named plugin");(["-plugin-opt"],(["ARG"],[]),(fun_->(funstate1->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_->(funstate1->state1)),"Set architecture");(["-EB"],([],[]),(fun_->(funstate1->state1)),"Link big-endian objects");(["-EL"],([],[]),(fun_->(funstate1->state1)),"Link little-endian objects");(["-R";"--just-symbols"],(["DIR"],[]),(fun_->(funstate1->state1)),"**srk** (if directory, same as --rpath)");(["-d";"-dc";"-dp"],([],[]),(fun_->(funstate1->state1)),"Force common symbols to be defined");(["-e";"--entry"],(["ADDRESS"],[]),(fun_->(funstate1->state1)),"Set start address");(["-E";"--export-dynamic"],([],[]),(fun_->(funstate1->state1)),"Export all dynamic symbols");(["--no-export-dynamic"],([],[]),(fun_->(funstate1->state1)),"Undo the effect of --export-dynamic");(["-f";"--auxiliary"],(["SHLIB"],[]),(fun_->(funstate1->state1)),"Auxiliary filter for shared object symbol table");(["-F";"--filter"],(["SHLIB"],[]),(fun_->(funstate1->state1)),"Filter for shared object symbol table");(["-G";"--gpsize"],(["SIZE"],[]),(fun_->(funstate1->state1)),"Small data size (if no size, same as --shared) **srk NOTE this quirk!**");(["-h";"-soname"],(["FILENAME"],[]),(fun_->(funstate1->state1)),"Set internal name of shared library");(["-I";"--dynamic-linker"],(["PROGRAM"],[]),(fun_->(funstate1->state1)),"Set PROGRAM as the dynamic linker to use");(["--sysroot="],([],["DIRECTORY"]),(fun_->(funstate1->state1)),"Override the default sysroot location");(["-m"],(["EMULATION"],[]),(fun_->(funstate1->state1)),"Set emulation");(["-n";"--nmagic"],([],[]),(fun_->(funstate1->state1)),"Do not page align data");(["-N";"--omagic"],([],[]),(fun_->(funstate1->state1)),"Do not page align data, do not make text readonly");(["--no-omagic"],([],[]),(fun_->(funstate1->state1)),"Page align data, make text readonly");(["-o";"--output"],(["FILE"],[]),(funargvals->set_or_replace_option(OutputFilename(List.hd(fstargvals)))),"Set output file name");(["-O"],([],[]),(fun_->(funstate1->state1)),"Optimise output file");(["-q";"--emit-relocs"],([],[]),(fun_->(funstate1->state1)),"Generate relocations in final output");(["-r";"-i";"--relocatable"],([],[]),(fun_->(funstate1->state1)),"Generate relocatable output");(["-s";"--strip-all"],([],[]),(fun_->(funstate1->state1)),"Strip all symbols");(["-S";"--strip-debug"],([],[]),(fun_->(funstate1->state1)),"Strip debugging symbols");(["--strip-discarded"],([],[]),(fun_->(funstate1->state1)),"Strip symbols in discarded sections");(["--no-strip-discarded"],([],[]),(fun_->(funstate1->state1)),"Do not strip symbols in discarded sections");(["--default-script";"-dT"],(["FILE"],[]),(fun_->(funstate1->state1)),"Read default linker script");(["--unique="],([],["SECTION"]),(fun_->(funstate1->state1)),"Don't merge input [SECTION | orphan] sections");(["-Ur"],([],[]),(fun_->(funstate1->state1)),"Build global constructor/destructor tables ( **srk**: like -r, but... )");(["-x";"--discard-all"],([],[]),(fun_->(funstate1->state1)),"Discard all local symbols");(["-X";"--discard-locals"],([],[]),(fun_->(funstate1->state1)),"Discard temporary local symbols (default)");(["--discard-none"],([],[]),(fun_->(funstate1->state1)),"Don't discard any local symbols");(["-Bsymbolic"],([],[]),(funargvals->(funstate1->set_or_replace_optionBindFunctionsEarly(set_or_replace_optionBindNonFunctionsEarlystate1))),"Bind global references locally");(["-Bsymbolic-functions"],([],[]),(funargvals->set_or_replace_option(BindFunctionsEarly)),"Bind global function references locally");(["--force-exe-suffix"],([],[]),(fun_->(funstate1->state1)),"Force generation of file with .exe suffix");(["--gc-sections"],([],[]),(fun_->(funstate1->state1)),"**srk: uncertain: can repeat?** Remove unused sections (on some targets)");(["--no-gc-sections"],([],[]),(fun_->(funstate1->state1)),"**srk: uncertain: can repeat?** Don't remove unused sections (default)");(["--hash-size="],([],["NUMBER"]),(fun_->(funstate1->state1)),"Set default hash table size close to <NUMBER>");(["--no-define-common"],([],[]),(fun_->(funstate1->state1)),"Do not define Common storage");(["--no-undefined"],([],[]),(fun_->(funstate1->state1)),"Do not allow unresolved references in object files");(["--allow-shlib-undefined"],([],[]),(fun_->(funstate1->state1)),"Allow unresolved references in shared libraries");(["--no-allow-shlib-undefined"],([],[]),(fun_->(funstate1->state1)),"Do not allow unresolved references in shared libs");(["--default-symver"],([],[]),(fun_->(funstate1->state1)),"Create default symbol version");(["--default-imported-symver"],([],[]),(fun_->(funstate1->state1)),"Create default symbol version for imported symbols");(["-nostdlib"],([],[]),(fun_->(funstate1->state1)),"Only use library directories specified on the command line");(["--oformat"],(["TARGET"],[]),(fun_->(funstate1->state1)),"Specify target of output file");(["--relax"],([],[]),(fun_->(funstate1->state1)),"Reduce code size by using target specific optimisations");(["--no-relax"],([],[]),(fun_->(funstate1->state1)),"Do not use relaxation techniques to reduce code size");(["--retain-symbols-file"],(["FILE"],[]),(fun_->(funstate1->state1)),"Keep only symbols listed in FILE");(["-rpath"],(["PATH"],[]),(fun_->(funstate1->state1)),"Set runtime shared library search path");(["-shared";"-Bshareable"],([],[]),(funargvals->set_or_replace_option(OutputKind(SharedLibrary))),"Create a shared library");(["-pie";"--pic-executable"],([],[]),(fun_->(funstate1->state1)),"Create a position independent executable");(["--sort-common="],(* (ascending|descending) *)([],["order"]),(fun_->(funstate1->state1)),"Sort common symbols by alignment [in specified order]");(["--sort-section="],(* (name|alignment) *)([],["key"]),(fun_->(funstate1->state1)),"Sort sections by name or maximum alignment");(["--spare-dynamic-tags"],(["COUNT"],[]),(fun_->(funstate1->state1)),"How many tags to reserve in .dynamic section");(["--split-by-file="],([],["SIZE"]),(fun_->(funstate1->state1)),"Split output sections every SIZE octets");(["--split-by-reloc="],([],["COUNT"]),(fun_->(funstate1->state1)),"Split output sections every COUNT relocs");(["--traditional-format"],([],[]),(fun_->(funstate1->state1)),"Use same format as native linker");(["--unresolved-symbols="],([],["method"]),(fun_->(funstate1->state1)),"How to handle unresolved symbols. <method> is: ignore-all, report-all, ignore-in-object-files, ignore-in-shared-libs");(["--dynamic-list-data"],([],[]),(fun_->(funstate1->state1)),"Add data symbols to dynamic list");(["--dynamic-list-cpp-new"],([],[]),(fun_->(funstate1->state1)),"Use C++ operator new/delete dynamic list");(["--dynamic-list-cpp-typeinfo "],([],[]),(fun_->(funstate1->state1)),"Use C++ typeinfo dynamic list");(["--dynamic-list"],(["FILE"],[]),(fun_->(funstate1->state1)),"Read dynamic list");(["--wrap"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Use wrapper functions for SYMBOL");(* the following are specific to ELF emulations *)(["--audit=(.*)"],([],["AUDITLIB"]),(fun_->(funstate1->state1)),"Specify a library to use for auditing");(["-Bgroup"],([],[]),(fun_->(funstate1->state1)),"Selects group name lookup rules for DSO");(["--build-id="],([],["STYLE"]),(fun_->(funstate1->state1)),"Generate build ID note");(["-P"],(["AUDITLIB"],[]),(fun_->(funstate1->state1)),"Specify a library to use for auditing dependencies");(["--depaudit="],([],["AUDITLIB"]),(fun_->(funstate1->state1)),"Specify a library to use for auditing dependencies");(["--disable-new-dtags"],([],[]),(fun_->(funstate1->state1)),"Disable new dynamic tags");(["--enable-new-dtags"],([],[]),(fun_->(funstate1->state1)),"Enable new dynamic tags");(["--eh-frame-hdr"],([],[]),(fun_->(funstate1->state1)),"Create .eh_frame_hdr section");(["--exclude-libs="],([],["LIBS"]),(fun_->(funstate1->state1)),"Make all symbols in LIBS hidden");(["--hash-style="],([],["STYLE"]),(fun_->(funstate1->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_->(funstate1->state1)),"Merge dynamic relocs into one section and sort");(["-z common-page-size="],([],["SIZE"]),(fun_->(funstate1->state1)),"Set common page size to SIZE");(["-z defs"],([],[]),(fun_->(funstate1->state1)),"Report unresolved symbols in object files.");(["-z execstack"],([],[]),(fun_->(funstate1->state1)),"Mark executable as requiring executable stack");(["-z global"],([],[]),(fun_->(funstate1->state1)),"Make symbols in DSO available for subsequently loaded objects");(["-z initfirst"],([],[]),(fun_->(funstate1->state1)),"Mark DSO to be initialized first at runtime");(["-z interpose"],([],[]),(fun_->(funstate1->state1)),"Mark object to interpose all DSOs but executable");(["-z lazy"],([],[]),(fun_->(funstate1->state1)),"Mark object lazy runtime binding (default)");(["-z loadfltr"],([],[]),(fun_->(funstate1->state1)),"Mark object requiring immediate process");(["-z max-page-size="],([],["SIZE"]),(fun_->(funstate1->state1)),"Set maximum page size to SIZE");(["-z nocombreloc"],([],[]),(fun_->(funstate1->state1)),"Don't merge dynamic relocs into one section");(["-z nocopyreloc"],([],[]),(fun_->(funstate1->state1)),"Don't create copy relocs");(["-z nodefaultlib"],([],[]),(fun_->(funstate1->state1)),"Mark object not to use default search paths");(["-z nodelete"],([],[]),(fun_->(funstate1->state1)),"Mark DSO non-deletable at runtime");(["-z nodlopen"],([],[]),(fun_->(funstate1->state1)),"Mark DSO not available to dlopen");(["-z nodump"],([],[]),(fun_->(funstate1->state1)),"Mark DSO not available to dldump");(["-z noexecstack"],([],[]),(fun_->(funstate1->state1)),"Mark executable as not requiring executable stack");(["-z norelro"],([],[]),(fun_->(funstate1->state1)),"Don't create RELRO program header");(["-z now"],([],[]),(fun_->(funstate1->state1)),"Mark object non-lazy runtime binding");(["-z origin"],([],[]),(fun_->(funstate1->state1)),"Mark object requiring immediate $ORIGIN processing at runtime");(["-z relro"],([],[]),(fun_->(funstate1->state1)),"Create RELRO program header");(["-z stacksize="],([],["SIZE"]),(fun_->(funstate1->state1)),"Set size of stack segment");(["-z bndplt"],([],[]),(fun_->(funstate1->state1)),"Always generate BND prefix in PLT entries");(["--ld-generated-unwind-info"],([],[]),(fun_->(funstate1->state1)),"Generate exception handling info for PLT.");(["--no-ld-generated-unwind-info"],([],[]),(fun_->(funstate1->state1)),"Don't do so.");(* quasi-input options (can be repeated): *)(["-c";"--mri-script"],(["FILE"],[]),(fun_->(funstate1->state1)),"Read MRI format linker script");(["-l";"--library"],(["LIBNAME"],[]),(fun_->(funstate1->state1)),"Search for library LIBNAME");(* (["-R" ,"--just-symbols"], (["FILE"], []), fun _ -> (fun state -> state), "Just link symbols"), *)(* Handled above! *)(["-T";"--script"],(["FILE"],[]),(fun_->(funstate1->state1)),"Read linker script");(["-u";"--undefined"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Start with undefined reference to SYMBOL");(["-(";"--start-group"],([],[]),(fun_->(funstate1->start_groupstate1)),"Start a group");(["-)";"--end-group"],([],[]),(fun_->(funstate1->end_groupstate1)),"End a group");(["--defsym"],(["SYMBOL=EXPRESSION"],[]),(fun_->(funstate1->state1)),"Define a symbol");(["-fini"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Call SYMBOL at unload-time");(["-init"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Call SYMBOL at load-time");(["--section-start"],(["SECTION=ADDRESS"],[]),(fun_->(funstate1->state1)),"Set address of named section");(["-Tbss"],(["ADDRESS"],[]),(fun_->(funstate1->state1)),"Set address of .bss section");(["-Tdata"],(["ADDRESS"],[]),(fun_->(funstate1->state1)),"Set address of .data section");(["-Ttext"],(["ADDRESS"],[]),(fun_->(funstate1->state1)),"Set address of .text section");(["-Ttext-segment"],(["ADDRESS"],[]),(funargvals->set_or_replace_option(TextSegmentStart(parse_address(List.hd(fstargvals))))),"Set address of text segment");(["-Trodata-segment"],(["ADDRESS"],[]),(funargvals->set_or_replace_option(RodataSegmentStart(parse_address(List.hd(fstargvals))))),"Set address of rodata segment");(["-Tldata-segment"],(["ADDRESS"],[]),(funargvals->set_or_replace_option(LdataSegmentStart(parse_address(List.hd(fstargvals))))),"Set address of ldata segment");(["--version-script"],(["FILE"],[]),(fun_->(funstate1->state1)),"Read version information script");(["--version-exports-section"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Take export symbols list from .exports, using SYMBOL as the version.");(* linker internal debugging/diagnostics and performance tuning *)(["-M";"--print-map"],([],[]),(fun_->(funstate1->state1)),"Print map file on standard output");(["-t";"--trace"],([],[]),(fun_->(funstate1->state1)),"Trace file opens");(["-v";"--version"],([],[]),(fun_->(funstate1->state1)),"Print version information");(["-V"],([],[]),(fun_->(funstate1->state1)),"Print version and emulation information");(["-y";"--trace-symbol"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Trace mentions of SYMBOL");(["--cref"],([],[]),(fun_->(funstate1->state1)),"Output cross reference table");(["--demangle="],([],["STYLE"]),(fun_->(funstate1->state1)),"Demangle symbol names [using STYLE]");(["--print-gc-sections"],([],[]),(fun_->(funstate1->state1)),"List removed unused sections on stderr");(["--no-print-gc-sections"],([],[]),(fun_->(funstate1->state1)),"Do not list removed unused sections");(["-Map"],(["FILE"],[]),(fun_->(funstate1->state1)),"Write a map file");(["-Map="],([],["FILE"]),(fun_->(funstate1->state1)),"Write a map file");(["--help"],([],[]),(fun_->(funstate1->state1)),"Print option help");(["--no-keep-memory"],([],[]),(fun_->(funstate1->state1)),"Use less memory and more disk I/O");(["--no-demangle"],([],[]),(fun_->(funstate1->state1)),"Do not demangle symbol names");(["--print-output-format"],([],[]),(fun_->(funstate1->state1)),"Print default output format");(["--print-sysroot"],([],[]),(fun_->(funstate1->state1)),"Print current sysroot");(["--reduce-memory-overheads"],([],[]),(fun_->(funstate1->state1)),"Reduce memory overheads, possibly taking much longer");(["--stats"],([],[]),(fun_->(funstate1->state1)),"Print memory usage statistics");(["--target-help"],([],[]),(fun_->(funstate1->state1)),"Display target specific options");(["--verbose="],([],["NUMBER"]),(fun_->(funstate1->state1)),"Output lots of information during link");(* unknown *)(["--embedded-relocs"],([],[]),(fun_->(funstate1->state1)),"Generate embedded relocs");(["--task-link"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Do task level linking");(* compatibility *)(["-a"],(["KEYWORD"],[]),(fun_->(funstate1->state1)),"Shared library control for HP/UX compatibility");(["-Y"],(["PATH"],[]),(fun_->(funstate1->state1)),"Default search path for Solaris compatibility");(* permissiveness controls (tightening/loosening) *)(["--accept-unknown-input-arch"],([],[]),(fun_->(funstate1->state1)),"Accept input files whose architecture cannot be determined");(["--no-accept-unknown-input-arch"],([],[]),(fun_->(funstate1->state1)),"Reject input files whose architecture is unknown");(["--fatal-warnings"],([],[]),(fun_->(funstate1->state1)),"Treat warnings as errors");(["--no-fatal-warnings"],([],[]),(fun_->(funstate1->state1)),"Do not treat warnings as errors (default)");(["--allow-multiple-definition"],([],[]),(fun_->(funstate1->state1)),"Allow multiple definitions");(["--no-undefined-version"],([],[]),(fun_->(funstate1->state1)),"Disallow undefined version");(["--noinhibit-exec"],([],[]),(fun_->(funstate1->state1)),"Create an output file even if errors occur");(["--error-unresolved-symbols"],([],[]),(fun_->(funstate1->state1)),"Report unresolved symbols as errors");(["--ignore-unresolved-symbol"],(["SYMBOL"],[]),(fun_->(funstate1->state1)),"Unresolved SYMBOL will not cause an error or warning");(* permissiveness, specific to ELF emulation *)(["-z muldefs"],([],[]),(fun_->(funstate1->state1)),"Allow multiple definitions");(* warnings (enabling/disabling) *)(["--no-warn-mismatch"],([],[]),(fun_->(funstate1->state1)),"Don't warn about mismatched input files");(["--no-warn-search-mismatch"],([],[]),(fun_->(funstate1->state1)),"Don't warn on finding an incompatible library");(["--warn-common"],([],[]),(fun_->(funstate1->state1)),"Warn about duplicate common symbols");(["--warn-constructors"],([],[]),(fun_->(funstate1->state1)),"Warn if global constructors/destructors are seen");(["--warn-multiple-gp"],([],[]),(fun_->(funstate1->state1)),"Warn if the multiple GP values are used");(["--warn-once"],([],[]),(fun_->(funstate1->state1)),"Warn only once per undefined symbol");(["--warn-section-align"],([],[]),(fun_->(funstate1->state1)),"Warn if start of section changes due to alignment");(["--warn-shared-textrel"],([],[]),(fun_->(funstate1->state1)),"Warn if shared object has DT_TEXTREL");(["--warn-alternate-em"],([],[]),(fun_->(funstate1->state1)),"Warn if an object has alternate ELF machine code");(["--warn-unresolved-symbols"],([],[]),(fun_->(funstate1->state1)),"Report unresolved symbols as warnings");(* meta-options *)(["--push-state"],([],[]),(fun_->(funstate1->state1)),"Push state of flags governing input file handling");(["--pop-state"],([],[]),(fun_->(funstate1->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*)letdelete_trailing_equalsstr:(string)option=(letcs=(Xstring.explodestr)inif(listEqualBy(=)['='](drop0(Nat_big_num.sub_nat(lengthcs)((Nat_big_num.of_int1)))cs))thenSome(Xstring.implode((take0(Nat_big_num.sub_nat(lengthcs)((Nat_big_num.of_int1)))cs)))else(* let _ = Missing_pervasives.errln ("No trailing equals: " ^ str)
in *)None)(*val string_following_equals_at : nat -> string -> maybe string*)letstring_following_equals_atposstr:(string)option=(let(first,second)=(Lem_list.split_atpos(Xstring.explodestr))in(matchsecondwith'='::rest->Some(Xstring.imploderest)|_->(* let _ = Missing_pervasives.errln ("No trailing equals at " ^ (show pos) ^ ": " ^ str)
in *)None))(*val equal_modulo_trailing_equals : string -> string -> bool*)letequal_modulo_trailing_equalsargstrargdef: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 *)letresult=((match(delete_trailing_equalsargdef)withSomematched->letfollowing_equals=(string_following_equals_at(String.lengthmatched)argstr)in(matchfollowing_equalswithSomefollowing->(* okay; does the pre-equals part match? *)matched=Xstring.implode(Lem_list.take(Nat_num.nat_monus(String.lengthargdef)1)(Xstring.explodeargstr))|_->(* 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)*)letrecmatching_arg_and_aliasargoptions:(string*((string)list*((string)list*(string)list)*(option_argvals->(command_state)list->(command_state)list)*string))option=((matchoptionswith[]->None|(aliases,argspec,meaning,doc)::more_opts->(matchlist_find_opt(funalias->equal_modulo_trailing_equalsargalias)aliaseswithSomefound_alias->Some(found_alias,(aliases,argspec,meaning,doc))|None->matching_arg_and_aliasargmore_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)*)letread_one_argstate_stackargs:(command_state)list*(string)list=((* Get the first string and look it up in our table. *)(matchargswith[]->(state_stack,[])|some_arg::more->(match(matching_arg_and_aliassome_argcommand_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. *)letargstrings=(Lem_list.take(List.lengthargspec_extras)more)inletregex_matches=((matchdelete_trailing_equalssome_argwithSomeprefix->(match(string_following_equals_at(Nat_num.nat_monus(String.lengthalias)1)some_arg)withSomefollowing_equals->[following_equals]|None->failwith"impossible: '=' not where it was a moment ago")|None->[]))inletnew_state_stack=(meaning(argstrings,regex_matches)state_stack)in(new_state_stack,drop0(lengthargspec_extras)more)|None->(* If we didn't match any args, we ought to be an input file. *)(add_input_filestate_stacksome_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 *)letrecfoldl_suffixfal:'a=((matchlwith|[]->a|x::xs->let(new_a,new_list)=(fal)infoldl_suffixfnew_anew_list))(* the word-splitting in argv needs a little fixing up. *)(*val cook_argv : list string -> list string -> list string*)letreccook_argvaccargs:(string)list=((matchargswith[]->acc|"-z"::more->(matchmorewith[]->failwith"-z must be followed by another argument"|something::yetmore->cook_argv(List.rev_append(List.revacc)[("-z "^something)])yetmore)|something::more->cook_argv(List.rev_append(List.revacc)[something])more))(*val command_line : unit -> interpreted_command_line*)letcommand_line:unit->(input_unit)list*(link_option)Pset.set=(fun_->(letcooked_argv=(cook_argv[](List.tlMl_bindings.argv_list))in(* Now we use our fold-alike. *)(matchfoldl_suffixread_one_arginitial_state0cooked_argvwithstate1::rest_of_stack->(state1.input_units,state1.link_options)|_->failwith"no command state left")))