as: handle .long directive

This commit is contained in:
Mikael Pettersson 2019-12-25 21:51:02 +01:00
parent b96d413aaf
commit 4850c75237
6 changed files with 121 additions and 17 deletions

View File

@ -43,7 +43,7 @@ section(Section, Tunit) ->
#section{ name = ".text" ++ _
, sh_type = ?SHT_PROGBITS
, sh_flags = ?SHF_ALLOC bor ?SHF_EXECINSTR
} -> text(Section, Tunit);
} -> stmts(Section, Tunit);
#section{ name = ".comment"
, sh_type = ?SHT_PROGBITS
, sh_flags = ?SHF_MERGE bor ?SHF_STRINGS
@ -76,31 +76,45 @@ image_size([], Acc) -> Acc;
image_size(TByte, Acc) when is_integer(TByte), 0 =< TByte, TByte =< 511 ->
Acc + 1.
%% Assemble .text --------------------------------------------------------------
%% Assemble user-defined contents ----------------------------------------------
text(Section = #section{data = {stmts, Stmts}}, Tunit) ->
case text_image(Stmts, Tunit) of
stmts(Section = #section{data = {stmts, Stmts}}, Tunit) ->
case stmts_image(Stmts, Tunit) of
{ok, Image} ->
{ok, tunit:put_section(Tunit, Section#section{data = {image, Image}})};
{error, _Reason} = Error -> Error
end.
text_image(Stmts, Tunit) -> text_image(Stmts, Tunit, []).
stmts_image(Stmts, Tunit) -> stmts_image(Stmts, Tunit, []).
text_image([], _Tunit, Acc) -> {ok, Acc}; % the input Stmts were in reverse order
text_image([Stmt | Stmts], Tunit, Acc) ->
case insn_image(Stmt, Tunit) of
{ok, Image} -> text_image(Stmts, Tunit, [Image | Acc]);
stmts_image([], _Tunit, Acc) -> {ok, Acc}; % the input Stmts were in reverse order
stmts_image([Stmt | Stmts], Tunit, Acc) ->
case stmt_image(Stmt, Tunit) of
{ok, Image} -> stmts_image(Stmts, Tunit, [Image | Acc]);
{error, _Reason} = Error -> Error
end.
insn_image(Insn, Tunit) ->
stmt_image(Stmt, Tunit) ->
case Stmt of
#s_dot_long{} -> dot_long_image(Stmt, Tunit);
#s_insn{} -> insn_image(Stmt, Tunit)
end.
dot_long_image(Stmt, Tunit) ->
#s_dot_long{exprs = Exprs} = Stmt,
case exprs_values(Exprs, Tunit) of
{ok, Values} ->
{ok, [pdp10_extint:uint36_to_ext(Value) || Value <- Values]};
{error, _Reason} = Error -> Error
end.
insn_image(Stmt, Tunit) ->
#s_insn{ high13 = High13
, at = At
, address = AddressExpr
, index = Index
} = Insn,
case insn_address(AddressExpr, Tunit) of
} = Stmt,
case expr_value(AddressExpr, Tunit) of
{ok, Address} ->
Word = (((High13 band ((1 bsl 13) - 1)) bsl (36 - 13)) bor
((case At of true -> 1; false -> 0 end) bsl (36 - 14)) bor
@ -110,8 +124,18 @@ insn_image(Insn, Tunit) ->
{error, _Reason} = Error -> Error
end.
insn_address(AddressExpr, Tunit) ->
case AddressExpr of
exprs_values(Exprs, Tunit) ->
exprs_values(Exprs, Tunit, []).
exprs_values([], _Tunit, Acc) -> {ok, lists:reverse(Acc)};
exprs_values([Expr | Exprs], Tunit, Acc) ->
case expr_value(Expr, Tunit) of
{ok, Value} -> exprs_values(Exprs, Tunit, [Value | Acc]);
{error, _Reason} = Error -> Error
end.
expr_value(Expr, Tunit) ->
case Expr of
#e_integer{value = Value} -> {ok, Value};
#e_symbol{name = Name} ->
case tunit:get_symbol(Tunit, Name) of

View File

@ -312,6 +312,7 @@ pass2_stmt(Location, Tunit, Stmt) ->
#s_dot_file{} -> dot_file(Location, Tunit, Stmt);
#s_dot_globl{} -> dot_globl(Location, Tunit, Stmt);
#s_dot_ident{} -> dot_ident(Location, Tunit, Stmt);
#s_dot_long{} -> dot_long(Location, Tunit, Stmt);
#s_dot_size{} -> dot_size(Location, Tunit, Stmt);
#s_dot_type{} -> dot_type(Location, Tunit, Stmt);
#s_label{} -> label(Location, Tunit, Stmt);
@ -363,6 +364,21 @@ dot_ident(_Location, Tunit, #s_dot_ident{} = Stmt) ->
NewSection = OldSection#section{data = {stmts, [Stmt | Stmts]}},
{ok, tunit:put_section(Tunit, NewSection)}.
dot_long(Location, Tunit, #s_dot_long{exprs = Exprs} = Stmt) ->
#tunit{cursect = Cursect} = Tunit,
#section{data = {stmts, Stmts}, dot = Dot} = Section = tunit:get_section(Tunit, Cursect),
case Dot rem 4 of % FIXME: target-specific
0 ->
NewExprs = [expr_fixup(Tunit, Expr) || Expr <- Exprs],
NewStmt = Stmt#s_dot_long{exprs = NewExprs},
NewSection =
Section#section{ data = {stmts, [NewStmt | Stmts]}
, dot = Dot + 4 * length(NewExprs) % FIXME: target-specific
},
{ok, tunit:put_section(Tunit, NewSection)};
_ -> fmterr(Location, "misaligned address for .long", [])
end.
dot_size(Location, Tunit, #s_dot_size{name = Name}) ->
#tunit{cursect = Cursect} = Tunit,
#section{dot = Dot} = tunit:get_section(Tunit, Cursect),
@ -448,7 +464,11 @@ insn(Location, Tunit, #s_insn{} = Stmt) ->
end.
insn_fixup(Tunit, Insn) ->
case Insn#s_insn.address of
Address = Insn#s_insn.address,
Insn#s_insn{address = expr_fixup(Tunit, Address)}.
expr_fixup(Tunit, Expr) ->
case Expr of
#e_local_label{number = Number, direction = Direction} ->
LabelSerial = local_label_serial(Tunit, Number),
ReferenceSerial =
@ -457,8 +477,8 @@ insn_fixup(Tunit, Insn) ->
$f -> LabelSerial + 1
end,
Name = local_label_name(Number, ReferenceSerial),
Insn#s_insn{address = #e_symbol{name = Name}};
_ -> Insn
#e_symbol{name = Name};
_ -> Expr
end.
%% Initialization --------------------------------------------------------------

View File

@ -38,6 +38,7 @@ stmt(ScanState) ->
{ok, {Location, ?T_DOT_FILE}} -> dot_file(ScanState, Location);
{ok, {Location, ?T_DOT_GLOBL}} -> dot_globl(ScanState, Location);
{ok, {Location, ?T_DOT_IDENT}} -> dot_ident(ScanState, Location);
{ok, {Location, ?T_DOT_LONG}} -> dot_long(ScanState, Location);
{ok, {Location, ?T_DOT_POPSECTION}} -> dot_popsection(ScanState, Location);
{ok, {Location, ?T_DOT_PREVIOUS}} -> dot_previous(ScanState, Location);
{ok, {Location, ?T_DOT_PUSHSECTION}} -> dot_pushsection(ScanState, Location);
@ -310,6 +311,16 @@ dot_globl(ScanState, Location) ->
ScanRes -> badtok("junk after .globl", ScanRes)
end.
dot_long(ScanState, Location) ->
case expr_list(ScanState) of
{ok, {Exprs, Follow}} ->
case Follow of
{_Location, ?T_NEWLINE} -> {ok, {Location, #s_dot_long{exprs = Exprs}}};
_ -> badtok("junk after .long <exprs>", {ok, Follow})
end;
{error, _Reason} = Error -> Error
end.
dot_popsection(ScanState, Location) ->
case scan:token(ScanState) of
{ok, {_Location, ?T_NEWLINE}} -> {ok, {Location, #s_dot_popsection{}}};
@ -420,6 +431,47 @@ dot_type(ScanState, Location) ->
ScanRes -> badtok("junk after .type", ScanRes)
end.
%% Expressions -----------------------------------------------------------------
%% <expr_list> ::= (<expr> ("," <expr>)*)?
expr_list(ScanState) ->
case expr_opt(ScanState) of
{false, Follow} -> {ok, {[], Follow}};
{ok, Expr} -> expr_list(ScanState, [Expr]);
{error, _Reason} = Error -> Error
end.
expr_list(ScanState, Exprs) ->
case scan:token(ScanState) of
{ok, {_Location, ?T_COMMA}} ->
case expr(ScanState) of
{ok, Expr} -> expr_list(ScanState, [Expr | Exprs]);
{error, _Reason} = Error -> Error
end;
{ok, Follow} -> {ok, {lists:reverse(Exprs), Follow}};
{error, _Reason} = Error -> Error
end.
expr(ScanState) ->
case expr_opt(ScanState) of
{false, First} -> badtok("invalid start of expr", {ok, First});
OkOrError -> OkOrError
end.
expr_opt(ScanState) ->
case scan:token(ScanState) of
{ok, {_Location, {?T_UINTEGER, UInt}}} ->
{ok, #e_integer{value = UInt}};
{ok, {_Location, {?T_LOCAL_LABEL, Number, Direction}}} ->
{ok, #e_local_label{number = Number, direction = Direction}};
{ok, {_Location, {?T_SYMBOL, Symbol}}} ->
{ok, #e_symbol{name = Symbol}};
{ok, First} ->
{false, First};
{error, _Reason} = Error ->
Error
end.
%% Error reporting -------------------------------------------------------------
badtok(_ErrMsg, {error, _Reason} = Error) -> Error;

View File

@ -33,6 +33,7 @@ from_symbol(Name) ->
".file" -> ?T_DOT_FILE;
".globl" -> ?T_DOT_GLOBL;
".ident" -> ?T_DOT_IDENT;
".long" -> ?T_DOT_LONG;
".popsection" -> ?T_DOT_POPSECTION;
".previous" -> ?T_DOT_PREVIOUS;
".pushsection" -> ?T_DOT_PUSHSECTION;
@ -50,6 +51,7 @@ format(Token) ->
?T_DOT_FILE -> ".file";
?T_DOT_GLOBL -> ".globl";
?T_DOT_IDENT -> ".ident";
?T_DOT_LONG -> ".long";
?T_DOT_POPSECTION -> ".popsection";
?T_DOT_PREVIOUS -> ".previous";
?T_DOT_PUSHSECTION -> ".pushsection";

View File

@ -30,6 +30,7 @@
-define(T_DOT_FILE, 'T_DOT_FILE'). % .file
-define(T_DOT_GLOBL, 'T_DOT_GLOBL'). % .globl
-define(T_DOT_IDENT, 'T_DOT_IDENT'). % .ident
-define(T_DOT_LONG, 'T_DOT_LONG'). % .long
-define(T_DOT_POPSECTION, 'T_DOT_POPSECTION'). % .popsection
-define(T_DOT_PREVIOUS, 'T_DOT_PREVIOUS'). % .previous
-define(T_DOT_PUSHSECTION, 'T_DOT_PUSHSECTION'). % .pushsection
@ -63,6 +64,7 @@
| ?T_DOT_FILE
| ?T_DOT_GLOBL
| ?T_DOT_IDENT
| ?T_DOT_LONG
| ?T_DOT_POPSECTION
| ?T_DOT_PREVIOUS
| ?T_DOT_PUSHSECTION

View File

@ -48,6 +48,9 @@
%% .ident "..."
-record(s_dot_ident, {string :: string()}).
%% .long [expr (, expr)*]
-record(s_dot_long, {exprs :: [expr()]}).
%% .popsection
-record(s_dot_popsection, {}).
@ -85,6 +88,7 @@
| #s_dot_file{}
| #s_dot_globl{}
| #s_dot_ident{}
| #s_dot_long{}
| #s_dot_popsection{}
| #s_dot_previous{}
| #s_dot_pushsection{}