diff --git a/erlang/apps/ld/src/ld.erl b/erlang/apps/ld/src/ld.erl index c464e9a..47fc308 100644 --- a/erlang/apps/ld/src/ld.erl +++ b/erlang/apps/ld/src/ld.erl @@ -216,7 +216,8 @@ ld(Argv) -> %% TODO: receive ok | error {ok, Sections} = phase1(Options, Inputs), %% TODO: receive ok | error - {ok, Segments} = phase2(Options, Sections), + {ok, Segments0} = phase2(Options, Sections), + Segments = assign(Options, Segments0), output(Options, Segments); {error, _Reason} = Error -> Error end; @@ -386,6 +387,10 @@ phase1(_Options, Inputs) -> {ok, ld_phase1:phase1(Inputs)}. phase2(_Options, Sections) -> {ok, ld_phase2:phase2(Sections)}. +%% Assigning Addresses ========================================================= + +assign(_Options, Segments) -> ld_assign:assign(Segments). + %% Output Generation =========================================================== output(_Options, _Segments) -> ok. % FIXME diff --git a/erlang/apps/ld/src/ld_assign.erl b/erlang/apps/ld/src/ld_assign.erl new file mode 100644 index 0000000..3a74b23 --- /dev/null +++ b/erlang/apps/ld/src/ld_assign.erl @@ -0,0 +1,48 @@ +%%% -*- erlang-indent-level: 2 -*- +%%% +%%% Assigning addresses for pdp10-elf-ld +%%% 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 . + +-module(ld_assign). + +-export([ assign/1 + ]). + +-include("ld_internal.hrl"). + +%% Output ====================================================================== + +-spec assign([#segment{}]) -> [#segment{}]. +assign(Segments) -> + %% TODO: assumes KL10B-compatible "small" code model output + VAddr = 8#00001001000 bsl 2, % section 1, page 1 + PhNum = length(Segments), + true = PhNum < ?PN_XNUM, % assert; TODO: otherwise store PhNum in Shdr0.sh_info + Offset = ?ELF36_EHDR_SIZEOF + ?ELF36_PHDR_SIZEOF * PhNum, + assign(Segments, Offset, VAddr, []). + +assign(_Segments = [], _Offset, _VAddr, NewSegments) -> lists:reverse(NewSegments); +assign([Segment | Segments], Offset, VAddr, NewSegments) -> + #segment{phdr = Phdr} = Segment, + #elf36_Phdr{p_filesz = FileSz, p_memsz = MemSz, p_align = Align} = Phdr, + SegAlign = max(4096, Align), % align to page boundary; TODO: target-specific + SegOffset = (Offset + (SegAlign - 1)) band bnot (SegAlign - 1), + SegVAddr = (VAddr + (SegAlign - 1)) band bnot (SegAlign - 1), + NewPhdr = Phdr#elf36_Phdr{p_offset = SegOffset, p_vaddr = SegVAddr, p_align = SegAlign}, + NewSegment = Segment#segment{phdr = NewPhdr}, + assign(Segments, SegOffset + FileSz, SegVAddr + MemSz, [NewSegment | NewSegments]).