Skip to content

Commit

Permalink
Changes to handle more than one switch stmts
Browse files Browse the repository at this point in the history
Commit only includes changes to elf64_format and hipe_llvm_main.
Also, fixed some annoying whitespace.
  • Loading branch information
Yiannis Tsiouris authored and yiannist committed Mar 5, 2014
1 parent 4fface5 commit f5d990d
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 81 deletions.
56 changes: 26 additions & 30 deletions lib/hipe/llvm/elf64_format.erl
Original file line number Diff line number Diff line change
Expand Up @@ -393,16 +393,9 @@ get_text_rodata_list(Elf) ->
%% Do the magic!
{_, LRodata} =
get_text_symbol_info(SymTab, StrTab, SHdrTab, ShStrTab, Rela, [], []),
%% Filter non-".rodata" symbols
Pred = fun({SymName, _}) -> SymName =:= ".rodata" end,
LRodata2 = lists:filter(Pred, LRodata),
%% Merge to one tuple and a list of addends
case LRodata2 of
[] ->
{".rodata", []};
Ros ->
hd(flatten_list(Ros))
end.
%% Filter non-table symbols (Table symbols are prefixed with "table_")
Pred = fun({SymName, _}) -> string:str(SymName, "skata") > 0 end,
lists:filter(Pred, LRodata).


%% @spec get_text_symbol_info( binary(), binary(), binary(), binary(), binary(),
Expand All @@ -419,38 +412,41 @@ get_text_rodata_list(Elf) ->
[{string(), integer()}], [{string(), integer()}] )
-> { [{string(), integer()}], [{string(), integer()}] }.
get_text_symbol_info(_SymTab, _StrTab, _SHdrTab, _ShStrTab, <<>>, Acc1, Acc2) ->
{Acc1, Acc2};
{lists:reverse(Acc1), lists:reverse(Acc2)}; % Reverse of Acc2 *is* essential!
get_text_symbol_info(SymTab, StrTab, SHdrTab, ShStrTab, Rela, OffAcc, RoAcc) ->
%% Get Offset and Information about name
Offset = get_rela_entry_field(Rela, ?R_OFFSET),
Info = get_rela_entry_field(Rela, ?R_INFO),
Addend = get_rela_entry_field(Rela, ?R_ADDEND),
%% Addend = get_rela_entry_field(Rela, ?R_ADDEND),
SymIndex = ?ELF64_R_SYM(Info), % Index in Symbol Table (.symtab)
%% Get appropriate entry from Symbol Table
SymTabEntry = get_symtab_entry(SymTab, ?ELF64_SYM_SIZE, SymIndex),
%% Extract entry's type (it might be a section, function, notype etc.)
SInfo = get_symtab_entry_field(SymTabEntry, ?ST_INFO),
SType = ?ELF64_ST_TYPE(SInfo),
%% SInfo = get_symtab_entry_field(SymTabEntry, ?ST_INFO),
%% SType = ?ELF64_ST_TYPE(SInfo),
SValue = get_symtab_entry_field(SymTabEntry, ?ST_VALUE), % for switch-table
%% Extract symbol's name
SymbolName =
case SType of
?STT_SECTION -> %% Get name from Section Header Table (name of section)
Shndx = get_symtab_entry_field(SymTabEntry, ?ST_SHNDX),
SHdrEntry = get_shdrtab_entry(SHdrTab, ?ELF64_SHDRENTRY_SIZE, Shndx),
SHdrName = get_header_field(SHdrEntry, ?SH_NAME),
<<_Hdr:SHdrName/binary, Names/binary>> = ShStrTab,
bin_get_string(Names);
%% XXX: Maybe only catch STT_FUNC and STT_NOTYPE?
_ -> %%Get name from String Table (undefined symbol)
%% Extract SName (contains offset of name in StrTab)
SymName = get_symtab_entry_field(SymTabEntry, ?ST_NAME),
<<_Hdr:SymName/binary, Names/binary>> = StrTab,
bin_get_string(Names)
end,
%% SymbolName =
%% case SType of
%% ?STT_SECTION -> %% Get name from Section Header Table (name of section)
%% Shndx = get_symtab_entry_field(SymTabEntry, ?ST_SHNDX),
%% SHdrEntry = get_shdrtab_entry(SHdrTab, ?ELF64_SHDRENTRY_SIZE, Shndx),
%% SHdrName = get_header_field(SHdrEntry, ?SH_NAME),
%% <<_Hdr:SHdrName/binary, Names/binary>> = ShStrTab,
%% bin_get_string(Names);
%% %% XXX: Maybe only catch STT_FUNC and STT_NOTYPE?
%% _ ->
%% Get name from String Table (undefined symbol)
%% Extract SName (contains offset of name in StrTab)
SymName = get_symtab_entry_field(SymTabEntry, ?ST_NAME),
<<_Hdr:SymName/binary, Names/binary>> = StrTab,
SymbolName = bin_get_string(Names),
%% end,
%% Continue with next entries in Relocation "table"
<<_Head:?ELF64_RELA_SIZE/binary, More/binary>> = Rela,
get_text_symbol_info(SymTab, StrTab, SHdrTab, ShStrTab, More,
[{SymbolName, Offset} | OffAcc], [{SymbolName, Addend} | RoAcc]).
[{SymbolName, Offset} | OffAcc],
[{SymbolName, SValue} | RoAcc]).


%%------------------------------------------------------------------------------
Expand Down
122 changes: 71 additions & 51 deletions lib/hipe/llvm/hipe_llvm_main.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ rtl_to_native(RTL, Roots, _Options) ->
%% Get Labels info
Labels = elf64_format:get_label_list(ObjBin),
SwitchAddends = elf64_format:get_text_rodata_list(ObjBin),
SwitchInfos = extract_switch_infos(SwitchAddends, Relocs, Labels),
%% Create final LabelMap
LabelMap = fix_labelmap(Relocs, TempLabelMap, Labels, SwitchAddends),
LabelMap = fix_labelmap(SwitchInfos, TempLabelMap),
%% Create relocation list
{Relocs1, Closures} = fix_relocations(Relocs, RelocsDict, Mod_Name),
SDescs2 = fix_sdescs(RelocsDict, Relocs1, SDescs, Closures),
Expand Down Expand Up @@ -126,61 +127,74 @@ llvmc(Fun_Name, Opts) ->
fix_opts(Opts) ->
lists:foldl(fun(X, Acc) -> Acc++" "++X end, "", Opts).

%%----------------------------------------------------------------------------

%%----------------------------------------------------------------------------
%% Functions to manage relocations
%%----------------------------------------------------------------------------

%% Currently we can not handle more than one swich statements in one function.
%% Thus, the code of this function does not have a lot of meaning.
%% TODO: Fix Label Maps
fix_labelmap(Relocs, TempLabelMap, LabelList, SwitchAddends) ->
Switches = merge_switches(Relocs, SwitchAddends),
LabelList2 = split_labels(LabelList, Switches),
A = lists:zip(TempLabelMap, LabelList2),
lists:map(fun fix_labelmap2/1, A).

fix_labelmap2({M, Labels}) ->
case M of
{_, _, []} ->
extract_switch_infos(Switches, Symbols, Labels) ->
%% Extract slice-offsets list.
{Names, Slices} = lists:unzip(Switches),
%% Convert slice-offsets in slice-indexes.
Slices2 = lists:map(fun(X) -> X div 8 end, Slices),
%% Perform slicing based on slice-indexes.
SlicedLabels = slice_labels(Labels, Slices2),
%% Zip back! (combine with names)
Sw = lists:zip(Names, SlicedLabels),
%% Create list [{SwitchName, SwitchNameOffset, OffsetsOfValues}]
create_switch_list(Sw, Symbols).


create_switch_list(Switches, Symbols) ->
create_switch_list(Switches, Symbols, []).

create_switch_list([], _Symbols, Acc) ->
lists:reverse(Acc);
create_switch_list([ {TabName, Labels}|MoreSwitches ], Symbols, Acc) ->
%% Extract Offset for "TabName" from "Symbols"
%% XXX: Switch symbols should be referenced only once in the code!
%% (error-prone)
{TabName, [SymbolOffset]} = lists:keyfind(TabName, 1, Symbols),
%% Continue with more Switches
create_switch_list(MoreSwitches, Symbols,
[ {TabName, SymbolOffset, Labels}|Acc ]).


slice_labels(Labels, Slices) ->
%% Convert slice indexes to number of elements (per list).
ListOfLengths = convert_slice_indexes(Slices, length(Labels), []),
%% Perform slicing based on number of elements (per list).
elf64_format:split_list(Labels, ListOfLengths).


%% [0,20,30] out of 42 ==> [20,10,12] (first list should be ordered!)
convert_slice_indexes([X], N, Acc) ->
lists:reverse([N-X|Acc]);
convert_slice_indexes([X,Y|More], N, Acc) ->
convert_slice_indexes([Y|More], N, [Y-X|Acc]).


%% Merge temporary LabelMap with Jump Table info that is extracted from
%% the object file in order to create the final LabelMap, to be loaded
%% to the runtime.
fix_labelmap([], []) -> [];
fix_labelmap(SwitchInfos, TempLabelMap) ->
SortedSwitches = lists:keysort(1, SwitchInfos),
SortedLabelMap = lists:keysort(1, TempLabelMap),
lists:zipwith(fun merge_labelmap/2, SortedSwitches, SortedLabelMap).


merge_labelmap({Name, _, Labels}, TempLabelMap) ->
case TempLabelMap of
{Name, _, _, []} ->
[{unsorted, lists:zip(lists:seq(0, length(Labels)*8-1,8), Labels)}];
{_, sorted, Length, SortedBy} ->
[{sorted, Length, lists:zip(SortedBy,Labels)}]
end.

merge_switches(_Relocs, []) -> [];
merge_switches(_Relocs, {".rodata", []}) -> [];
merge_switches(Relocs, {".rodata", Addends}) ->
case lists:keyfind(".rodata", 1, Relocs) of
false ->
[];
{".rodata", Offsets} ->
lists:zip(Offsets,Addends)
{Name, _, sorted, Length, SortedBy} ->
[{sorted, Length, lists:zip(SortedBy,Labels)}];
_ ->
exit({?MODULE, merge_labelmap, "No match in switch infos with temporary
label map"})
end.

split_labels(LabelList, Switches) ->
LabelsLength = length(LabelList),
Switches1 = lists:keysort(2, Switches),
Switches2 = find_switch_length(Switches1, LabelsLength),
{Offsets, Lengths} = lists:unzip(Switches2),
LabelList2 = elf64_format:split_list(LabelList, Lengths),
Switches3 = lists:zip(Offsets, LabelList2),
Switches4 = lists:keysort(1, Switches3),
{_, LabelList3} = lists:unzip(Switches4),
LabelList3.


find_switch_length(Switches, LabelsLength) ->
Switches1 = lists:map(fun ({X,Y}) -> {X, Y div 8} end, Switches),
find_switch_length(Switches1, LabelsLength, []).
find_switch_length([], _LabelsLength, Acc) ->
Acc;
find_switch_length([{Offset, Addend}], LabelsLength, Acc) ->
lists:reverse([{Offset, LabelsLength-Addend}|Acc]);
find_switch_length([{Offset1, Addend1}, {Offset2, Addend2}|Rest], LL, Acc) ->
find_switch_length([{Offset2, Addend2}|Rest], LL, [{Offset1,
Addend2-Addend1}|Acc]).

%% Correlate object file relocation symbols with info from translation to llvm
%% code. Also split relocations according to their type, as expected by the
Expand All @@ -189,6 +203,7 @@ fix_relocations(Relocs, RelocsDict, ModName) ->
Relocs1 = fix_rodata(Relocs),
fix_relocs(Relocs1, RelocsDict, ModName, [], [], [], [], []).


fix_relocs([], _, _, Acc0, Acc1, Acc2, Acc3, Acc4) ->
Relocs = [{0, Acc0}, {1, Acc1}, {2, Acc2}, {3, Acc3}],
%% Remove Empty Elements
Expand All @@ -199,7 +214,6 @@ fix_relocs([], _, _, Acc0, Acc1, Acc2, Acc3, Acc4) ->
end
end,
{lists:filter(NotEmpty, Relocs), Acc4};

fix_relocs([{Name, Offset}|Rs], RelocsDict, ModName, Acc0, Acc1, Acc2, Acc3,
Acc4) ->
case dict:fetch(Name, RelocsDict) of
Expand All @@ -221,16 +235,17 @@ fix_relocs([{Name, Offset}|Rs], RelocsDict, ModName, Acc0, Acc1, Acc2, Acc3,
A}|Acc4]);
%% MFA calls to functions in the same module are of type 3, while all
%% other MFA calls are of type 2.
{call, {ModName,F,A}=MFA} ->
{call, {ModName,_F,_A}=MFA} ->
NR = {MFA, Offset},
fix_relocs(Rs, RelocsDict, ModName, Acc0, Acc1, Acc2, [NR|Acc3], Acc4);
{call, {M,F,A}=MFA} ->
{call, MFA} ->
NR = {MFA, Offset},
fix_relocs(Rs, RelocsDict, ModName, Acc0, Acc1, [NR|Acc2], Acc3, Acc4);
Other ->
exit({?MODULE, fix_relocs, {"Relocation Not In Relocation Dictionary", Other}})
end.


%% Temporary function that gives correct names to symbols that correspond to
%% .rodata section, which are produced from switch statement translation.
fix_rodata(Relocs) ->
Expand All @@ -251,9 +266,11 @@ fix_rodata_1([O|Os], Base, Acc) ->
NewName = ".rodata"++integer_to_list(Base),
fix_rodata_1(Os, Base+1, [{NewName, [O]}|Acc]).


%%----------------------------------------------------------------------------
%% Fixing Stack Descriptors
%%----------------------------------------------------------------------------

closures_offsets_arity([], SDescs) -> SDescs;
closures_offsets_arity(Closures, SDescs) ->
{_,Offsets1} = lists:unzip(SDescs),
Expand Down Expand Up @@ -309,6 +326,7 @@ calls_with_stack_args(Dict) ->
end,
lists:map(FindNameArity, Calls2).


%% This functions extracts the stack arity and the offset in the code of the
%% calls that have stack arguments.
calls_offsets_arity(Relocs, CallsWithStackArgs) ->
Expand All @@ -333,9 +351,11 @@ calls_offsets_arity(Relocs, CallsWithStackArgs) ->
end, CallsWithStackArgs),
lists:flatten(OffsetsArity1).


fix_sdescs1(SDescs, OffsetsArity) ->
lists:foldl(fun fix_sdescs2/2, SDescs, OffsetsArity).


fix_sdescs2(OffsetsArity, SDescs) ->
lists:foldl(
fun(X, Acc) -> fix_sdescs3(OffsetsArity, X) ++ Acc end, [], SDescs).
Expand Down

0 comments on commit f5d990d

Please sign in to comment.