{ Copyright (c) 2002 by Florian Klaempfl This unit implements an asmoutput class for PowerPC with MPW syntax This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **************************************************************************** } { This unit implements an asmoutput class for PowerPC with MPW syntax } unit agppcmpw; {$i fpcdefs.inc} { We know that use_PR is a const boolean but we don't care about this warning } {$WARN 6018 OFF} interface uses aasmtai,aasmdata, globals,aasmbase,aasmcpu,assemble, cpubase; type TPPCMPWAssembler = class(TExternalAssembler) procedure WriteTree(p:TAsmList);override; procedure WriteAsmList;override; Function DoAssemble:boolean;override; procedure WriteExternals; procedure WriteAsmFileHeader; private cur_CSECT_name: String; cur_CSECT_class: String; procedure WriteInstruction(hp : tai); procedure WriteProcedureHeader(var hp:tai); procedure WriteDataHeader(var s:string; isExported, isConst:boolean); end; implementation uses cutils,globtype,systems,cclasses, verbose,finput,fmodule,cscript,cpuinfo, cgbase,cgutils, itcpugas ; const line_length = 70; {Whether internal procedure references should be xxx[PR]: } use_PR = false; const_storage_class = ''; var_storage_class = ''; secnames : array[TAsmSectiontype] of string[10] = ( '', {none} '', {user} 'csect', {code} 'csect', {data} 'csect', {read only data} 'csect', {read only data - no relocations} 'csect', {bss} 'csect', '', 'csect','csect','csect','csect','csect', 'csect','csect','csect', '','','','','','','','','','','','','','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ); type t64bitarray = array[0..7] of byte; t32bitarray = array[0..3] of byte; function ReplaceForbiddenChars(var s: string):Boolean; {Returns wheater a replacement has occurred.} var i:Integer; {The dollar sign is not allowed in MPW PPCAsm} begin ReplaceForbiddenChars:=false; for i:=1 to Length(s) do if s[i]='$' then begin s[i]:='s'; ReplaceForbiddenChars:=true; end; end; {*** From here is copyed from agppcgas.pp, except where marked with CHANGED. Perhaps put in a third common file. ***} function getreferencestring(var ref : treference) : string; var s : string; begin with ref do begin if (refaddr <> addr_no) then InternalError(2002110301) else if ((offset < -32768) or (offset > 32767)) then InternalError(19991); if assigned(symbol) then begin s:= symbol.name; ReplaceForbiddenChars(s); {if symbol.typ = AT_FUNCTION then ;} s:= s+'[TC]' {ref to TOC entry } end else s:= ''; if offset<0 then s:=s+tostr(offset) else if (offset>0) then begin if assigned(symbol) then s:=s+'+'+tostr(offset) else s:=s+tostr(offset); end; if (index=NR_NO) and (base<>NR_NO) then begin if offset=0 then if not assigned(symbol) then s:=s+'0'; s:=s+'('+gas_regname(base)+')'; end else if (index<>NR_NO) and (base<>NR_NO) and (offset=0) then begin if (offset=0) then s:=s+gas_regname(base)+','+gas_regname(index) else internalerror(19992); end else if (base=NR_NO) and (offset=0) then begin {Temporary fix for inline asm, where a local var is referenced.} //if assigned(symbol) then // s:= s+'(rtoc)'; end; end; getreferencestring:=s; end; function getopstr_jmp(const o:toper) : string; var hs : string; begin case o.typ of top_reg : getopstr_jmp:=gas_regname(o.reg); { no top_ref jumping for powerpc } top_const : getopstr_jmp:=tostr(o.val); top_ref : begin if o.ref^.refaddr=addr_full then begin hs:=o.ref^.symbol.name; ReplaceForbiddenChars(hs); case o.ref^.symbol.typ of AT_FUNCTION: begin if hs[1] <> '@' then {if not local label} if use_PR then hs:= '.'+hs+'[PR]' else hs:= '.'+hs end else ; end; if o.ref^.offset>0 then hs:=hs+'+'+tostr(o.ref^.offset) else if o.ref^.offset<0 then hs:=hs+tostr(o.ref^.offset); getopstr_jmp:=hs; end else internalerror(200402263); end; top_none: getopstr_jmp:=''; else internalerror(2002070603); end; end; function getopstr(const o:toper) : string; var hs : string; begin case o.typ of top_reg: getopstr:=gas_regname(o.reg); top_const: getopstr:=tostr(longint(o.val)); top_ref: if o.ref^.refaddr=addr_no then getopstr:=getreferencestring(o.ref^) else if o.ref^.refaddr=addr_pic_no_got then begin if (o.ref^.base<>NR_RTOC) or (o.ref^.index<>NR_NO) or (o.ref^.offset<>0) or not assigned(o.ref^.symbol) then internalerror(2011122701); hs:=o.ref^.symbol.name; ReplaceForbiddenChars(hs); hs:=hs+'[TC](RTOC)'; getopstr:=hs; end else begin hs:=o.ref^.symbol.name; ReplaceForbiddenChars(hs); if o.ref^.offset>0 then hs:=hs+'+'+tostr(o.ref^.offset) else if o.ref^.offset<0 then hs:=hs+tostr(o.ref^.offset); getopstr:=hs; end; else internalerror(2002070604); end; end; type topstr = string[4]; function branchmode(o: tasmop): topstr; var tempstr: topstr; begin tempstr := ''; case o of A_BCCTR,A_BCCTRL: tempstr := 'ctr'; A_BCLR,A_BCLRL: tempstr := 'lr'; else ; end; case o of A_BL,A_BLA,A_BCL,A_BCLA,A_BCCTRL,A_BCLRL: tempstr := tempstr+'l'; else ; end; case o of A_BA,A_BLA,A_BCA,A_BCLA: tempstr:=tempstr+'a'; else ; end; branchmode := tempstr; end; function cond2str(op: tasmop; c: tasmcond): string; { note: no checking is performed whether the given combination of } { conditions is valid } var tempstr: string; begin tempstr:=#9; case c.simple of false: begin cond2str := tempstr+gas_op2str[op]; case c.dirhint of DH_None:; DH_Minus: cond2str:=cond2str+'-'; DH_Plus: cond2str:=cond2str+'+'; else internalerror(2003112901); end; cond2str:=cond2str+#9+tostr(c.bo)+','+tostr(c.bi)+','; end; true: if (op >= A_B) and (op <= A_BCLRL) then case c.cond of { unconditional branch } C_NONE: cond2str := tempstr+gas_op2str[op]; { bdnzt etc } else begin tempstr := tempstr+'b'+asmcondflag2str[c.cond]+ branchmode(op); case c.dirhint of DH_None: tempstr:=tempstr+#9; DH_Minus: tempstr:=tempstr+('-'+#9); DH_Plus: tempstr:=tempstr+('+'+#9); else internalerror(2003112904); end; case c.cond of C_LT..C_NU: cond2str := tempstr+gas_regname(newreg(R_SPECIALREGISTER,c.cr,R_SUBWHOLE)); C_T,C_F,C_DNZT,C_DNZF,C_DZT,C_DZF: cond2str := tempstr+tostr(c.crbit); else cond2str := tempstr; end; end; end { we have a trap instruction } else begin internalerror(2002070601); { not yet implemented !!!!!!!!!!!!!!!!!!!!! } { case tempstr := 'tw';} end; end; end; procedure TPPCMPWAssembler.WriteInstruction(hp : tai); var op: TAsmOp; s: string; i: byte; sep: string[3]; begin op:=taicpu(hp).opcode; if is_calljmp(op) then begin { direct BO/BI in op[0] and op[1] not supported, put them in condition! } case op of A_B,A_BA: s:=#9+gas_op2str[op]+#9; A_BCTR,A_BCTRL,A_BLR,A_BLRL: s:=#9+gas_op2str[op]; A_BL,A_BLA: s:=#9+gas_op2str[op]+#9; else begin s:=cond2str(op,taicpu(hp).condition); if (s[length(s)] <> #9) and (taicpu(hp).ops>0) then s := s + ','; end; end; if (taicpu(hp).ops>0) and (taicpu(hp).oper[0]^.typ<>top_none) then begin { first write the current contents of s, because the symbol } { may be 255 characters } writer.AsmWrite(s); s:=getopstr_jmp(taicpu(hp).oper[0]^); end; end else { process operands } begin s:=#9+gas_op2str[op]; if taicpu(hp).ops<>0 then begin sep:=#9; for i:=0 to taicpu(hp).ops-1 do begin s:=s+sep+getopstr(taicpu(hp).oper[i]^); sep:=','; end; end; end; writer.AsmWriteLn(s); end; {*** Until here is copyed from agppcgas.pp. ***} function single2str(d : single) : string; var hs : string; p : byte; begin str(d,hs); { nasm expects a lowercase e } p:=pos('E',hs); if p>0 then hs[p]:='e'; p:=pos('+',hs); if p>0 then delete(hs,p,1); single2str:=lower(hs); end; function double2str(d : double) : string; var hs : string; p : byte; begin str(d,hs); { nasm expects a lowercase e } p:=pos('E',hs); if p>0 then hs[p]:='e'; p:=pos('+',hs); if p>0 then delete(hs,p,1); double2str:=lower(hs); end; { convert floating point values } { to correct endian } procedure swap64bitarray(var t: t64bitarray); var b: byte; begin b:= t[7]; t[7] := t[0]; t[0] := b; b := t[6]; t[6] := t[1]; t[1] := b; b:= t[5]; t[5] := t[2]; t[2] := b; b:= t[4]; t[4] := t[3]; t[3] := b; end; procedure swap32bitarray(var t: t32bitarray); var b: byte; begin b:= t[1]; t[1]:= t[2]; t[2]:= b; b:= t[0]; t[0]:= t[3]; t[3]:= b; end; Function PadTabs(const p:string;addch:char):string; var s : string; i : longint; begin i:=length(p); if addch<>#0 then begin inc(i); s:=p+addch; end else s:=p; if i<8 then PadTabs:=s+#9#9 else PadTabs:=s+#9; end; {**************************************************************************** PowerPC MPW Assembler ****************************************************************************} procedure TPPCMPWAssembler.WriteProcedureHeader(var hp:tai); {Returns the current hp where the caller should continue from} {For multiple entry procedures, only the last is exported as xxx[PR] (if use_PR is set) } procedure WriteExportHeader(hp:tai); var s: string; replaced: boolean; begin s:= tai_symbol(hp).sym.name; replaced:= ReplaceForbiddenChars(s); if not use_PR then begin writer.AsmWrite(#9'export'#9'.'); writer.AsmWrite(s); if replaced then begin writer.AsmWrite(' => ''.'); writer.AsmWrite(tai_symbol(hp).sym.name); writer.AsmWrite(''''); end; writer.AsmLn; end; writer.AsmWrite(#9'export'#9); writer.AsmWrite(s); writer.AsmWrite('[DS]'); if replaced then begin writer.AsmWrite(' => '''); writer.AsmWrite(tai_symbol(hp).sym.name); writer.AsmWrite('[DS]'''); end; writer.AsmLn; {Entry in transition vector: } writer.AsmWrite(#9'csect'#9); writer.AsmWrite(s); writer.AsmWriteLn('[DS]'); writer.AsmWrite(#9'dc.l'#9'.'); writer.AsmWriteLn(s); writer.AsmWriteln(#9'dc.l'#9'TOC[tc0]'); {Entry in TOC: } writer.AsmWriteLn(#9'toc'); writer.AsmWrite(#9'tc'#9); writer.AsmWrite(s); writer.AsmWrite('[TC],'); writer.AsmWrite(s); writer.AsmWriteln('[DS]'); end; function GetAdjacentTaiSymbol(var hp:tai):Boolean; begin GetAdjacentTaiSymbol:= false; while assigned(hp.next) do case tai(hp.next).typ of ait_symbol: begin hp:=tai(hp.next); GetAdjacentTaiSymbol:= true; Break; end; ait_function_name: hp:=tai(hp.next); else begin //writer.AsmWriteln(' ;#*#*# ' + tostr(Ord(tai(hp.next).typ))); Break; end; end; end; var first,last: tai; s: string; replaced: boolean; begin s:= tai_symbol(hp).sym.name; {Write all headers} first:= hp; repeat WriteExportHeader(hp); last:= hp; until not GetAdjacentTaiSymbol(hp); {Start the section of the body of the proc: } s:= tai_symbol(last).sym.name; replaced:= ReplaceForbiddenChars(s); if use_PR then begin writer.AsmWrite(#9'export'#9'.'); writer.AsmWrite(s); writer.AsmWrite('[PR]'); if replaced then begin writer.AsmWrite(' => ''.'); writer.AsmWrite(tai_symbol(last).sym.name); writer.AsmWrite('[PR]'''); end; writer.AsmLn; end; {Starts the section: } writer.AsmWrite(#9'csect'#9'.'); writer.AsmWrite(s); writer.AsmWriteLn('[PR]'); {Info for the debugger: } writer.AsmWrite(#9'function'#9'.'); writer.AsmWrite(s); writer.AsmWriteLn('[PR]'); {Write all labels: } hp:= first; repeat s:= tai_symbol(hp).sym.name; ReplaceForbiddenChars(s); writer.AsmWrite('.'); writer.AsmWrite(s); writer.AsmWriteLn(':'); until not GetAdjacentTaiSymbol(hp); end; procedure TPPCMPWAssembler.WriteDataHeader(var s:string; isExported, isConst:boolean); // Returns in s the changed string var sym: string; replaced: boolean; begin sym:= s; replaced:= ReplaceForbiddenChars(s); if isExported then begin writer.AsmWrite(#9'export'#9); writer.AsmWrite(s); if isConst then writer.AsmWrite(const_storage_class) else writer.AsmWrite(var_storage_class); if replaced then begin writer.AsmWrite(' => '''); writer.AsmWrite(sym); writer.AsmWrite(''''); end; writer.AsmLn; end; if not macos_direct_globals then begin {The actual section is here interrupted, by inserting a "tc" entry} writer.AsmWriteLn(#9'toc'); writer.AsmWrite(#9'tc'#9); writer.AsmWrite(s); writer.AsmWrite('[TC], '); writer.AsmWrite(s); if isConst then writer.AsmWrite(const_storage_class) else writer.AsmWrite(var_storage_class); writer.AsmLn; {The interrupted section is here continued.} writer.AsmWrite(#9'csect'#9); writer.AsmWriteln(cur_CSECT_name+cur_CSECT_class); writer.AsmWrite(PadTabs(s+':',#0)); end else begin writer.AsmWrite(#9'csect'#9); writer.AsmWrite(s); writer.AsmWrite('[TC]'); end; writer.AsmLn; end; const ait_const2str:array[aitconst_32bit..aitconst_8bit] of string[8]= (#9'dc.l'#9,#9'dc.w'#9,#9'dc.b'#9); procedure TPPCMPWAssembler.WriteTree(p:TAsmList); var s : string; hp : tai; counter, lines, InlineLevel : longint; i,j,l : longint; consttype : taiconst_type; do_line,DoNotSplitLine, quoted : boolean; begin if not assigned(p) then exit; InlineLevel:=0; { lineinfo is only needed for al_procedures (PFV) } do_line:=((cs_asm_source in current_settings.globalswitches) or (cs_lineinfo in current_settings.moduleswitches)) and (p=current_asmdata.asmlists[al_procedures]); DoNotSplitLine:=false; hp:=tai(p.first); while assigned(hp) do begin prefetch(pointer(hp.next)^); if not(hp.typ in SkipLineInfo) then begin current_filepos:=tailineinfo(hp).fileinfo; { no line info for inlined code } if do_line and (inlinelevel=0) and not DoNotSplitLine then WriteSourceLine(hp as tailineinfo); end; DoNotSplitLine:=false; case hp.typ of ait_comment: begin writer.AsmWrite(asminfo^.comment); writer.AsmWritePChar(tai_comment(hp).str); writer.AsmLn; end; ait_regalloc, ait_tempalloc: ; ait_section: begin ResetSourceLines; {if LastSecType<>sec_none then writer.AsmWriteLn('_'+asminfo^.secnames[LastSecType]+#9#9'ENDS');} if tai_section(hp).sectype<>sec_none then begin if tai_section(hp).sectype in [sec_data,sec_rodata,sec_bss] then cur_CSECT_class:= '[RW]' else if tai_section(hp).sectype in [sec_code] then cur_CSECT_class:= '' else cur_CSECT_class:= '[RO]'; s:= tai_section(hp).name^; if s = '' then InternalError(2004101001); {Nameless sections should not occur on MPW} ReplaceForbiddenChars(s); cur_CSECT_name:= s; writer.AsmLn; writer.AsmWriteLn(#9+secnames[tai_section(hp).sectype]+' '+cur_CSECT_name+cur_CSECT_class); end; LastSecType:=tai_section(hp).sectype; end; ait_align: begin case tai_align(hp).aligntype of 1:writer.AsmWriteLn(#9'align 0'); 2:writer.AsmWriteLn(#9'align 1'); 4:writer.AsmWriteLn(#9'align 2'); otherwise internalerror(2002110302); end; end; ait_datablock: {Storage for global variables.} begin s:= tai_datablock(hp).sym.name; WriteDataHeader(s, tai_datablock(hp).is_global, false); if not macos_direct_globals then begin writer.AsmWriteLn(#9'ds.b '+tostr(tai_datablock(hp).size)); end else begin writer.AsmWriteLn(PadTabs(s+':',#0)+'ds.b '+tostr(tai_datablock(hp).size)); {TODO: ? PadTabs(s,#0) } end; end; ait_const: begin consttype:=tai_const(hp).consttype; case consttype of aitconst_128bit: begin internalerror(2004042904); end; aitconst_64bit: begin if assigned(tai_const(hp).sym) then internalerror(2004042905); writer.AsmWrite(ait_const2str[aitconst_32bit]); if target_info.endian = endian_little then begin writer.AsmWrite(tostr(longint(lo(tai_const(hp).value)))); writer.AsmWrite(','); writer.AsmWrite(tostr(longint(hi(tai_const(hp).value)))); end else begin writer.AsmWrite(tostr(longint(hi(tai_const(hp).value)))); writer.AsmWrite(','); writer.AsmWrite(tostr(longint(lo(tai_const(hp).value)))); end; writer.AsmLn; end; aitconst_uleb128bit, aitconst_sleb128bit, aitconst_32bit, aitconst_16bit, aitconst_8bit, aitconst_rva_symbol : begin writer.AsmWrite(ait_const2str[consttype]); l:=0; repeat if assigned(tai_const(hp).sym) then begin if assigned(tai_const(hp).endsym) then begin if (tai_const(hp).endsym.typ = AT_FUNCTION) and use_PR then writer.AsmWrite('.'); s:=tai_const(hp).endsym.name; ReplaceForbiddenChars(s); writer.AsmWrite(s); inc(l,length(s)); if tai_const(hp).endsym.typ = AT_FUNCTION then begin if use_PR then writer.AsmWrite('[PR]') else writer.AsmWrite('[DS]'); end; writer.AsmWrite('-'); inc(l,5); {Approx 5 extra, no need to be exactly} end; if (tai_const(hp).sym.typ = AT_FUNCTION) and use_PR then writer.AsmWrite('.'); s:= tai_const(hp).sym.name; ReplaceForbiddenChars(s); writer.AsmWrite(s); inc(l,length(s)); if tai_const(hp).sym.typ = AT_FUNCTION then begin if use_PR then writer.AsmWrite('[PR]') else writer.AsmWrite('[DS]'); end; inc(l,5); {Approx 5 extra, no need to be exactly} if tai_const(hp).value > 0 then s:= '+'+tostr(tai_const(hp).value) else if tai_const(hp).value < 0 then s:= '-'+tostr(tai_const(hp).value) else s:= ''; if s<>'' then begin writer.AsmWrite(s); inc(l,length(s)); end; end else begin s:= tostr(tai_const(hp).value); writer.AsmWrite(s); inc(l,length(s)); end; if (l>line_length) or (hp.next=nil) or (tai(hp.next).typ<>ait_const) or (tai_const(hp.next).consttype<>consttype) then break; hp:=tai(hp.next); writer.AsmWrite(','); until false; writer.AsmLn; end; else internalerror(2019050950); end; end; ait_realconst: begin WriteRealConstAsBytes(tai_realconst(hp),#9'dc.b'#9,do_line); end; ait_string: begin {NOTE When a single quote char is encountered, it is replaced with a numeric ascii value. It could also have been replaced with the escape seq of double quotes. Backslash seems to be used as an escape char, although this is not mentioned in the PPCAsm documentation.} counter := 0; lines := tai_string(hp).len div line_length; { separate lines in different parts } if tai_string(hp).len > 0 then begin for j := 0 to lines-1 do begin writer.AsmWrite(#9'dc.b'#9); quoted:=false; for i:=counter to counter+line_length-1 do begin { it is an ascii character. } if (ord(tai_string(hp).str[i])>31) and (ord(tai_string(hp).str[i])<128) and (tai_string(hp).str[i]<>'''') and (tai_string(hp).str[i]<>'\') then begin if not(quoted) then begin if i>counter then writer.AsmWrite(','); writer.AsmWrite(''''); end; writer.AsmWrite(tai_string(hp).str[i]); quoted:=true; end { if > 31 and < 128 and ord('"') } else begin if quoted then writer.AsmWrite(''''); if i>counter then writer.AsmWrite(','); quoted:=false; writer.AsmWrite(tostr(ord(tai_string(hp).str[i]))); end; end; { end for i:=0 to... } if quoted then writer.AsmWrite(''''); writer.AsmLn; counter := counter+line_length; end; { end for j:=0 ... } { do last line of lines } if counter < tai_string(hp).len then writer.AsmWrite(#9'dc.b'#9); quoted:=false; for i:=counter to tai_string(hp).len-1 do begin { it is an ascii character. } if (ord(tai_string(hp).str[i])>31) and (ord(tai_string(hp).str[i])<128) and (tai_string(hp).str[i]<>'''') and (tai_string(hp).str[i]<>'\') then begin if not(quoted) then begin if i>counter then writer.AsmWrite(','); writer.AsmWrite(''''); end; writer.AsmWrite(tai_string(hp).str[i]); quoted:=true; end { if > 31 and < 128 and " } else begin if quoted then writer.AsmWrite(''''); if i>counter then writer.AsmWrite(','); quoted:=false; writer.AsmWrite(tostr(ord(tai_string(hp).str[i]))); end; end; { end for i:=0 to... } if quoted then writer.AsmWrite(''''); end; writer.AsmLn; end; ait_label: begin if tai_label(hp).labsym.is_used then begin s:= tai_label(hp).labsym.name; if s[1] = '@' then begin ReplaceForbiddenChars(s); //Local labels: writer.AsmWriteLn(s+':') end else begin //Procedure entry points: if not macos_direct_globals then begin WriteDataHeader(s, tai_label(hp).labsym.bind in [AB_GLOBAL,AB_PRIVATE_EXTERN], true); end else begin ReplaceForbiddenChars(s); writer.AsmWrite(#9'csect'#9); writer.AsmWrite(s); writer.AsmWriteLn('[TC]'); writer.AsmWriteLn(PadTabs(s+':',#0)); end; end; end; end; ait_symbol: begin if tai_symbol(hp).sym.typ=AT_FUNCTION then WriteProcedureHeader(hp) else if tai_symbol(hp).sym.typ in [AT_DATA,AT_METADATA] then begin s:= tai_symbol(hp).sym.name; WriteDataHeader(s, tai_symbol(hp).is_global, true); if macos_direct_globals then begin writer.AsmWrite(s); writer.AsmWriteLn(':'); end; end else InternalError(2003071301); end; ait_symbol_end: ; ait_instruction: WriteInstruction(hp); ait_stab, ait_force_line, ait_function_name : ; ait_cutobject : begin InternalError(2004101101); {Smart linking is done transparently by the MPW linker.} end; ait_marker : begin if tai_marker(hp).kind=mark_NoLineInfoStart then inc(InlineLevel) else if tai_marker(hp).kind=mark_NoLineInfoEnd then dec(InlineLevel); end; ait_directive : if tai_directive(hp).directive=asd_cpu then begin writer.AsmWrite(asminfo^.comment+' CPU '); if tai_directive(hp).name<>'' then writer.AsmWrite(tai_directive(hp).name); writer.AsmLn; end else internalerror(2016022601); else internalerror(2002110303); end; hp:=tai(hp.next); end; end; var currentasmlist : TExternalAssembler; procedure writeexternal(p:tasmsymbol); var s:string; replaced: boolean; begin if tasmsymbol(p).bind in [AB_EXTERNAL,AB_EXTERNAL_INDIRECT] then begin //Writeln('ZZZ ',p.name,' ',p.typ); s:= p.name; replaced:= ReplaceForbiddenChars(s); with currentasmlist do case tasmsymbol(p).typ of AT_FUNCTION: begin writer.AsmWrite(#9'import'#9'.'); writer.AsmWrite(s); if use_PR then writer.AsmWrite('[PR]'); if replaced then begin writer.AsmWrite(' <= ''.'); writer.AsmWrite(p.name); if use_PR then writer.AsmWrite('[PR]''') else writer.AsmWrite(''''); end; writer.AsmLn; writer.AsmWrite(#9'import'#9); writer.AsmWrite(s); writer.AsmWrite('[DS]'); if replaced then begin writer.AsmWrite(' <= '''); writer.AsmWrite(p.name); writer.AsmWrite('[DS]'''); end; writer.AsmLn; writer.AsmWriteLn(#9'toc'); writer.AsmWrite(#9'tc'#9); writer.AsmWrite(s); writer.AsmWrite('[TC],'); writer.AsmWrite(s); writer.AsmWriteLn('[DS]'); end; AT_DATA: begin writer.AsmWrite(#9'import'#9); writer.AsmWrite(s); writer.AsmWrite(var_storage_class); if replaced then begin writer.AsmWrite(' <= '''); writer.AsmWrite(p.name); writer.AsmWrite(''''); end; writer.AsmLn; writer.AsmWriteLn(#9'toc'); writer.AsmWrite(#9'tc'#9); writer.AsmWrite(s); writer.AsmWrite('[TC],'); writer.AsmWrite(s); writer.AsmWriteLn(var_storage_class); end else InternalError(2003090901); end; end; end; procedure TPPCMPWAssembler.WriteExternals; var i : longint; begin currentasmlist:=self; // current_asmdata.asmsymboldict.foreach_static(@writeexternal,nil); for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do begin writeexternal(tasmsymbol(current_asmdata.AsmSymbolDict[i])); end; end; function TPPCMPWAssembler.DoAssemble : boolean; begin DoAssemble:=Inherited DoAssemble; end; procedure TPPCMPWAssembler.WriteAsmFileHeader; begin writer.AsmWriteLn(#9'string asis'); {Interpret strings just to be the content between the quotes.} writer.AsmWriteLn(#9'aligning off'); {We do our own aligning.} writer.AsmLn; end; procedure TPPCMPWAssembler.WriteAsmList; var hal : tasmlisttype; begin {$ifdef EXTDEBUG} if current_module.mainsource<>'' then comment(v_info,'Start writing MPW-styled assembler output for '+current_module.mainsource); {$endif} WriteAsmFileHeader; WriteExternals; for hal:=low(TasmlistType) to high(TasmlistType) do begin writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmListTypeStr[hal]); writetree(current_asmdata.asmlists[hal]); writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmListTypeStr[hal]); end; writer.AsmWriteLn(#9'end'); writer.AsmLn; {$ifdef EXTDEBUG} if current_module.mainsource<>'' then comment(v_info,'Done writing MPW-styled assembler output for '+current_module.mainsource); {$endif EXTDEBUG} end; {***************************************************************************** Initialize *****************************************************************************} const as_powerpc_mpw_info : tasminfo = ( id : as_powerpc_mpw; idtxt : 'MPW'; asmbin : 'PPCAsm'; asmcmd : '-case on $ASM $EXTRAOPT -o $OBJ'; supported_targets : [system_powerpc_macosclassic]; flags : [af_needar,af_smartlink_sections,af_labelprefix_only_inside_procedure]; labelprefix : '@'; labelmaxlen : -1; comment : '; '; dollarsign: 's'; ); initialization RegisterAssembler(as_powerpc_mpw_info,TPPCMPWAssembler); end.