mirror of
https://github.com/mikpe/pdp10-tools.git
synced 2026-01-22 18:42:34 +00:00
ld: top-level structure, options processing
This commit is contained in:
parent
de6db33f71
commit
d712c86cf7
@ -21,7 +21,7 @@ REBAR3=$(shell type -p rebar3 || echo ./rebar3)
|
||||
REBAR3_GIT=https://github.com/erlang/rebar3.git
|
||||
REBAR3_VSN=3.7.5
|
||||
|
||||
PROGRAMS=8to9 ar as nm od readelf
|
||||
PROGRAMS=8to9 ar as ld nm od readelf
|
||||
|
||||
default: compile link
|
||||
|
||||
|
||||
25
erlang/apps/ld/src/ld.app.src
Normal file
25
erlang/apps/ld/src/ld.app.src
Normal file
@ -0,0 +1,25 @@
|
||||
%%% Copyright (C) 2020 Mikael Pettersson
|
||||
%%%
|
||||
%%% This file is part of pdp10-tools.
|
||||
%%%
|
||||
%%% pdp10-tools is free software: you can redistribute it and/or modify
|
||||
%%% it under the terms of the GNU General Public License as published by
|
||||
%%% the Free Software Foundation, either version 3 of the License, or
|
||||
%%% (at your option) any later version.
|
||||
%%%
|
||||
%%% pdp10-tools is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
%%% GNU General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
{application, ld,
|
||||
[{description, "'ld' clone for pdp10-elf"},
|
||||
{vsn, "0.1.0"},
|
||||
{registered, []},
|
||||
{applications, [kernel, stdlib, lib]},
|
||||
{env, []},
|
||||
{modules, []}
|
||||
]}.
|
||||
384
erlang/apps/ld/src/ld.erl
Normal file
384
erlang/apps/ld/src/ld.erl
Normal file
@ -0,0 +1,384 @@
|
||||
%%% -*- erlang-indent-level: 2 -*-
|
||||
%%%
|
||||
%%% 'ld' clone for pdp10-elf
|
||||
%%% Copyright (C) 2020 Mikael Pettersson
|
||||
%%%
|
||||
%%% This file is part of pdp10-tools.
|
||||
%%%
|
||||
%%% pdp10-tools is free software: you can redistribute it and/or modify
|
||||
%%% it under the terms of the GNU General Public License as published by
|
||||
%%% the Free Software Foundation, either version 3 of the License, or
|
||||
%%% (at your option) any later version.
|
||||
%%%
|
||||
%%% pdp10-tools is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
%%% GNU General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
-module(ld).
|
||||
-export([ main/1
|
||||
, format_error/1
|
||||
]).
|
||||
|
||||
-define(EMULATION, "elf36_pdp10").
|
||||
-define(OBJFORMAT, "elf36-pdp10").
|
||||
|
||||
-record(options,
|
||||
{ entry = "_start" :: string()
|
||||
, files = [] :: [{file, string()} | {library, string()}]
|
||||
, fini = "_fini" :: string()
|
||||
, init = "_init" :: string()
|
||||
, library_path = [] :: [string()]
|
||||
, output = "a.out" :: string()
|
||||
, page_align_sections = false :: boolean()
|
||||
, rwtext = false :: boolean()
|
||||
, section_starts = [] :: [{string(), integer()}]
|
||||
, trace = 0 :: non_neg_integer()
|
||||
}).
|
||||
|
||||
%% Command-line interface ======================================================
|
||||
|
||||
main(Argv) ->
|
||||
escript_runtime:start(fun main_/1, Argv).
|
||||
|
||||
-spec main_([string()]) -> no_return().
|
||||
main_(Argv) ->
|
||||
case ld(Argv) of
|
||||
ok -> halt(0);
|
||||
{error, Reason} ->
|
||||
escript_runtime:fatal("~s\n", [error:format(Reason)])
|
||||
end.
|
||||
|
||||
ld(Argv) ->
|
||||
%% NYI options:
|
||||
%% @file
|
||||
%% -a
|
||||
%% --audit
|
||||
%% -c / --mri-script
|
||||
%% -d / -dc / -dp
|
||||
%% -P / --depaudit
|
||||
%% --exclude-libs
|
||||
%% --exclude-modules-for-imlib
|
||||
%% -E / --[no-]export-dynamic
|
||||
%% -EL
|
||||
%% -f / --auxiliary
|
||||
%% -F / --filter
|
||||
%% -g
|
||||
%% -G / --gpsize
|
||||
%% -h / -soname
|
||||
%% -M / --print-map
|
||||
%% --[no-]print-map-discarded
|
||||
%% -O
|
||||
%% -plugin
|
||||
%% --push-state / --pop-state
|
||||
%% -q / --emit-relocs
|
||||
%% --force-dynamic
|
||||
%% -r / --relocatable / -i
|
||||
%% -R / --just-symbols
|
||||
%% -s / --strip-all
|
||||
%% -S / --strip-debug
|
||||
%% --[no-]strip-discarded
|
||||
%% -T / --script
|
||||
%% -dT / --default-script
|
||||
%% -u / --undefined
|
||||
%% --require-defined
|
||||
%% -Ur
|
||||
%% --orphan-handling
|
||||
%% --unique
|
||||
%% -x / --discard-all
|
||||
%% -X / --discard-locals
|
||||
%% -y / --trace-symbol
|
||||
%% -Y
|
||||
%% -z
|
||||
%% -( / -) / --start-group / --end-group
|
||||
%% --[no-]accept-unknown-input-arch
|
||||
%% --[no-]as-needed
|
||||
%% -assert
|
||||
%% -Bdynamic / -dy / -call_shared
|
||||
%% -Bgroup
|
||||
%% -Bstatic / -dn / -non_shared / -static
|
||||
%% -Bsymbolic
|
||||
%% -Bsymbolic-functions
|
||||
%% --dynamic-list
|
||||
%% --dynamic-list-data
|
||||
%% --dynamic-list-cpp-new
|
||||
%% --dynamic-list-cpp-typeinfo
|
||||
%% --[no-]check-sections
|
||||
%% --[no-]copy-dt-needed-entries / --[no-]add-needed
|
||||
%% --cref
|
||||
%% --no-define-common
|
||||
%% --force-group-allocation
|
||||
%% --defsym
|
||||
%% --[no-]demangle
|
||||
%% -I / --dynamic-linker
|
||||
%% --no-dynamic-linker
|
||||
%% --embedded-relocs
|
||||
%% --disable-multiple-abs-defs
|
||||
%% --[no-]fatal-warnings
|
||||
%% --force-exe-suffix
|
||||
%% --[no-]gc-sections
|
||||
%% --[no-]print-gc-sections
|
||||
%% --gc-keep-exported
|
||||
%% --print-memory-usage
|
||||
%% -Map
|
||||
%% --no-keep-memory
|
||||
%% --no-undefined / -z defs
|
||||
%% --allow-multiple-definitions / -z muldefs
|
||||
%% --[no-]allow-shlib-undefined
|
||||
%% --no-undefined-version
|
||||
%% --default-symver
|
||||
%% --default-imported-symver
|
||||
%% --no-warn-mismatch
|
||||
%% --no-warn-search-mismatch
|
||||
%% --noinhibit-exec
|
||||
%% -nostdlib
|
||||
%% --out-implib
|
||||
%% -pie / --pic-executable
|
||||
%% -qmagic
|
||||
%% -Qy
|
||||
%% --[no-]relax
|
||||
%% --retain-symbols-file
|
||||
%% -rpath
|
||||
%% -rpath-link
|
||||
%% -shared / -Bshareable
|
||||
%% --sort-common
|
||||
%% --sort-section
|
||||
%% --spare-dynamic-tags
|
||||
%% --split-by-file
|
||||
%% --split-by-reloc
|
||||
%% --stats
|
||||
%% --sysroot
|
||||
%% --task-link
|
||||
%% --traditional-format
|
||||
%% -Tldata-segment
|
||||
%% --unresolved-symbols
|
||||
%% --dll-verbose / --verbose
|
||||
%% --version-script
|
||||
%% --warn-common
|
||||
%% --warn-constructors
|
||||
%% --warn-multiple-gp
|
||||
%% --warn-once
|
||||
%% --warn-section-align
|
||||
%% --warn-shared-textrel
|
||||
%% --warn-alternate-em
|
||||
%% --warn-unresolved-symbols / --error-unresolved-symbols
|
||||
%% --[no-]whole-archive
|
||||
%% --wrap
|
||||
%% --[no-]eh-frame-hdr
|
||||
%% --no-ld-generated-unwind-info
|
||||
%% --enable-new-dtags / --disable-new-dtags
|
||||
%% --hash-size
|
||||
%% --hash-style
|
||||
%% --compress-debug-sections
|
||||
%% --reduce-memory-overheads
|
||||
%% --build-id
|
||||
%% All other target-specific options.
|
||||
%%
|
||||
%% LD has quite archaic option syntax:
|
||||
%% - it takes some single-dash long options, e.g. -nostdlib
|
||||
%% - options and non-options must be processed in the order given,
|
||||
%% e.g. due to --start-group <file.o>... --end-group
|
||||
case getopt:parse(Argv, "-b:e:l:L:m:nNo:tvV",
|
||||
[ %% single-dash long options
|
||||
{ "-EB", no, 'EB' }
|
||||
, { "-fini", required, fini }
|
||||
, { "-init", required, init }
|
||||
, { "-Tbss", required, 'Tbss' }
|
||||
, { "-Tdata", required, 'Tdata' }
|
||||
, { "-Trodata-segment", required, 'Trodata' }
|
||||
, { "-Ttext", required, 'Ttext' }
|
||||
, { "-Ttext-segment", required, 'Ttext' }
|
||||
%% long-only options
|
||||
, { "help", no, help }
|
||||
, { "no-omagic", no, no_omagic }
|
||||
, { "oformat", required, oformat }
|
||||
, { "print-output-format", no, print_output_format }
|
||||
, { "section-start", required, section_start }
|
||||
, { "target-help", no, target_help }
|
||||
%% long aliases for short options
|
||||
, { "entry", required, $e }
|
||||
, { "format", required, $b }
|
||||
, { "library", required, $l }
|
||||
, { "library-path", required, $L }
|
||||
, { "nmagic", no, $n }
|
||||
, { "omagic", no, $N }
|
||||
, { "output", required, $o }
|
||||
, { "trace", no, $t }
|
||||
, { "version", no, $v }
|
||||
]) of
|
||||
{ok, {Opts, _NonOpts = []}} ->
|
||||
case process_options(Opts) of
|
||||
{ok, Options} ->
|
||||
%% FIXME: input(Options) -> {ok, _} | {error, _}
|
||||
{ok, TUnit} = input(Options),
|
||||
output(Options, TUnit);
|
||||
{error, _Reason} = Error -> Error
|
||||
end;
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
process_options(Opts) -> process_options(Opts, #options{}).
|
||||
|
||||
process_options([Opt | Opts], Options) ->
|
||||
case process_option(Opt, Options) of
|
||||
{ok, NewOptions} -> process_options(Opts, NewOptions);
|
||||
{error, _Reason} = Error -> Error
|
||||
end;
|
||||
process_options([], Options) ->
|
||||
#options{ files = Files, library_path = LibraryPath } = Options,
|
||||
{ok, Options#options{ files = lists:reverse(Files)
|
||||
, library_path = lists:reverse(LibraryPath)
|
||||
}}.
|
||||
|
||||
process_option(Opt, Options) ->
|
||||
case Opt of
|
||||
'EB' -> handle_EB(Opt, Options);
|
||||
{$m, _} -> handle_emulation(Opt, Options);
|
||||
{$e, _} -> handle_entry(Opt, Options);
|
||||
{fini, _} -> handle_fini(Opt, Options);
|
||||
{$b, _} -> handle_format(Opt, Options);
|
||||
help -> handle_help(Opt, Options);
|
||||
{init, _} -> handle_init(Opt, Options);
|
||||
{$l, _} -> handle_library(Opt, Options);
|
||||
{$L, _} -> handle_library_path(Opt, Options);
|
||||
$n -> handle_nmagic(Opt, Options);
|
||||
no_omagic -> handle_no_omagic(Opt, Options);
|
||||
{oformat, _} -> handle_oformat(Opt, Options);
|
||||
$N -> handle_omagic(Opt, Options);
|
||||
{$o, _} -> handle_output(Opt, Options);
|
||||
print_output_format -> handle_print_output_format(Opt, Options);
|
||||
{section_start, _} -> handle_section_start(Opt, Options);
|
||||
target_help -> handle_target_help(Opt, Options);
|
||||
{'Tbss', _} -> handle_Tbss(Opt, Options);
|
||||
{'Tdata', _} -> handle_Tdata(Opt, Options);
|
||||
$t -> handle_trace(Opt, Options);
|
||||
{'Trodata', _} -> handle_Trodata(Opt, Options);
|
||||
{'Ttext', _} -> handle_Ttext(Opt, Options);
|
||||
$V -> handle_V(Opt, Options);
|
||||
$v -> handle_version(Opt, Options)
|
||||
end.
|
||||
|
||||
%% Option Handlers =============================================================
|
||||
|
||||
handle_EB('EB', Options) ->
|
||||
{ok, Options}.
|
||||
|
||||
handle_emulation({$m, Emulation}, Options) ->
|
||||
case Emulation of
|
||||
?EMULATION -> {ok, Options};
|
||||
_ -> {error, {?MODULE, {invalid, emulation, Emulation}}}
|
||||
end.
|
||||
|
||||
handle_entry({$e, Entry}, Options) ->
|
||||
{ok, Options#options{entry = Entry}}.
|
||||
|
||||
handle_fini({fini, Fini}, Options) ->
|
||||
{ok, Options#options{fini = Fini}}.
|
||||
|
||||
handle_format({$b, InputFormat}, Options) ->
|
||||
case InputFormat of
|
||||
?OBJFORMAT -> {ok, Options};
|
||||
_ -> {error, {?MODULE, {invalid, "input format", InputFormat}}}
|
||||
end.
|
||||
|
||||
handle_help(help, _Options) ->
|
||||
io:format("--help: NYI\n"),
|
||||
exit(0).
|
||||
|
||||
handle_init({init, Init}, Options) ->
|
||||
{ok, Options#options{init = Init}}.
|
||||
|
||||
handle_library({$l, Library}, Options) ->
|
||||
{ok, Options#options{files = [{library, Library} | Options#options.files]}}.
|
||||
|
||||
handle_library_path({$L, Path}, Options) ->
|
||||
{ok, Options#options{library_path = [Path | Options#options.library_path]}}.
|
||||
|
||||
handle_nmagic($n, Options) ->
|
||||
{ok, Options#options{page_align_sections = false}}.
|
||||
|
||||
handle_no_omagic(no_omagic, Options) ->
|
||||
{ok, Options#options{rwtext = false, page_align_sections = true}}.
|
||||
|
||||
handle_oformat({oformat, OutputFormat}, Options) ->
|
||||
case OutputFormat of
|
||||
?OBJFORMAT -> {ok, Options};
|
||||
_ -> {error, {?MODULE, {invalid, "output format", OutputFormat}}}
|
||||
end.
|
||||
|
||||
handle_omagic($N, Options) ->
|
||||
{ok, Options#options{rwtext = true, page_align_sections = false}}.
|
||||
|
||||
handle_output({$o, Output}, Options) ->
|
||||
{ok, Options#options{output = Output}}.
|
||||
|
||||
handle_print_output_format(print_output_format, Options) ->
|
||||
io:format(?OBJFORMAT "\n"),
|
||||
{ok, Options}.
|
||||
|
||||
handle_section_start({section_start, Arg}, Options) ->
|
||||
case string:split(Arg, "=") of
|
||||
[Name, Org] -> section_start(Name, Org, Options);
|
||||
_ -> {error, {?MODULE, {invalid, "section-start", Arg}}}
|
||||
end.
|
||||
|
||||
handle_target_help(target_help, _Options) ->
|
||||
io:format("No target-specific options apply.\n"),
|
||||
exit(0).
|
||||
|
||||
handle_Tbss({'Tbss', Org}, Options) ->
|
||||
section_start(".bss", Org, Options).
|
||||
|
||||
handle_Tdata({'Tdata', Org}, Options) ->
|
||||
section_start(".data", Org, Options).
|
||||
|
||||
handle_trace($t, Options) ->
|
||||
{ok, Options#options{trace = Options#options.trace + 1}}.
|
||||
|
||||
handle_Trodata({'Trodata', Org}, Options) ->
|
||||
section_start(".rodata", Org, Options).
|
||||
|
||||
handle_Ttext({'Ttext', Org}, Options) ->
|
||||
section_start(".text", Org, Options).
|
||||
|
||||
handle_V($V, Options) ->
|
||||
version(),
|
||||
io:format(" Supported emulations:\n"),
|
||||
io:format(" " ?EMULATION "\n"),
|
||||
{ok, Options}.
|
||||
|
||||
handle_version($v, Options) ->
|
||||
version(),
|
||||
{ok, Options}.
|
||||
|
||||
section_start(Name, Org, Options) ->
|
||||
case strtol:parse(Org, _Base = 16) of
|
||||
{ok, {Value, _Rest = []}} ->
|
||||
SectionStarts = Options#options.section_starts,
|
||||
NewSectionStarts = lists:keystore(Name, 1, SectionStarts, {Name, Value}),
|
||||
{ok, Options#options{section_starts = NewSectionStarts}};
|
||||
_ -> {error, {?MODULE, {invalid, "org for section " ++ Name, Org}}}
|
||||
end.
|
||||
|
||||
version() ->
|
||||
io:format("pdp10-tools ld version 0.1\n").
|
||||
|
||||
%% Input Processing ============================================================
|
||||
|
||||
input(_Options) -> {ok, []}. % FIXME
|
||||
|
||||
%% Output Generation ===========================================================
|
||||
|
||||
output(_Options, []) -> ok. % FIXME
|
||||
|
||||
%% Error Formatting ============================================================
|
||||
|
||||
-spec format_error(term()) -> io_lib:chars().
|
||||
format_error(Reason) ->
|
||||
case Reason of
|
||||
{invalid, What, Parameter} ->
|
||||
io_lib:format("invalid ~s: ~s", [What, Parameter])
|
||||
end.
|
||||
@ -44,6 +44,7 @@
|
||||
{'8to9', main, 1}
|
||||
, {ar, main, 1}
|
||||
, {as, main, 1}
|
||||
, {ld, main, 1}
|
||||
, {nm, main, 1}
|
||||
, {od, main, 1}
|
||||
, {readelf, main, 1}
|
||||
@ -51,6 +52,7 @@
|
||||
, {assemble, format_error, 1}
|
||||
, {getopt, format_error, 1}
|
||||
, {input, format_error, 1}
|
||||
, {ld, format_error, 1}
|
||||
, {output, format_error, 1}
|
||||
, {parse, format_error, 1}
|
||||
, {pdp10_elf36, format_error, 1}
|
||||
@ -69,6 +71,7 @@
|
||||
[ {'8to9', [{escript_main_app, '8to9'}]}
|
||||
, {ar, [{escript_main_app, ar}]}
|
||||
, {as, [{escript_main_app, as}]}
|
||||
, {ld, [{escript_main_app, ld}]}
|
||||
, {nm, [{escript_main_app, nm}]}
|
||||
, {od, [{escript_main_app, od}]}
|
||||
, {readelf, [{escript_main_app, readelf}]}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user