hipe_arm_assemble.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 650 行 · 第 1/2 页

ERL
650
字号
  NewS = do_s(false),  NewDstLo = do_reg(DstLo),  NewDstHi = do_reg(DstHi),  NewSrc1 = do_reg(Src1),  NewSrc2 = do_reg(Src2),  [{'smull', {NewCond,NewS,NewDstLo,NewDstHi,NewSrc1,NewSrc2}, I}].do_store(I) ->  #store{stop=StOp,src=Src,am2=Am2} = I,  NewCond = do_cond('al'),  NewSrc = do_reg(Src),  NewAm2 = do_am2(Am2),  [{StOp, {NewCond,NewSrc,NewAm2}, I}].do_reg(#arm_temp{reg=Reg,type=Type})  when is_integer(Reg), 0 =< Reg, Reg < 16, Type =/= 'double' ->  {r,Reg}.  do_cond(Cond) -> {'cond',Cond}.do_s(S) -> {'s', case S of false -> 0; true -> 1 end}.do_label_ref(Label) when is_integer(Label) ->  {label,Label}.	% symbolic, since offset is not yet computabledo_am1(Am1) ->  case Am1 of    #arm_temp{} -> do_reg(Am1);    {Src1,'rrx'} -> {do_reg(Src1),'rrx'};    {Src1,ShiftOp,Src2=#arm_temp{}} -> {do_reg(Src1),{ShiftOp,do_reg(Src2)}};    {Src1,ShiftOp,Imm5} -> {do_reg(Src1),{ShiftOp,{imm5,Imm5}}};    {Imm8,Imm4} -> {{imm8,Imm8},{imm4,Imm4}}  end.do_am2(#am2{src=Src,sign=Sign,offset=Offset}) ->  NewSrc = do_reg(Src),  case Offset of    #arm_temp{} -> {'register_offset',NewSrc,Sign,do_reg(Offset)};    {Src3,'rrx'} -> {'scaled_register_offset',NewSrc,Sign,do_reg(Src3),'rrx'};    {Src3,ShiftOp,Imm5} -> {'scaled_register_offset',NewSrc,Sign,do_reg(Src3),{ShiftOp,{imm5,Imm5}}};    Imm12 -> {'immediate_offset',NewSrc,Sign,{imm12,Imm12}}  end.do_am3(#am3{src=Src,sign=Sign,offset=Offset}) ->  NewSrc = do_reg(Src),  case Offset of    #arm_temp{} -> {'register_offset',NewSrc,Sign,do_reg(Offset)};    _ -> {'immediate_offset',NewSrc,Sign,{'imm8',Offset}}  end.%%%%%% Assembly Pass 3.%%% Process final {MFA,Code,CodeSize,LabelMap} list from pass 2.%%% Translate to a single binary code segment.%%% Collect relocation patches.%%% Build ExportMap (MFA-to-address mapping).%%% Combine LabelMaps to a single one (for mk_data_relocs/2 compatibility).%%% Return {CombinedCodeSize,BinaryCode,Relocs,CombinedLabelMap,ExportMap}.%%%encode(Code, Options) ->  CodeSize = compute_code_size(Code, 0),  ExportMap = build_export_map(Code, 0, []),  {AccCode,Relocs} = encode_mfas(Code, 0, [], [], Options),  CodeBinary = list_to_binary(lists:reverse(AccCode)),  ?ASSERT(CodeSize =:= size(CodeBinary)),  CombinedLabelMap = combine_label_maps(Code, 0, gb_trees:empty()),  {CodeSize,CodeBinary,Relocs,CombinedLabelMap,ExportMap}.compute_code_size([{_MFA,_Insns,CodeSize,_LabelMap}|Code], Size) ->  compute_code_size(Code, Size+CodeSize);compute_code_size([], Size) -> Size.build_export_map([{{M,F,A},_Insns,CodeSize,_LabelMap}|Code], Address, ExportMap) ->  build_export_map(Code, Address+CodeSize, [{Address,M,F,A}|ExportMap]);build_export_map([], _Address, ExportMap) -> ExportMap.combine_label_maps([{MFA,_Insns,CodeSize,LabelMap}|Code], Address, CLM) ->  NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),  combine_label_maps(Code, Address+CodeSize, NewCLM);combine_label_maps([], _Address, CLM) -> CLM.merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->  NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),  merge_label_map(Rest, MFA, Address, NewCLM);merge_label_map([], _MFA, _Address, CLM) -> CLM.encode_mfas([{MFA,Insns,CodeSize,LabelMap}|Code], Address, AccCode, Relocs, Options) ->  print("Generating code for: ~w\n", [MFA], Options),  print("Offset   | Opcode   | Instruction\n", [], Options),  {Address1,Relocs1,AccCode1} =    encode_insns(Insns, Address, Address, LabelMap, Relocs, AccCode, Options),  ExpectedAddress = Address + CodeSize,  ?ASSERT(Address1 =:= ExpectedAddress),  print("Finished.\n", [], Options),  encode_mfas(Code, Address1, AccCode1, Relocs1, Options);encode_mfas([], _Address, AccCode, Relocs, _Options) ->  {AccCode,Relocs}.encode_insns([I|Insns], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->  case I of    {'.label',L,_} ->      LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,      ?ASSERT(Address =:= LabelAddress),	% sanity check      print_insn(Address, [], I, Options),      encode_insns(Insns, Address, FunAddress, LabelMap, Relocs, AccCode, Options);    {'.reloc',Data,_} ->      print_insn(Address, [], I, Options),      Reloc = encode_reloc(Data, Address, FunAddress, LabelMap),      encode_insns(Insns, Address, FunAddress, LabelMap, [Reloc|Relocs], AccCode, Options);    {'.long',Value,_} ->      print_insn(Address, Value, I, Options),      Segment = <<Value:32/integer-big>>,      NewAccCode = [Segment|AccCode],      encode_insns(Insns, Address+4, FunAddress, LabelMap, Relocs, NewAccCode, Options);    _ ->      {Op,Arg,_} = fix_pc_refs(I, Address, FunAddress, LabelMap),      Word = hipe_arm_encode:insn_encode(Op, Arg),      print_insn(Address, Word, I, Options),      Segment = <<Word:32/integer-big>>,      NewAccCode = [Segment|AccCode],      encode_insns(Insns, Address+4, FunAddress, LabelMap, Relocs, NewAccCode, Options)  end;encode_insns([], Address, _FunAddress, _LabelMap, Relocs, AccCode, _Options) ->  {Address,Relocs,AccCode}.encode_reloc(Data, Address, FunAddress, LabelMap) ->  case Data of    {b_fun,MFAorPrim,Linkage} ->      %% b and bl are patched the same, so no need to distinguish      %% call from tailcall      PatchTypeExt =	case Linkage of	  remote -> ?CALL_REMOTE;	  not_remote -> ?CALL_LOCAL	end,      {PatchTypeExt, Address, untag_mfa_or_prim(MFAorPrim)};    {load_atom,Atom} ->      {?LOAD_ATOM, Address, Atom};    {load_address,X} ->      {?LOAD_ADDRESS, Address, X};    {sdesc,SDesc} ->      #arm_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live} = SDesc,      ExnRA =	case ExnLab of	  [] -> [];	% don't cons up a new one	  ExnLab -> gb_trees:get(ExnLab, LabelMap) + FunAddress	end,      {?SDESC, Address,       ?STACK_DESC(ExnRA, FSize, Arity, Live)}  end.untag_mfa_or_prim(#arm_mfa{m=M,f=F,a=A}) -> {M,F,A};untag_mfa_or_prim(#arm_prim{prim=Prim}) -> Prim.fix_pc_refs(I, InsnAddress, FunAddress, LabelMap) ->  case I of    {b, {Cond,{label,L}}, OrigI} ->      LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,      Imm24 = (LabelAddress - (InsnAddress+8)) div 4,      %% ensure Imm24 fits in a 24 bit sign-extended field      ?ASSERT(Imm24 =<   16#7FFFFF),      ?ASSERT(Imm24 >= -(16#800000)),      {b, {Cond,{imm24,Imm24 band 16#FFFFFF}}, OrigI};    {'.pseudo_li', {Dst,{label,L}}, OrigI} ->      LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,      Offset = LabelAddress - (InsnAddress+8),      {Sign,Imm12} =	if Offset < 0 -> {'-', -Offset};	   true -> {'+', Offset}	end,      ?ASSERT(Imm12 =< 16#FFF),      Am2 = {'immediate_offset',{r,15},Sign,{imm12,Imm12}},      {ldr, {do_cond('al'),Dst,Am2}, OrigI};    _ -> I  end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%mk_data_relocs(RefsFromConsts, LabelMap) ->  lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->  Map = [case Label of	   {L,Pos} ->	     Offset = find({MFA,L}, LabelMap),	     {Pos,Offset};	   {sorted,Base,OrderedLabels} ->	     {sorted, Base, [begin			       Offset = find({MFA,L}, LabelMap),			       {Order, Offset}			     end			     || {L,Order} <- OrderedLabels]}	 end	 || Label <- Labels],  %% msg("Map: ~w Map\n",[Map]),  mk_data_relocs(Rest, LabelMap, [Map,Acc]);mk_data_relocs([],_,Acc) -> Acc.find({MFA,L},LabelMap) ->  gb_trees:get({MFA,L}, LabelMap).slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->  IsClosure = lists:member({M,F,A}, Closures),  IsExported = is_exported(F, A, Exports),  [Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];slim_sorted_exportmap([],_,_) -> [].is_exported(F, A, Exports) -> lists:member({F,A}, Exports).%%%%%% Assembly listing support (pp_asm option).%%%print(String, Arglist, Options) ->  ?when_option(pp_asm, Options, io:format(String, Arglist)).print_insn(Address, Word, I, Options) ->  ?when_option(pp_asm, Options, print_insn_2(Address, Word, I)).print_insn_2(Address, Word, {NewI,NewArgs,OrigI}) ->  io:format("~8.16.0b | ", [Address]),  print_code_list(word_to_bytes(Word), 0),  case NewI of    '.long' ->      io:format("\t.long ~.16x\n", [Word, "0x"]);    '.reloc' ->      io:format("\t.reloc ~w\n", [NewArgs]);    _ ->      hipe_arm_pp:pp_insn(OrigI)  end.word_to_bytes(W) ->  case W of    [] -> [];	% label or other pseudo instruction    _ -> [(W bsr 24) band 16#FF, (W bsr 16) band 16#FF,	  (W bsr 8) band 16#FF, W band 16#FF]  end.print_code_list([Byte|Rest], Len) ->  print_byte(Byte),  print_code_list(Rest, Len+1);print_code_list([], Len) ->  fill_spaces(8-(Len*2)),  io:format(" | ").print_byte(Byte) ->  io:format("~2.16.0b", [Byte band 16#FF]).fill_spaces(N) when N > 0 ->  io:format(" "),  fill_spaces(N-1);fill_spaces(0) ->  [].%%%%%% Lookup a constant in a ConstMap.%%%find_const({MFA,Label},[{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->  ConstNo;find_const(N,[_|R]) ->  find_const(N,R);find_const(C,[]) ->  ?EXIT({constant_not_found,C}).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ADT for previous immediates.%%% This is a queue (fifo) of the previously defined immediates,%%% plus a mapping from these immediates to their labels.%%%-record(previous, {set, head, tail}). % INV: tail=[] if head=[]previous_empty() -> #previous{set=gb_trees:empty(), head=[], tail=[]}.previous_lookup(#previous{set=S}, Imm) -> gb_trees:lookup(Imm, S).previous_findmin(#previous{head=H}) ->  case H of    [X|_] -> X;    _ -> []  end.previous_delmin(#previous{set=S, head=[{_Address,Imm}|H], tail=T}) ->  {NewH,NewT} =    case H of      [] -> {lists:reverse(T), []};      _ -> {H, T}    end,  #previous{set=gb_trees:delete(Imm, S), head=NewH, tail=NewT}.previous_append(#previous{set=S, head=H, tail=T}, Address, Lab, Imm) ->  {NewH,NewT} =    case H of      [] -> {[{Address,Imm}], []};      _  -> {H, [{Address,Imm}|T]}    end,  #previous{set=gb_trees:insert(Imm, Lab, S), head=NewH, tail=NewT}.%%%%%% ADT for pending immediates.%%% This is a queue (fifo) of immediates pending definition,%%% plus a mapping from these immediates to their labels,%%% and a recording of the first (lowest) code address referring%%% to a pending immediate.%%%-record(pending, {set, list, firstref}).pending_empty() -> #pending{set=gb_trees:empty(), list=[], firstref=[]}.pending_to_list(#pending{list=L}) -> lists:reverse(L).pending_lookup(#pending{set=S}, Imm) -> gb_trees:lookup(Imm, S).pending_firstref(#pending{firstref=F}) -> F.pending_append(#pending{set=S, list=L, firstref=F}, Address, Lab, RelocOrInt, Imm) ->  #pending{set=gb_trees:insert(Imm, Lab, S),	   list=[{Lab,RelocOrInt,Imm}|L],	   firstref=case F of [] -> Address; _ -> F end}.pending_size(#pending{list=L}) -> length(L).

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?