ld_input: add support for archives

This commit is contained in:
Mikael Pettersson
2023-08-09 20:49:05 +02:00
parent f59cecaa6d
commit f6096ec45c
2 changed files with 72 additions and 6 deletions

View File

@@ -17,6 +17,19 @@
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
%%%
%%%=============================================================================
%%%
%%% - Process input files in the order given.
%%% - Maintain sets of currently defined and undefined symbols, initially empty
%%% and the entry symbol, respectiively.
%%% - An input object file is included unconditionally. Its symbol table is read
%%% and the sets of defined and undefined symbols are updated accordingly.
%%% - An input archive has its members processed in the order stored.
%%% - An input archive member is included if any only if the archive's symbol table
%%% indicates that the member defines some currently undefined symbol.
%%% - If an archive member is included it is processed exactly like an explicit
%%% input object file.
-module(ld_input).
@@ -25,6 +38,8 @@
]).
-include("ld_internal.hrl").
-include_lib("lib/include/archive.hrl").
-include_lib("lib/include/pdp10_ar.hrl").
%% error reasons
-define(badelf, badelf).
@@ -55,14 +70,58 @@ input([], _DefMap, UndefMap, Inputs) ->
end.
input_file(File, DefMap, UndefMap, Inputs) ->
case pdp10_stdio:fopen(File, [raw, read]) of
{ok, FP} ->
case archive:read(File) of
{ok, {FP, Archive}} ->
try
input_elf(File, FP, DefMap, UndefMap, Inputs)
input_archive(File, FP, Archive, DefMap, UndefMap, Inputs)
after
pdp10_stdio:fclose(FP)
end;
{error, Reason} -> mkerror({?badfile, File, Reason})
{error, _} ->
case pdp10_stdio:fopen(File, [raw, read]) of
{ok, FP} ->
try
input_elf(File, FP, DefMap, UndefMap, Inputs)
after
pdp10_stdio:fclose(FP)
end;
{error, Reason} -> mkerror({?badfile, File, Reason})
end
end.
%% Process input archive =======================================================
input_archive(File, FP, Archive, DefMap, UndefMap, Inputs) ->
#archive{symtab = SymTab, members = Members} = Archive,
%% Build a mapping from member offset to the set of symbols defined there.
OffsetToDefs =
lists:foldl(
fun({Symbol, Offset}, Map) ->
Symbols = maps:get(Offset, Map, #{}),
maps:put(Offset, maps:put(Symbol, false, Symbols), Map)
end, maps:new(), SymTab),
input_archive(Members, OffsetToDefs, File, FP, DefMap, UndefMap, Inputs).
input_archive(_Members = [], _OffsetToDefs, _File, _FP, DefMap, UndefMap, Inputs) ->
{ok, {DefMap, UndefMap, Inputs}};
input_archive([Member | Members], OffsetToDefs, File, FP, DefMap, UndefMap, Inputs) ->
case input_member(Member, OffsetToDefs, File, FP, DefMap, UndefMap) of
false ->
input_archive(Members, OffsetToDefs, File, FP, DefMap, UndefMap, Inputs);
{ok, {NewDefMap, NewUndefMap, Input}} ->
input_archive(Members, OffsetToDefs, File, FP, NewDefMap, NewUndefMap, [Input | Inputs]);
{error, _Reason} = Error -> Error
end.
input_member(Member, OffsetToDefs, File, FP, DefMap, UndefMap) ->
#member{arhdr = ArHdr, location = HdrOffset} = Member,
MemberDefs = maps:get(HdrOffset, OffsetToDefs, #{}),
case maps:size(maps:intersect(MemberDefs, UndefMap)) of
0 -> false;
_ ->
Offset = HdrOffset + ?PDP10_ARHDR_SIZEOF,
#arhdr{ar_name = Name, ar_size = Size} = ArHdr,
input_elf({File, Name, Offset, Size}, FP, Offset, Offset + Size, DefMap, UndefMap)
end.
%% Process input object file ===================================================

View File

@@ -1,7 +1,7 @@
%%% -*- erlang-indent-level: 2 -*-
%%%
%%% internal declarations for pdp10-elf ld.
%%% Copyright (C) 2020 Mikael Pettersson
%%% Copyright (C) 2020-2023 Mikael Pettersson
%%%
%%% This file is part of pdp10-tools.
%%%
@@ -23,8 +23,15 @@
-include_lib("lib/include/pdp10_elf36.hrl").
-type ifile() :: string() % explicit input .o-file
| { Archive :: string() % archive name
, Name :: string() % member name
, Offset :: non_neg_integer() % member data (not header) at this offset
, Size :: non_neg_integer() % member data size
}.
-record(input,
{ file :: string()
{ file :: ifile()
, shtab :: [#elf36_Shdr{}]
, symtab :: [#elf36_Sym{}]
, stshndx :: non_neg_integer()