aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/llvm
diff options
context:
space:
mode:
authorMagnus Lång <[email protected]>2016-05-10 17:22:25 +0200
committerMagnus Lång <[email protected]>2016-05-11 13:19:46 +0200
commit0f489445070cf65d96db7938f80ad118921c1f6a (patch)
treeeb31f67e5d9506ab000c3fd547c8f18aa92fadc4 /lib/hipe/llvm
parent3dc060d7b6e0f2ea55e6649b23a47d226874b9d4 (diff)
downloadotp-0f489445070cf65d96db7938f80ad118921c1f6a.tar.gz
otp-0f489445070cf65d96db7938f80ad118921c1f6a.tar.bz2
otp-0f489445070cf65d96db7938f80ad118921c1f6a.zip
hipe: Extract some records into elf_format.hrl
This allows for much more robust interpretation of relocations, symbols and sections in hipe_llvm_main, without the clunkiness of an abstract interface between two internal modules that belong to the same subsystem anyway.
Diffstat (limited to 'lib/hipe/llvm')
-rw-r--r--lib/hipe/llvm/Makefile8
-rw-r--r--lib/hipe/llvm/elf32_format.hrl6
-rw-r--r--lib/hipe/llvm/elf64_format.hrl6
-rw-r--r--lib/hipe/llvm/elf_format.erl140
-rw-r--r--lib/hipe/llvm/elf_format.hrl52
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl131
6 files changed, 197 insertions, 146 deletions
diff --git a/lib/hipe/llvm/Makefile b/lib/hipe/llvm/Makefile
index d2d39fb9e3..d172e37b02 100644
--- a/lib/hipe/llvm/Makefile
+++ b/lib/hipe/llvm/Makefile
@@ -108,3 +108,11 @@ release_spec: opt
$(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
release_docs_spec:
+
+$(EBIN)/elf_format.beam: elf_format.hrl elf32_format.hrl elf64_format.hrl
+$(EBIN)/hipe_llvm_main.beam: ../../kernel/src/hipe_ext_format.hrl \
+ hipe_llvm_arch.hrl elf_format.hrl elf32_format.hrl elf64_format.hrl
+$(EBIN)/hipe_llvm_merge.beam: ../../kernel/src/hipe_ext_format.hrl \
+ hipe_llvm_arch.hrl ../rtl/hipe_literals.hrl ../main/hipe.hrl
+$(EBIN)/hipe_rtl_to_llvm.beam: ../rtl/hipe_rtl.hrl ../rtl/hipe_literals.hrl \
+ hipe_llvm_arch.hrl
diff --git a/lib/hipe/llvm/elf32_format.hrl b/lib/hipe/llvm/elf32_format.hrl
index af1d95bf5b..1158cb6434 100644
--- a/lib/hipe/llvm/elf32_format.hrl
+++ b/lib/hipe/llvm/elf32_format.hrl
@@ -57,3 +57,9 @@
-define(P_MEMSZ_OFFSET, (?P_FILESZ_OFFSET + ?P_FILESZ_SIZE) ).
-define(P_FLAGS_OFFSET, (?P_TYPE_OFFSET + ?P_TYPE_SIZE) ).
-define(P_ALIGN_OFFSET, (?P_MEMSZ_OFFSET + ?P_MEMSZ_SIZE) ).
+
+%%------------------------------------------------------------------------------
+%% Exported record and type declarations for 'elf_format' module
+%%------------------------------------------------------------------------------
+
+-type reloc_type() :: '32' | 'pc32'.
diff --git a/lib/hipe/llvm/elf64_format.hrl b/lib/hipe/llvm/elf64_format.hrl
index 794746ffdc..0136e7f381 100644
--- a/lib/hipe/llvm/elf64_format.hrl
+++ b/lib/hipe/llvm/elf64_format.hrl
@@ -56,3 +56,9 @@
-define(P_FILESZ_OFFSET, (?P_PVADDR_OFFSET + ?P_PVADDR_SIZE) ).
-define(P_MEMSZ_OFFSET, (?P_FILESZ_OFFSET + ?P_FILESZ_SIZE) ).
-define(P_ALIGN_OFFSET, (?P_MEMSZ_OFFSET + ?P_MEMSZ_SIZE) ).
+
+%%------------------------------------------------------------------------------
+%% Exported record and type declarations for 'elf_format' module
+%%------------------------------------------------------------------------------
+
+-type reloc_type() :: '64' | 'pc32' | '32'.
diff --git a/lib/hipe/llvm/elf_format.erl b/lib/hipe/llvm/elf_format.erl
index e56ccce626..4155dff7c4 100644
--- a/lib/hipe/llvm/elf_format.erl
+++ b/lib/hipe/llvm/elf_format.erl
@@ -13,18 +13,16 @@
-module(elf_format).
--export([get_tab_entries/1,
- %% Relocations
- get_rodata_relocs/1,
- get_text_relocs/1,
+-export([%% Relocations
extract_rela/2,
- get_rela_addends/1,
%% Note
extract_note/2,
%% Executable code
extract_text/1,
%% GCC Exception Table
get_exn_handlers/1,
+ %% Symbols
+ elf_symbols/1,
%% Main interface
read/1
]).
@@ -40,14 +38,7 @@
-type lp() :: non_neg_integer(). % landing pad
-type num() :: non_neg_integer().
-type index() :: non_neg_integer().
--type offset() :: non_neg_integer().
--type size() :: non_neg_integer().
-type start() :: non_neg_integer().
--type reloc_type() :: atom().
-
--type valueoff() :: offset().
-
--type name() :: string().
-type tuple(X) :: {} | {X} | {X, X} | tuple().
@@ -91,38 +82,6 @@
}).
%% -type elf_ehdr_ident() :: #elf_ehdr_ident{}.
-%% Section header entries
--record(elf_shdr, {name :: string(), % Section name
- type, % Section type
- flags, % Section attributes
- addr, % Virtual address in memory
- offset :: offset(), % Offset in file
- size :: size(), % Size of section
- link, % Link to other section
- info, % Miscellaneous information
- addralign, % Address align boundary
- entsize % Size of entries, if section has table
- }).
--type elf_shdr() :: #elf_shdr{}.
-
-%% Symbol table entries
--record(elf_sym, {name :: string(), % Symbol name
- info, % Type and Binding attributes
- other, % Reserved
- section :: undefined | abs | elf_shdr(),
- value :: valueoff(), % Symbol value
- size :: size() % Size of object
- }).
--type elf_sym() :: #elf_sym{}.
-
-%% Relocations
--record(elf_rel, {offset :: offset()
- ,type :: reloc_type()
- ,addend :: offset() | undefined
- ,symbol :: elf_sym()
- }).
--type elf_rel() :: #elf_rel{}.
-
%% %% Program header table
%% -record(elf_phdr, {type, % Type of segment
%% flags, % Segment attributes
@@ -201,13 +160,13 @@ mk_shdr(Name, Type, Flags, Addr, Offset, Size, Link, Info, AddrAlign, EntSize) -
%%%-------------------------
%%% Symbol Table Entries
%%%-------------------------
-mk_sym(Name, Info, Other, Section, Value, Size) ->
- #elf_sym{name = Name, info = Info, other = Other,
+mk_sym(Name, Bind, Type, Section, Value, Size) ->
+ #elf_sym{name = Name, bind = Bind, type = Type,
section = Section, value = Value, size = Size}.
--spec sym_name(elf_sym()) -> string().
-sym_name(#elf_sym{name = Name}) -> Name.
-
+%% -spec sym_name(elf_sym()) -> string().
+%% sym_name(#elf_sym{name = Name}) -> Name.
+%%
%% -spec sym_value(elf_sym()) -> valueoff().
%% sym_value(#elf_sym{value = Value}) -> Value.
%%
@@ -327,10 +286,26 @@ get_shdrtab_entries(ShdrTab, ShStrTab) ->
Entsize:?bits(?SH_ENTSIZE_SIZE)/integer-little,
Rest/binary
>> = ShdrTab,
- Entry = mk_shdr(get_strtab_entry(Name, ShStrTab), Type, Flags, Addr, Offset,
- Size, Link, Info, Addralign, Entsize),
+ Entry = mk_shdr(get_strtab_entry(Name, ShStrTab), decode_shdr_type(Type),
+ Flags, Addr, Offset, Size, Link, Info, Addralign, Entsize),
[Entry | get_shdrtab_entries(Rest, ShStrTab)].
+decode_shdr_type(?SHT_NULL) -> 'null';
+decode_shdr_type(?SHT_PROGBITS) -> 'progbits';
+decode_shdr_type(?SHT_SYMTAB) -> 'symtab';
+decode_shdr_type(?SHT_STRTAB) -> 'strtab';
+decode_shdr_type(?SHT_RELA) -> 'rela';
+decode_shdr_type(?SHT_HASH) -> 'hash'; %unused
+decode_shdr_type(?SHT_DYNAMIC) -> 'dynamic'; %unused
+decode_shdr_type(?SHT_NOTE) -> 'note'; %unused
+decode_shdr_type(?SHT_NOBITS) -> 'nobits';
+decode_shdr_type(?SHT_REL) -> 'rel';
+decode_shdr_type(?SHT_SHLIB) -> 'shlib'; %unused
+decode_shdr_type(?SHT_DYNSYM) -> 'dynsym'; %unused
+decode_shdr_type(OS) when ?SHT_LOOS =< OS, OS =< ?SHT_HIOS -> {os, OS};
+decode_shdr_type(Proc) when ?SHT_LOPROC =< Proc, Proc =< ?SHT_HIPROC ->
+ {proc, Proc}.
+
-spec elf_section(non_neg_integer(), elf()) -> undefined | abs | elf_shdr().
elf_section(0, #elf{}) -> undefined;
elf_section(?SHN_ABS, #elf{}) -> abs;
@@ -338,14 +313,6 @@ elf_section(Index, #elf{sec_idx=SecIdx}) when Index =< tuple_size(SecIdx) ->
element(Index, SecIdx).
%%------------------------------------------------------------------------------
-
--spec get_tab_entries(elf()) -> [{name(), valueoff(), size()}].
-get_tab_entries(#elf{sym_idx=SymIdx}) ->
- [{Name, Value, Size div ?ELF_XWORD_SIZE}
- || #elf_sym{name = Name, value = Value, size = Size}
- <- tuple_to_list(SymIdx), Name =/= ""].
-
-%%------------------------------------------------------------------------------
%% Functions to manipulate Symbol Table
%%------------------------------------------------------------------------------
@@ -360,30 +327,51 @@ parse_sym(<<%% Structural pattern matching on fields.
Value:?bits(?ST_VALUE_SIZE)/integer-little,
Size:?bits(?ST_SIZE_SIZE)/integer-little,
Info:?bits(?ST_INFO_SIZE)/integer-little,
- Other:?bits(?ST_OTHER_SIZE)/integer-little,
+ _Other:?bits(?ST_OTHER_SIZE)/integer-little,
Shndx:?bits(?ST_SHNDX_SIZE)/integer-little>>,
Elf, StrTab) ->
- mk_sym(get_strtab_entry(Name, StrTab), Info, Other, elf_section(Shndx, Elf),
- Value, Size).
+ mk_sym(get_strtab_entry(Name, StrTab), decode_symbol_bind(?ELF_ST_BIND(Info)),
+ decode_symbol_type(?ELF_ST_TYPE(Info)), elf_section(Shndx, Elf), Value,
+ Size).
-else.
parse_sym(<<%% Same fields in different order:
Name:?bits(?ST_NAME_SIZE)/integer-little,
Info:?bits(?ST_INFO_SIZE)/integer-little,
- Other:?bits(?ST_OTHER_SIZE)/integer-little,
+ _Other:?bits(?ST_OTHER_SIZE)/integer-little,
Shndx:?bits(?ST_SHNDX_SIZE)/integer-little,
Value:?bits(?ST_VALUE_SIZE)/integer-little,
Size:?bits(?ST_SIZE_SIZE)/integer-little>>,
Elf, StrTab) ->
- mk_sym(get_strtab_entry(Name, StrTab), Info, Other, elf_section(Shndx, Elf),
- Value, Size).
+ mk_sym(get_strtab_entry(Name, StrTab), decode_symbol_bind(?ELF_ST_BIND(Info)),
+ decode_symbol_type(?ELF_ST_TYPE(Info)), elf_section(Shndx, Elf), Value,
+ Size).
-endif.
+decode_symbol_bind(?STB_LOCAL) -> 'local';
+decode_symbol_bind(?STB_GLOBAL) -> 'global';
+decode_symbol_bind(?STB_WEAK) -> 'weak'; %unused
+decode_symbol_bind(OS) when ?STB_LOOS =< OS, OS =< ?STB_HIOS -> {os, OS};
+decode_symbol_bind(Proc) when ?STB_LOPROC =< Proc, Proc =< ?STB_HIPROC ->
+ {proc, Proc}.
+
+decode_symbol_type(?STT_NOTYPE) -> 'notype';
+decode_symbol_type(?STT_OBJECT) -> 'object';
+decode_symbol_type(?STT_FUNC) -> 'func';
+decode_symbol_type(?STT_SECTION) -> 'section';
+decode_symbol_type(?STT_FILE) -> 'file';
+decode_symbol_type(OS) when ?STT_LOOS =< OS, OS =< ?STT_HIOS -> {os, OS};
+decode_symbol_type(Proc) when ?STT_LOPROC =< Proc, Proc =< ?STT_HIPROC ->
+ {proc, Proc}.
+
%% @doc Extracts a specific entry from the Symbol Table.
-spec elf_symbol(0, elf()) -> undefined;
(pos_integer(), elf()) -> elf_sym().
elf_symbol(0, #elf{}) -> undefined;
elf_symbol(Index, #elf{sym_idx=SymIdx}) -> element(Index, SymIdx).
+-spec elf_symbols(elf()) -> [elf_sym()].
+elf_symbols(#elf{sym_idx=SymIdx}) -> tuple_to_list(SymIdx).
+
%%------------------------------------------------------------------------------
%% Functions to manipulate String Table
%%------------------------------------------------------------------------------
@@ -415,22 +403,6 @@ bin_get_string(<<Char, Rest/binary>>) -> [Char|bin_get_string(Rest)].
%% Functions to manipulate Relocations
%%------------------------------------------------------------------------------
-%% @doc This function gets as argument an ELF binary file and returns a list
-%% with all .rela.rodata labels (i.e. constants and literals in code)
-%% or an empty list if no ".rela.rodata" section exists in code.
--spec get_rodata_relocs(elf()) -> [offset()].
-get_rodata_relocs(Elf) -> get_rela_addends(extract_rela(Elf, ?RODATA)).
-
--spec get_rela_addends([elf_rel()]) -> [offset()].
-get_rela_addends(RelaEntries) -> [A || #elf_rel{addend=A} <- RelaEntries].
-
-%% @doc Extract a list of the form `[{SymbolName, Offset}]' with all relocatable
-%% symbols and their offsets in the code from the ".text" section.
--spec get_text_relocs(elf()) -> [{name(), offset()}].
-get_text_relocs(Elf) ->
- [{sym_name(Symbol), Offset}
- || #elf_rel{offset=Offset, symbol=Symbol} <- extract_rela(Elf, ?TEXT)].
-
%% @doc Extract the Relocations segment for section `Name' (that is passed
%% as second argument) from an ELF formated Object file binary.
-spec extract_rela(elf(), name()) -> [elf_rel()].
@@ -442,7 +414,7 @@ extract_rela(Elf, Name) ->
type=decode_reloc_type(?ELF_R_TYPE(Info)),
addend=read_implicit_addend(Offset, SecData)}
|| <<Offset:?bits(?R_OFFSET_SIZE)/little,
- Info:?bits(?R_INFO_SIZE)/little % ELF-32 uses ".rel"
+ Info:?bits(?R_INFO_SIZE)/little % 386 uses ".rel"
>> <= extract_segment_by_name(Elf, ?REL(Name))].
%% The only types HiPE knows how to patch
@@ -451,7 +423,7 @@ decode_reloc_type(2) -> 'pc32'.
read_implicit_addend(Offset, Section) ->
%% All x86 relocation types uses 'word32' relocation fields; i.e. 32-bit LE.
- <<_:Offset/binary, Addend:32/little, _/binary>> = Section,
+ <<_:Offset/binary, Addend:32/signed-little, _/binary>> = Section,
Addend.
-else. %% BIT32
@@ -460,7 +432,7 @@ extract_rela(Elf, Name) ->
type=decode_reloc_type(?ELF_R_TYPE(Info)), addend=Addend}
|| <<Offset:?bits(?R_OFFSET_SIZE)/little,
Info:?bits(?R_INFO_SIZE)/little,
- Addend:?bits(?R_ADDEND_SIZE)/little % ...while ELF-64 uses ".rela"
+ Addend:?bits(?R_ADDEND_SIZE)/signed-little % X86_64 uses ".rela"
>> <= extract_segment_by_name(Elf, ?RELA(Name))].
decode_reloc_type(1) -> '64';
diff --git a/lib/hipe/llvm/elf_format.hrl b/lib/hipe/llvm/elf_format.hrl
index 7a3cdfead6..5074682ae6 100644
--- a/lib/hipe/llvm/elf_format.hrl
+++ b/lib/hipe/llvm/elf_format.hrl
@@ -486,3 +486,55 @@
%% Misc.
%%------------------------------------------------------------------------------
-define(bits(Bytes), ((Bytes) bsl 3)).
+
+%%------------------------------------------------------------------------------
+%% Exported record and type declarations for 'elf_format' module
+%%------------------------------------------------------------------------------
+
+-type offset() :: non_neg_integer().
+-type size() :: non_neg_integer().
+-type addend() :: integer() | undefined.
+-type sym_bind() :: 'local' | 'global' | 'weak' | {os, ?STB_LOOS..?STB_HIOS}
+ | {proc, ?STB_LOPROC..?STB_HIPROC}.
+-type sym_type() :: 'notype' | 'object' | 'func' | 'section' | 'file'
+ | {os, ?STT_LOOS..?STT_HIOS}
+ | {proc, ?STT_LOPROC..?STT_HIPROC}.
+-type shdr_type() :: 'null' | 'progbits' | 'symtab' | 'strtab' | 'rela'
+ | 'hash' | 'dynamic' | 'note' | 'nobits' | 'rel' | 'shlib'
+ | 'dynsym' | {os, ?SHT_LOOS..?SHT_HIOS}
+ | {proc, ?SHT_LOPROC..?SHT_HIPROC}.
+
+-type valueoff() :: offset().
+-type name() :: string().
+
+%% Section header entries
+-record(elf_shdr, {name :: name() % Section name
+ ,type :: shdr_type()% Section type
+ ,flags % Section attributes
+ ,addr % Virtual address in memory
+ ,offset :: offset() % Offset in file
+ ,size :: size() % Size of section
+ ,link % Link to other section
+ ,info % Miscellaneous information
+ ,addralign % Address align boundary
+ ,entsize % Size of entries, if section has table
+ }).
+-type elf_shdr() :: #elf_shdr{}.
+
+%% Symbol table entries
+-record(elf_sym, {name :: name() % Symbol name
+ ,bind :: sym_bind() % Symbol binding
+ ,type :: sym_type() % Symbol type
+ ,value :: valueoff() % Symbol value
+ ,size :: size() % Size of object
+ ,section :: undefined | abs | elf_shdr()
+ }).
+-type elf_sym() :: #elf_sym{}.
+
+%% Relocations
+-record(elf_rel, {offset :: offset()
+ ,type :: reloc_type()
+ ,addend :: addend()
+ ,symbol :: elf_sym()
+ }).
+-type elf_rel() :: #elf_rel{}.
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
index 60833d4af9..3ab213f94c 100644
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -26,11 +26,10 @@ rtl_to_native(MFA, RTL, Roots, Options) ->
ObjBin = open_object_file(ObjectFile),
Obj = elf_format:read(ObjBin),
%% Get labels info (for switches and jump tables)
- Labels = elf_format:get_rodata_relocs(Obj),
- {Switches, Closures} = get_tables(Obj),
+ Labels = elf_format:extract_rela(Obj, ?RODATA),
+ Tables = get_tables(Obj),
%% Associate Labels with Switches and Closures with stack args
- {SwitchInfos, ExposedClosures} =
- correlate_labels(Switches ++ Closures, Labels),
+ {SwitchInfos, ExposedClosures} = correlate_labels(Tables, Labels),
%% SwitchInfos: [{"table_50", [Labels]}]
%% ExposedClosures: [{"table_closures", [Labels]}]
@@ -38,7 +37,7 @@ rtl_to_native(MFA, RTL, Roots, Options) ->
%% used for switch's jump tables
LabelMap = create_labelmap(MFA, SwitchInfos, RelocsDict),
%% Get relocation info
- TextRelocs = elf_format:get_text_relocs(Obj),
+ TextRelocs = elf_format:extract_rela(Obj, ?TEXT),
%% AccRefs contains the offsets of all references to relocatable symbols in
%% the code:
AccRefs = fix_relocations(TextRelocs, RelocsDict, MFA),
@@ -158,12 +157,10 @@ trans_optlev_flag(Tool, Options) ->
%%------------------------------------------------------------------------------
%% @doc Get switch table and closure table.
+-spec get_tables(elf_format:elf()) -> [elf_sym()].
get_tables(Elf) ->
- %% Search Symbol Table for an entry with name prefixed with "table_":
- Triples = elf_format:get_tab_entries(Elf),
- Switches = [T || T={"table_" ++ _, _, _} <- Triples],
- Closures = [T || T={"table_closures" ++ _, _, _} <- Switches],
- {Switches, Closures}.
+ %% Search Symbol Table for entries where name is prefixed with "table_":
+ [S || S=#elf_sym{name="table_" ++ _} <- elf_format:elf_symbols(Elf)].
%% @doc This function associates symbols who point to some table of labels with
%% the corresponding offsets of the labels in the code. These tables can
@@ -171,14 +168,12 @@ get_tables(Elf) ->
%% of blocks that contain closure calls with more than ?NR_ARG_REGS.
correlate_labels([], _L) -> {[], []};
correlate_labels(Tables, Labels) ->
- %% Sort "Tables" based on "ValueOffsets"
- OffsetSortedTb = lists:ukeysort(2, Tables),
- %% Unzip offset-sorted list of "Switches"
- {Names, _Offsets, TablesSizeList} = lists:unzip3(OffsetSortedTb),
- %% Associate switch names with labels
- L = split_list(Labels, TablesSizeList),
- %% Zip back! (to [{SwitchName, Values}])
- NamesValues = lists:zip(Names, L),
+ %% Assumes that the relocations are sorted
+ RelocTree = gb_trees:from_orddict(
+ [{Rel#elf_rel.offset, Rel#elf_rel.addend} || Rel <- Labels]),
+ %% Lookup all relocations pertaining to each symbol
+ NamesValues = [{Name, lookup_range(Value, Value+Size, RelocTree)}
+ || #elf_sym{name=Name, value=Value, size=Size} <- Tables],
case lists:keytake("table_closures", 1, NamesValues) of
false -> %% No closures in the code, no closure table
{NamesValues, []};
@@ -186,6 +181,17 @@ correlate_labels(Tables, Labels) ->
{SwitchesNV, ClosureTableNV}
end.
+%% Fetches all values with a key in [Low, Hi)
+-spec lookup_range(_::K, _::K, gb_trees:tree(K,V)) -> [_::V].
+lookup_range(Low, Hi, Tree) ->
+ lookup_range_1(Hi, gb_trees:iterator_from(Low, Tree)).
+
+lookup_range_1(Hi, Iter0) ->
+ case gb_trees:next(Iter0) of
+ {Key, Value, Iter} when Key < Hi -> [Value | lookup_range_1(Hi, Iter)];
+ _ -> []
+ end.
+
%% @doc Create a gb_tree which contains information about the labels that used
%% for switch's jump tables. The keys of the gb_tree are of the form
%% {MFA, Label} and the values are the actual Offsets.
@@ -216,37 +222,53 @@ insert_to_labelmap([{Key, Value}|Rest], LabelMap) ->
%% @doc Correlate object file relocation symbols with info from translation to
%% llvm code.
fix_relocations(Relocs, RelocsDict, MFA) ->
- fix_relocs(Relocs, RelocsDict, MFA, []).
-
-fix_relocs([], _, _, RelocAcc) -> RelocAcc;
-fix_relocs([{Name, Offset}|Rs], RelocsDict, {ModName,_,_}=MFA, RelocAcc) ->
+ lists:map(fun(Reloc) -> fix_reloc(Reloc, RelocsDict, MFA) end, Relocs).
+
+%% Relocation types and expected addends for x86 and amd64
+-define(PCREL_T, 'pc32').
+-define(PCREL_A, -4). %% Hard-coded in hipe_x86.c and hipe_amd64.c
+-ifdef(BIT32).
+-define(ABS_T, '32').
+-define(ABS_A, _). %% We support any addend
+-else.
+-define(ABS_T, '64').
+-define(ABS_A, 0).
+-endif.
+
+fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=undefined, type=notype},
+ offset=Offset, type=?PCREL_T, addend=?PCREL_A},
+ RelocsDict, {ModName,_,_}) when Name =/= "" ->
case dict:fetch(Name, RelocsDict) of
- {atom, AtomName} ->
- fix_relocs(Rs, RelocsDict, MFA,
- [{?LOAD_ATOM, Offset, AtomName}|RelocAcc]);
- {constant, Label} ->
- fix_relocs(Rs, RelocsDict, MFA,
- [{?LOAD_ADDRESS, Offset, {constant, Label}}|RelocAcc]);
- {switch, _, JTabLab} -> %% Treat switch exactly as constant
- fix_relocs(Rs, RelocsDict, MFA,
- [{?LOAD_ADDRESS, Offset, {constant, JTabLab}}|RelocAcc]);
- {closure, _}=Closure ->
- fix_relocs(Rs, RelocsDict, MFA,
- [{?LOAD_ADDRESS, Offset, Closure}|RelocAcc]);
- {call, {bif, BifName, _}} ->
- fix_relocs(Rs, RelocsDict, MFA,
- [{?CALL_LOCAL, Offset, BifName}|RelocAcc]);
+ {call, {bif, BifName, _}} -> {?CALL_LOCAL, Offset, BifName};
%% 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}=CallMFA} ->
- fix_relocs(Rs, RelocsDict, MFA,
- [{?CALL_LOCAL, Offset, CallMFA}|RelocAcc]);
- {call, CallMFA} ->
- fix_relocs(Rs, RelocsDict, MFA,
- [{?CALL_REMOTE, Offset, CallMFA}|RelocAcc]);
- Other ->
- exit({?MODULE, fix_relocs,
- {"Relocation not in relocation dictionary", Other}})
+ %% XXX: Does this code break hot code loading (by transforming external
+ %% calls into local calls?)
+ {call, {ModName,_F,_A}=CallMFA} -> {?CALL_LOCAL, Offset, CallMFA};
+ {call, CallMFA} -> {?CALL_REMOTE, Offset, CallMFA}
+ end;
+fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=undefined, type=notype},
+ offset=Offset, type=?ABS_T, addend=?ABS_A},
+ RelocsDict, _) when Name =/= "" ->
+ case dict:fetch(Name, RelocsDict) of
+ {atom, AtomName} -> {?LOAD_ATOM, Offset, AtomName};
+ {constant, Label} -> {?LOAD_ADDRESS, Offset, {constant, Label}};
+ {closure, _}=Closure -> {?LOAD_ADDRESS, Offset, Closure}
+ end;
+fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=#elf_shdr{name=?TEXT},
+ type=func},
+ offset=Offset, type=?PCREL_T, addend=?PCREL_A},
+ RelocsDict, MFA) when Name =/= "" ->
+ case dict:fetch(Name, RelocsDict) of
+ {call, MFA} -> {?CALL_LOCAL, Offset, MFA}
+ end;
+fix_reloc(#elf_rel{symbol=#elf_sym{name=Name, section=#elf_shdr{name=?RODATA},
+ type=object},
+ offset=Offset, type=?ABS_T, addend=?ABS_A},
+ RelocsDict, _) when Name =/= "" ->
+ case dict:fetch(Name, RelocsDict) of
+ {switch, _, JTabLab} -> %% Treat switch exactly as constant
+ {?LOAD_ADDRESS, Offset, {constant, JTabLab}}
end.
%%------------------------------------------------------------------------------
@@ -278,7 +300,7 @@ get_sdescs(Elf) ->
Roots/binary>> = NoteGC_bin,
LiveRoots = get_liveroots(Roots, []),
%% Extract the safe point offsets:
- SPOffs = elf_format:get_rela_addends(RelaNoteGC),
+ SPOffs = [A || #elf_rel{addend=A} <- RelaNoteGC],
%% Extract Exception Handler labels:
ExnHandlers = elf_format:get_exn_handlers(Elf),
%% Combine ExnHandlers and Safe point addresses (return addresses):
@@ -476,18 +498,3 @@ unique_folder(FunName, Arity, Options) ->
dir_exists(Filename) ->
{Flag, Info} = file:read_file_info(Filename),
(Flag =:= ok) andalso (element(3, Info) =:= directory).
-
-%% @doc Function that takes as arguments a list of integers and a list with
-%% numbers indicating how many items should each tuple have and splits
-%% the original list to a list of lists of integers (with the specified
-%% number of elements), i.e. [ [...], [...] ].
--spec split_list([integer()], [integer()]) -> [ [integer()] ].
-split_list(List, ElemsPerTuple) ->
- split_list(List, ElemsPerTuple, []).
-
--spec split_list([integer()], [integer()], [ [integer()] ]) -> [ [integer()] ].
-split_list([], [], Acc) ->
- lists:reverse(Acc);
-split_list(List, [NumOfElems | MoreNums], Acc) ->
- {L1, L2} = lists:split(NumOfElems, List),
- split_list(L2, MoreNums, [ L1 | Acc]).