From 6d5a4e61b5dd729e2aacd4ddff7f5cae1b093a25 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Thu, 10 Aug 2023 16:58:20 +0200 Subject: [PATCH] ld_phase1: cleanups --- erlang/apps/ld/src/ld_phase1.erl | 210 +++++++++++++++++-------------- 1 file changed, 117 insertions(+), 93 deletions(-) diff --git a/erlang/apps/ld/src/ld_phase1.erl b/erlang/apps/ld/src/ld_phase1.erl index d8cc73b..04d9a08 100644 --- a/erlang/apps/ld/src/ld_phase1.erl +++ b/erlang/apps/ld/src/ld_phase1.erl @@ -1,7 +1,7 @@ %%% -*- erlang-indent-level: 2 -*- %%% %%% linking phase 1 for pdp10-elf ld -%%% Copyright (C) 2020 Mikael Pettersson +%%% Copyright (C) 2020-2023 Mikael Pettersson %%% %%% This file is part of pdp10-tools. %%% @@ -17,6 +17,15 @@ %%% %%% You should have received a copy of the GNU General Public License %%% along with pdp10-tools. If not, see . +%%% +%%%============================================================================= +%%% +%%% Citing The System V Application Binary Interface, Ch. 4 Sections: +%%% "In the first phase, input sections that match in name, type and attribute +%%% flags should be concatenated into single sections. The concatenation order +%%% should satisfy the requirements of any known input section attributes (e.g, +%%% SHF_MERGE and SHF_LINK_ORDER). When not otherwise constrained, sections +%%% should be emitted in input order." -module(ld_phase1). @@ -25,41 +34,44 @@ -include("ld_internal.hrl"). +-record(section_key, + { sh_name :: string() + , sh_type :: non_neg_integer() + , sh_flags :: non_neg_integer() + }). + +-record(output, % accumulates fragments for a given section + { nr :: non_neg_integer() % determines output order + , shdr :: #elf36_Shdr{} + , frags :: [#sectfrag{}] + }). + +-type outputsmap() :: #{#section_key{} => #output{}}. + +-type relocsmap() :: #{non_neg_integer() => #elf36_Shdr{}}. + %% Linking Phase 1 ============================================================= -%% -%% Citing The System V Application Binary Interface, Ch. 4 Sections: -%% "In the first phase, input sections that match in name, type and attribute -%% flags should be concatenated into single sections. The concatenation order -%% should satisfy the requirements of any known input section attributes (e.g, -%% SHF_MERGE and SHF_LINK_ORDER). When not otherwise constrained, sections -%% should be emitted in input order." -spec phase1([#input{}]) -> [#section{}]. phase1(Inputs) -> - phase1(Inputs, _OutputMap = maps:new()). + OutputsMap = lists:foldl(fun phase1/2, _OutputsMap = maps:new(), Inputs), + UnsortedOutputs = maps:values(OutputsMap), + SortedOutputs = lists:keysort(#output.nr, UnsortedOutputs), + lists:map(fun output_to_section/1, SortedOutputs). -phase1([Input | Inputs], OutputsMap) -> +output_to_section(#output{shdr = Shdr, frags = Frags}) -> + #section{shdr = Shdr, frags = lists:reverse(Frags)}. + +-spec phase1(#input{}, outputsmap()) -> outputsmap(). +phase1(Input, OutputsMap0) -> #input{file = File, shtab = ShTab, stshndx = StShNdx} = Input, - NewOutputsMap = phase1(File, ShTab, StShNdx, OutputsMap), - phase1(Inputs, NewOutputsMap); -phase1([], OutputsMap) -> - Sections1 = maps:values(OutputsMap), - Sections2 = lists:map(fun({Nr, Shdr, Frags}) -> - {Nr, #section{shdr = Shdr, frags = lists:reverse(Frags)}} - end, Sections1), - Sections3 = lists:keysort(1, Sections2), - lists:map(fun({_Nr, Section}) -> Section end, Sections3). - -phase1(File, ShTab, StShNdx, OutputsMap) -> RelocsMap = relocs_map(ShTab, StShNdx), - phase1(ShTab, _ShNdx = 0, File, RelocsMap, OutputsMap). - -phase1([], _ShNdx, _File, _RelocsMap, OutputsMap) -> - OutputsMap; -phase1([Shdr | ShTab], ShNdx, File, RelocsMap, OutputsMap) -> - NewOutputsMap = - maybe_output_section(Shdr, ShNdx, File, RelocsMap, OutputsMap), - phase1(ShTab, ShNdx + 1, File, RelocsMap, NewOutputsMap). + {_NewShNdx, NewOutputsMap} = + lists:foldl( + fun(Shdr, {ShNdx, OutputsMap}) -> + {ShNdx + 1, maybe_output_section(Shdr, ShNdx, File, RelocsMap, OutputsMap)} + end, {_ShNdx = 0, OutputsMap0}, ShTab), + NewOutputsMap. maybe_output_section(Shdr, ShNdx, File, RelocsMap, OutputsMap) -> case should_output_section(Shdr) of @@ -67,71 +79,9 @@ maybe_output_section(Shdr, ShNdx, File, RelocsMap, OutputsMap) -> false -> OutputsMap end. -output_section(Shdr, ShNdx, File, RelocsMap, OutputsMap) -> - SectionKey = section_key(Shdr), - Output = output_get(SectionKey, OutputsMap, Shdr), - Relocs = maps:get(ShNdx, RelocsMap, false), - NewOutput = output_append(Output, File, Shdr, ShNdx, Relocs), - maps:put(SectionKey, NewOutput, OutputsMap). - -output_get(SectionKey, OutputsMap, Shdr) -> - case maps:get(SectionKey, OutputsMap, false) of - {_Nr, _Shdr, _Frags} = Output -> Output; - false -> - OutputShdr = Shdr#elf36_Shdr{ sh_addr = 0 - , sh_offset = 0 - , sh_size = 0 - , sh_link = 0 - , sh_info = 0 - , sh_addralign = 0 - }, - {_Nr = maps:size(OutputsMap), OutputShdr, _Frags = []} - end. - -output_append({Nr, OutputShdr, Frags}, File, Shdr, ShNdx, Relocs) -> - OutputAlignment = section_alignment(OutputShdr), - FragAlignment = section_alignment(Shdr), - NewAlignment = max(OutputAlignment, FragAlignment), - OutputSize = section_size(OutputShdr), - FragSize = section_size(Shdr), - FragOffset = align(OutputSize, FragAlignment), - NewSize = FragOffset + FragSize, - NewOutputShdr = OutputShdr#elf36_Shdr{ sh_size = NewSize - , sh_addralign = NewAlignment - }, - Frag = #sectfrag{file = File, shdr = Shdr, shndx = ShNdx, relocs = Relocs, offset = FragOffset}, - {Nr, NewOutputShdr, [Frag | Frags]}. - -section_alignment(Shdr) -> - case Shdr#elf36_Shdr.sh_addralign of - 0 -> 1; - Alignment -> Alignment - end. - -section_size(Shdr) -> - Shdr#elf36_Shdr.sh_size. - -align(Offset, Alignment) -> - (Offset + Alignment - 1) band bnot (Alignment - 1). - -relocs_map(ShTab, StShNdx) -> - lists:foldl(fun(Shdr, RelocsMap) -> relocs_map(Shdr, RelocsMap, StShNdx) end, - maps:new(), ShTab). - -relocs_map(Shdr, RelocsMap, StShNdx) -> % FIXME: ok | error - case Shdr of - #elf36_Shdr{sh_type = ?SHT_RELA, sh_link = Link, sh_info = Info} -> - Link = StShNdx, % assert - maps:put(Info, Shdr, RelocsMap); - #elf36_Shdr{} -> RelocsMap - end. - should_output_section(Shdr) -> #elf36_Shdr{sh_type = Type, sh_flags = Flags} = Shdr, - case should_output_type(Type) of - true -> should_output_flags(Flags); - false -> false - end. + should_output_type(Type) andalso should_output_flags(Flags). should_output_type(Type) -> case Type of @@ -153,6 +103,80 @@ should_output_flags(Flags) -> ?SHF_STRINGS bor ?SHF_TLS)) =:= 0. +%% Append a section to the outputs accumulator ================================= + +output_section(Shdr, ShNdx, File, RelocsMap, OutputsMap) -> + SectionKey = section_key(Shdr), + Output = output_get(SectionKey, OutputsMap, Shdr), + Relocs = relocs_get(ShNdx, RelocsMap), + NewOutput = output_append(Output, File, Shdr, ShNdx, Relocs), + maps:put(SectionKey, NewOutput, OutputsMap). + +output_get(SectionKey, OutputsMap, Shdr) -> + case maps:get(SectionKey, OutputsMap, false) of + false -> + OutputShdr = Shdr#elf36_Shdr{ sh_addr = 0 + , sh_offset = 0 + , sh_size = 0 + , sh_link = 0 + , sh_info = 0 + , sh_addralign = 0 + }, + #output{nr = maps:size(OutputsMap), shdr = OutputShdr, frags = []}; + Output -> Output + end. + +output_append(Output, File, Shdr, ShNdx, Relocs) -> + #output{shdr = OutputShdr, frags = Frags} = Output, + OutputAlignment = section_alignment(OutputShdr), + FragAlignment = section_alignment(Shdr), + NewAlignment = max(OutputAlignment, FragAlignment), + OutputSize = section_size(OutputShdr), + FragSize = section_size(Shdr), + FragOffset = align(OutputSize, FragAlignment), + NewSize = FragOffset + FragSize, + NewOutputShdr = OutputShdr#elf36_Shdr{ sh_size = NewSize + , sh_addralign = NewAlignment + }, + Frag = #sectfrag{file = File, shdr = Shdr, shndx = ShNdx, relocs = Relocs, offset = FragOffset}, + Output#output{shdr = NewOutputShdr, frags = [Frag | Frags]}. + +section_alignment(Shdr) -> + case Shdr#elf36_Shdr.sh_addralign of + 0 -> 1; + Alignment -> Alignment + end. + +section_size(Shdr) -> + Shdr#elf36_Shdr.sh_size. + +align(Offset, Alignment) -> + (Offset + Alignment - 1) band bnot (Alignment - 1). + section_key(Shdr) -> #elf36_Shdr{sh_name = Name, sh_type = Type, sh_flags = Flags} = Shdr, - {Name, Type, Flags}. + #section_key{sh_name = Name, sh_type = Type, sh_flags = Flags}. + +%% Relocs Map ================================================================== +%% +%% The Relocs Map is a mapping from a section's section header index to the section +%% header for the SHT_RELA which applies to that section, if any. + +-spec relocs_map([#elf36_Shdr{}], non_neg_integer()) -> relocsmap(). +relocs_map(ShTab, StShNdx) -> + lists:foldl( + fun(Shdr, RelocsMap) -> + relocs_map(Shdr, RelocsMap, StShNdx) + end, maps:new(), ShTab). + +relocs_map(Shdr, RelocsMap, StShNdx) -> % FIXME: ok | error + case Shdr of + #elf36_Shdr{sh_type = ?SHT_RELA, sh_link = Link, sh_info = Info} -> + Link = StShNdx, % assert + maps:put(Info, Shdr, RelocsMap); + #elf36_Shdr{} -> RelocsMap + end. + +-spec relocs_get(non_neg_integer(), relocsmap()) -> #elf36_Shdr{} | false. +relocs_get(ShNdx, RelocsMap) -> + maps:get(ShNdx, RelocsMap, false).