{ Copyright (c) 1998-2002 by Florian Klaempfl This unit implements an asmoutput class for Intel syntax with Intel i386+ 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 Intel syntax with Intel i386+ } unit agx86int; {$i fpcdefs.inc} interface uses cpubase,constexp, aasmbase,aasmtai,aasmdata,aasmcpu,assemble,cgutils; type Tx86IntelAssembler = class(TExternalAssembler) private procedure WriteReference(var ref : treference); procedure WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean); procedure WriteOper_jmp(const o:toper;s : topsize); public function single2str(d : single) : string; override; function double2str(d : double) : string; override; function extended2str(e : extended) : string; override; function comp2str(d : bestreal) : string; procedure WriteTree(p:TAsmList);override; procedure WriteAsmList;override; Function DoAssemble:boolean;override; procedure WriteExternals; end; implementation uses SysUtils,math, cutils,globtype,globals,systems,cclasses, verbose,cscript,cpuinfo, itx86int, cgbase {$ifdef EXTDEBUG} ,fmodule {$endif EXTDEBUG} ; const line_length = 70; max_tokens : longint = 25; (* wasm_cpu_name : array[tcputype] of string = ( {$if defined(x86_64)} 'IA64', // cpu_none, '686', // cpu_athlon64, '686', // cpu_core_i, '686', // cpu_core_avx, '686' // cpu_core_avx2 {$elseif defined(i386)} 'IA64', // cpu_none, '386', // cpu_386, '486', // cpu_486, '586', // cpu_Pentium, '686', // cpu_Pentium2, '686', // cpu_Pentium3, '686', // cpu_Pentium4, '686', // cpu_PentiumM, '686', // cpu_core_i, '686', // cpu_core_avx, '686' // cpu_core_avx2 {$elseif defined(i8086)} 'IA64', // cpu_none '8086', // cpu_8086 '186', // cpu_186 '286', // cpu_286 '386', // cpu_386 '486', // cpu_486 '586', // cpu_Pentium '686', // cpu_Pentium2 '686', // cpu_Pentium3 '686', // cpu_Pentium4 '686' // cpu_PentiumM {$endif} ); *) secnames : array[TAsmSectiontype] of string[4] = ('','', 'CODE','DATA','DATA','DATA','BSS','TLS', '','','','','','', '','','','', '', '', '', '', '', '','','','','','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ); secnamesml64 : array[TAsmSectiontype] of string[7] = ('','', '_TEXT','_DATA','_DATA','_DATA','_BSS','_TLS', '','','','', 'idata$2','idata$4','idata$5','idata$6','idata$7','edata', '', '', '', '', '', '','','','','','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' ); function TX86IntelAssembler.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 TX86IntelAssembler.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; function TX86IntelAssembler.extended2str(e : extended) : string; var hs : string; p : byte; begin str(e,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); extended2str:=lower(hs); end; function TX86IntelAssembler.comp2str(d : bestreal) : string; type pdouble = ^double; var c : comp; dd : pdouble; begin c:=comp(d); dd:=pdouble(@c); { this makes a bitwise copy of c into a double } comp2str:=double2str(dd^); end; { MASM supports aligns up to 8192 } function alignstr(b : longint) : string; begin case b of 1: result:='BYTE'; 2: result:='WORD'; 4: result:='DWORD'; 0, 16: result:='PARA'; 256: result:='PAGE'; else result:='ALIGN('+tostr(b)+')'; end; end; {**************************************************************************** tx86IntelAssembler ****************************************************************************} procedure tx86IntelAssembler.WriteReference(var ref : treference); var first : boolean; begin with ref do begin first:=true; if segment<>NR_NO then writer.AsmWrite(masm_regname(segment)+':[') else writer.AsmWrite('['); if assigned(symbol) then begin if (asminfo^.id = as_i386_tasm) then writer.AsmWrite('dword ptr '); writer.AsmWrite(ApplyAsmSymbolRestrictions(symbol.name)); first:=false; end; if (base<>NR_NO) then begin if not(first) then writer.AsmWrite('+') else first:=false; {$ifdef x86_64} { ml64 needs [$+foo] instead of [rip+foo] } if (base=NR_RIP) and (asminfo^.id=as_x86_64_masm) then writer.AsmWrite('$') else {$endif x86_64} writer.AsmWrite(masm_regname(base)); end; if (index<>NR_NO) then begin if not(first) then writer.AsmWrite('+') else first:=false; writer.AsmWrite(masm_regname(index)); if scalefactor<>0 then writer.AsmWrite('*'+tostr(scalefactor)); end; if offset<0 then begin writer.AsmWrite(tostr(offset)); first:=false; end else if (offset>0) then begin writer.AsmWrite('+'+tostr(offset)); first:=false; end; if first then writer.AsmWrite('0'); writer.AsmWrite(']'); end; end; procedure tx86IntelAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean); begin case o.typ of top_reg : writer.AsmWrite(masm_regname(o.reg)); top_const : writer.AsmWrite(tostr(o.val)); top_ref : begin if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got] then begin if ((opcode <> A_LGS) and (opcode <> A_LSS) and (opcode <> A_LFS) {$ifndef x86_64} and (opcode <> A_LDS) and (opcode <> A_LES) {$endif x86_64} ) then Begin case s of S_B : writer.AsmWrite('byte ptr '); S_W : writer.AsmWrite('word ptr '); S_L : writer.AsmWrite('dword ptr '); S_Q : writer.AsmWrite('qword ptr '); S_IS : writer.AsmWrite('word ptr '); S_IL : writer.AsmWrite('dword ptr '); S_IQ : writer.AsmWrite('qword ptr '); S_FS : writer.AsmWrite('dword ptr '); S_FL : writer.AsmWrite('qword ptr '); S_T, S_FX : writer.AsmWrite('tbyte ptr '); S_BW : if dest then writer.AsmWrite('word ptr ') else writer.AsmWrite('byte ptr '); S_BL : if dest then writer.AsmWrite('dword ptr ') else writer.AsmWrite('byte ptr '); S_WL : if dest then writer.AsmWrite('dword ptr ') else writer.AsmWrite('word ptr '); S_XMM: writer.AsmWrite('xmmword ptr '); S_YMM: writer.AsmWrite('ymmword ptr '); S_ZMM: writer.AsmWrite('zmmword ptr '); {$ifdef x86_64} S_BQ : if dest then writer.AsmWrite('qword ptr ') else writer.AsmWrite('byte ptr '); S_WQ : if dest then writer.AsmWrite('qword ptr ') else writer.AsmWrite('word ptr '); S_LQ : if dest then writer.AsmWrite('qword ptr ') else writer.AsmWrite('dword ptr '); {$endif x86_64} else ; end; end; WriteReference(o.ref^); end else begin writer.AsmWrite('offset '); if assigned(o.ref^.symbol) then writer.AsmWrite(ApplyAsmSymbolRestrictions(o.ref^.symbol.name)); if o.ref^.offset>0 then writer.AsmWrite('+'+tostr(o.ref^.offset)) else if o.ref^.offset<0 then writer.AsmWrite(tostr(o.ref^.offset)) else if not(assigned(o.ref^.symbol)) then writer.AsmWrite('0'); end; end; else internalerror(2005060510); end; end; procedure tx86IntelAssembler.WriteOper_jmp(const o:toper;s : topsize); begin case o.typ of top_reg : writer.AsmWrite(masm_regname(o.reg)); top_const : writer.AsmWrite(tostr(o.val)); top_ref : { what about lcall or ljmp ??? } begin if o.ref^.refaddr=addr_no then begin if (asminfo^.id <> as_i386_tasm) then begin if s=S_FAR then writer.AsmWrite('far ptr ') else {$ifdef x86_64} writer.AsmWrite('qword ptr '); {$else x86_64} writer.AsmWrite('dword ptr '); {$endif x86_64} end; WriteReference(o.ref^); end else begin writer.AsmWrite(ApplyAsmSymbolRestrictions(o.ref^.symbol.name)); if o.ref^.offset>0 then writer.AsmWrite('+'+tostr(o.ref^.offset)) else if o.ref^.offset<0 then writer.AsmWrite(tostr(o.ref^.offset)); end; end; else internalerror(2005060511); end; end; const ait_const2str : array[aitconst_128bit..aitconst_64bit_unaligned] of string[20]=( #9''#9,#9'DQ'#9,#9'DD'#9,#9'DW'#9,#9'DB'#9, #9'FIXMESLEB',#9'FIXEMEULEB', #9'DD RVA'#9,#9'DD SECREL32'#9, #9'FIXME',#9'FIXME',#9'FIXME',#9'FIXME', #9'DW'#9,#9'DD'#9,#9'DQ'#9 ); 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; procedure tx86IntelAssembler.WriteTree(p:TAsmList); var s, prefix, suffix : string; hp,nhp : tai; cpu: tcputype; counter, lines, tokens, InlineLevel : longint; i,j,l : longint; consttype : taiconst_type; do_line,DoNotSplitLine, quoted : boolean; fixed_opcode: TAsmOp; begin if not assigned(p) then exit; { 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]); InlineLevel:=0; 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_section : begin ResetSourceLines; if tai_section(hp).sectype<>sec_none then begin if asminfo^.id=as_x86_64_masm then begin if LasTSecType<>sec_none then writer.AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS'); writer.AsmLn; writer.AsmWriteLn(secnamesml64[tai_section(hp).sectype]+#9+'SEGMENT') end else begin if LasTSecType<>sec_none then writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS'); writer.AsmLn; if (asminfo^.id=as_i386_wasm) then s:='DWORD' else s:=alignstr(tai_section(hp).secalign); writer.AsmWriteLn('_'+secnames[tai_section(hp).sectype]+#9#9+ 'SEGMENT'#9+s+' PUBLIC USE32 '''+ secnames[tai_section(hp).sectype]+''''); end; end; LasTSecType:=tai_section(hp).sectype; end; ait_align : begin { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION } { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN } { HERE UNDER TASM! } if tai_align_abstract(hp).aligntype>1 then writer.AsmWriteLn(#9'ALIGN '+tostr(tai_align_abstract(hp).aligntype)); end; ait_datablock : begin if tai_datablock(hp).is_global then writer.AsmWriteLn(#9'PUBLIC'#9+ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name)); writer.AsmWriteLn(PadTabs(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name),#0)+'DB'#9+tostr(tai_datablock(hp).size)+' DUP(?)'); end; ait_const: begin consttype:=tai_const(hp).consttype; case consttype of aitconst_uleb128bit, aitconst_sleb128bit, aitconst_128bit, aitconst_64bit, aitconst_32bit, aitconst_16bit, aitconst_8bit, aitconst_16bit_unaligned, aitconst_32bit_unaligned, aitconst_64bit_unaligned, aitconst_rva_symbol, aitconst_secrel32_symbol : begin writer.AsmWrite(ait_const2str[consttype]); l:=0; tokens:=1; repeat if assigned(tai_const(hp).sym) then begin if assigned(tai_const(hp).endsym) then s:=ApplyAsmSymbolRestrictions(tai_const(hp).endsym.name)+'-'+ApplyAsmSymbolRestrictions(tai_const(hp).sym.name) else s:=ApplyAsmSymbolRestrictions(tai_const(hp).sym.name); if tai_const(hp).value<>0 then s:=s+tostr_with_plus(tai_const(hp).value); end else s:=tostr(tai_const(hp).value); writer.AsmWrite(s); inc(l,length(s)); inc(tokens); if (l>line_length) or (tokens>max_tokens) 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; { Substract section start for secrel32 type } if consttype=aitconst_secrel32_symbol then writer.AsmWrite(' - $$'); writer.AsmLn; end; else internalerror(200704253); end; end; ait_realconst: begin case tai_realconst(hp).realtyp of aitrealconst_s32bit: begin if (asminfo^.id = as_i386_wasm) and (IsInfinite(tai_realconst(hp).value.s32val)) then begin { Watcom Wasm does not handle Infinity } if Sign(tai_realconst(hp).value.s32val)=PositiveValue then writer.AsmWriteln(#9#9'DB'#9'0,0,80h,7Fh') else writer.AsmWriteln(#9#9'DW'#9'0,0,80h,FFh'); end else if (asminfo^.id = as_i386_wasm) and (IsNan(tai_realconst(hp).value.s32val)) then writer.AsmWriteln(#9#9'DB'#9'1,0,80h,7Fh') else writer.AsmWriteLn(#9#9'DD'#9+single2str(tai_realconst(hp).value.s32val)); end; aitrealconst_s64bit: begin if (asminfo^.id = as_i386_wasm) and (IsInfinite(tai_realconst(hp).value.s64val)) then begin { Watcom Wasm does not handle Infinity } if Sign(tai_realconst(hp).value.s64val)=PositiveValue then writer.AsmWriteln(#9#9'DW'#9'0,0,0,7FF0h') else writer.AsmWriteln(#9#9'DW'#9'0,0,0,FFF0h'); end else if (asminfo^.id = as_i386_wasm) and (IsNan(tai_realconst(hp).value.s64val)) then writer.AsmWriteln(#9#9'DW'#9'0,0,0,0,7FF8h') else writer.AsmWriteLn(#9#9'DQ'#9+double2str(tai_realconst(hp).value.s64val)); end; aitrealconst_s80bit: if (asminfo^.id = as_i386_wasm) and (IsInfinite(tai_realconst(hp).value.s80val)) then begin { Watcom Wasm does not handle Infinity } if Sign(tai_realconst(hp).value.s80val)=PositiveValue then writer.AsmWriteln(#9#9'DW'#9'0,0,0,8000h,7FFFh') else writer.AsmWriteln(#9#9'DW'#9'0,0,0,8000h,FFFFh'); end else if (asminfo^.id = as_i386_wasm) and (IsNan(tai_realconst(hp).value.s80val)) then writer.AsmWriteln(#9#9'DW'#9'0,0,0,0xC000,0x7FFF') else writer.AsmWriteLn(#9#9'DT'#9+extended2str(tai_realconst(hp).value.s80val)); aitrealconst_s64comp: writer.AsmWriteLn(#9#9'DQ'#9+extended2str(tai_realconst(hp).value.s64compval)); else internalerror(2014050606); end; end; ait_string : begin 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#9'DB'#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]<>'"') 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.AsmWrite(target_info.newline); counter := counter+line_length; end; { end for j:=0 ... } { do last line of lines } if counter<tai_string(hp).len then writer.AsmWrite(#9#9'DB'#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]<>'"') 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 writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name)); if not assigned(hp.next) or not(tai(hp.next).typ in [ait_const,ait_realconst,ait_string]) then writer.AsmWriteLn(':') else DoNotSplitLine:=true; end; end; ait_symbol : begin if tai_symbol(hp).has_value then internalerror(2009090802); { wasm is case insensitive, we need to use only uppercase version if both a lowercase and an uppercase version are provided } if (asminfo^.id = as_i386_wasm) then begin nhp:=tai(hp.next); while assigned(nhp) and (nhp.typ in [ait_function_name,ait_force_line]) do nhp:=tai(nhp.next); if assigned(nhp) and (tai(nhp).typ=ait_symbol) and (lower(tai_symbol(nhp).sym.name)=tai_symbol(hp).sym.name) then begin writer.AsmWriteln(asminfo^.comment+' '+tai_symbol(hp).sym.name+' removed'); hp:=tai(nhp); end; end; if tai_symbol(hp).is_global then writer.AsmWriteLn(#9'PUBLIC'#9+ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name)); writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name)); if not assigned(hp.next) or not(tai(hp.next).typ in [ait_const,ait_realconst,ait_string]) then writer.AsmWriteLn(':'); end; ait_symbol_end : begin end; ait_instruction : begin fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes; taicpu(hp).SetOperandOrder(op_intel); { Reset } suffix:=''; prefix:= ''; { We need to explicitely set word prefix to get selectors to be pushed in 2 bytes PM } if (taicpu(hp).opsize=S_W) and ( ( (fixed_opcode=A_PUSH) or (fixed_opcode=A_POP) ) and (taicpu(hp).oper[0]^.typ=top_reg) and is_segment_reg(taicpu(hp).oper[0]^.reg) ) then writer.AsmWriteln(#9#9'DB'#9'066h'); { added prefix instructions, must be on same line as opcode } if (taicpu(hp).ops = 0) and ((fixed_opcode = A_REP) or (fixed_opcode = A_LOCK) or (fixed_opcode = A_REPE) or (fixed_opcode = A_REPNZ) or (fixed_opcode = A_REPZ) or (fixed_opcode = A_REPNE)) then Begin prefix:=std_op2str[fixed_opcode]+#9; { there can be a stab inbetween when the opcode was on a different line in the source code } repeat hp:=tai(hp.next); until (hp=nil) or (hp.typ=ait_instruction); { next instruction ... } fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes; taicpu(hp).SetOperandOrder(op_intel); { this is theorically impossible... } if hp=nil then begin writer.AsmWriteLn(#9#9+prefix); break; end; { nasm prefers prefix on a line alone writer.AsmWriteln(#9#9+prefix); but not masm PM prefix:=''; } if asminfo^.id in [as_i386_nasmcoff,as_i386_nasmwin32,as_i386_nasmwdosx, as_i386_nasmelf,as_i386_nasmobj,as_i386_nasmbeos,as_i386_nasmhaiku] then begin writer.AsmWriteln(prefix); prefix:=''; end; end else prefix:= ''; if (asminfo^.id = as_i386_wasm) and (taicpu(hp).opsize=S_W) and (fixed_opcode=A_PUSH) and (taicpu(hp).oper[0]^.typ=top_const) then begin writer.AsmWriteln(#9#9'DB 66h,68h ; pushw imm16'); writer.AsmWrite(#9#9'DW'); end else if (asminfo^.id=as_x86_64_masm) and (fixed_opcode=A_MOVQ) then writer.AsmWrite(#9#9'mov') {$ifdef I386} else if (asminfo^.id = as_i386_wasm) and ((fixed_opcode=A_RETD) or (fixed_opcode=A_RETND) or (fixed_opcode=A_RETFD)) then begin { no 'd' suffix for Watcom assembler } case fixed_opcode of A_RETD: writer.AsmWrite(#9#9'ret'); A_RETND: writer.AsmWrite(#9#9'retn'); A_RETFD: writer.AsmWrite(#9#9'retf'); else internalerror(2019050907); end end {$endif I386} else writer.AsmWrite(#9#9+prefix+std_op2str[fixed_opcode]+cond2str[taicpu(hp).condition]+suffix); if taicpu(hp).ops<>0 then begin if is_calljmp(fixed_opcode) then begin writer.AsmWrite(#9); WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp).opsize); end else begin for i:=0to taicpu(hp).ops-1 do begin if i=0 then writer.AsmWrite(#9) else writer.AsmWrite(','); WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,fixed_opcode,(i=2)); end; end; end; writer.AsmLn; end; ait_stab, ait_force_line, ait_function_name : ; ait_cutobject : begin { only reset buffer if nothing has changed } if not writer.ClearIfEmpty then begin if LasTSecType<>sec_none then writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS'); writer.AsmLn; writer.AsmWriteLn(#9'END'); writer.AsmClose; DoAssemble; writer.AsmCreate(tai_cutobject(hp).place); end; { avoid empty files } while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do begin if tai(hp.next).typ=ait_section then lasTSecType:=tai_section(hp.next).sectype; hp:=tai(hp.next); end; if (asminfo^.id = as_i386_wasm) then begin writer.AsmWriteLn(#9'.686p'); writer.AsmWriteLn(#9'.xmm'); end else writer.AsmWriteLn(#9'.386p'); {$ifdef i8086} writer.AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA'); writer.AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP'); {$endif i8086} { I was told that this isn't necesarry because } { the labels generated by FPC are unique (FK) } { writer.AsmWriteLn(#9'LOCALS '+asminfo^.labelprefix); } { TODO: PARA is incorrect, must use actual section align } if lasTSectype<>sec_none then writer.AsmWriteLn('_'+secnames[lasTSectype]+#9#9+ 'SEGMENT'#9'PARA PUBLIC USE32 '''+ secnames[lasTSectype]+''''); writer.MarkEmpty; 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 : begin case tai_directive(hp).directive of asd_nasm_import : begin writer.AsmWrite('import '); writer.AsmWrite(tai_directive(hp).name); writer.AsmLn; end; asd_extern : begin writer.AsmWrite('EXTRN '); writer.AsmWrite(tai_directive(hp).name); writer.AsmLn; end; asd_cpu : begin if (asminfo^.id = as_i386_wasm) then begin {writer.AsmWrite('.');} for cpu:=low(tcputype) to high(tcputype) do begin if tai_directive(hp).name=CPUTypeStr[CPU] then begin { writer.AsmWriteLn(wasm_cpu_name[cpu]); } break; end; end; end else begin { TODO: implement this properly for TASM/MASM/WASM (.686p, etc.) } writer.AsmWrite(asminfo^.comment+' CPU '); writer.AsmWrite(tai_directive(hp).name); writer.AsmLn; end; end else internalerror(200509192); end; end; ait_seh_directive : { Ignore for now }; else if not WriteComments(hp) then internalerror(2020100802); end; hp:=tai(hp.next); end; end; procedure tx86intelassembler.WriteExternals; var sym : TAsmSymbol; i : longint; begin for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do begin sym:=TAsmSymbol(current_asmdata.AsmSymbolDict[i]); if sym.bind in [AB_EXTERNAL,AB_EXTERNAL_INDIRECT] then begin case asminfo^.id of as_i386_masm, as_i386_wasm : writer.AsmWriteln(#9'EXTRN'#9+ApplyAsmSymbolRestrictions(sym.name)+': NEAR'); as_x86_64_masm : writer.AsmWriteln(#9'EXTRN'#9+ApplyAsmSymbolRestrictions(sym.name)+': PROC'); else writer.AsmWriteln(#9'EXTRN'#9+ApplyAsmSymbolRestrictions(sym.name)); end; end; end; end; function tx86intelassembler.DoAssemble : boolean; var masmobjfn : string; begin DoAssemble:=Inherited DoAssemble; { masm does not seem to recognize specific extensions and uses .obj allways PM } if (asminfo^.id in [as_i386_masm,as_i386_wasm]) then begin masmobjfn:=ChangeFileExt(objfilename,'.obj'); if not(cs_asm_extern in current_settings.globalswitches) then begin if Not FileExists(objfilename) and FileExists(masmobjfn) then RenameFile(masmobjfn,objfilename); end else AsmRes.AddAsmCommand('mv',masmobjfn+' '+objfilename,objfilename); end; end; procedure tx86IntelAssembler.WriteAsmList; var hal : tasmlisttype; begin {$ifdef EXTDEBUG} if current_module.mainsource<>'' then comment(v_info,'Start writing intel-styled assembler output for '+current_module.mainsource); {$endif} if asminfo^.id<>as_x86_64_masm then begin if (asminfo^.id = as_i386_wasm) then begin writer.AsmWriteLn(#9'.686p'); writer.AsmWriteLn(#9'.xmm'); end else writer.AsmWriteLn(#9'.386p'); { masm 6.11 does not seem to like LOCALS PM } if (asminfo^.id = as_i386_tasm) then begin writer.AsmWriteLn(#9'LOCALS '+asminfo^.labelprefix); end; {$ifdef i8086} writer.AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA'); writer.AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP'); {$endif i8086} writer.AsmLn; end; 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; { better do this at end of WriteTree, but then there comes a trouble with al_const which does not have leading ait_section and thus goes out of segment } if LastSecType <> sec_none then begin if asminfo^.id=as_x86_64_masm then writer.AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS') else writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS'); end; LastSecType := sec_none; writer.AsmWriteLn(#9'END'); writer.AsmLn; {$ifdef EXTDEBUG} if current_module.mainsource<>'' then comment(v_info,'Done writing intel-styled assembler output for '+current_module.mainsource); {$endif EXTDEBUG} end; {***************************************************************************** Initialize *****************************************************************************} const {$ifdef i386} as_i386_tasm_info : tasminfo = ( id : as_i386_tasm; idtxt : 'TASM'; asmbin : 'tasm'; asmcmd : '/m2 /ml $EXTRAOPT $ASM $OBJ'; supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince]; flags : [af_needar,af_labelprefix_only_inside_procedure]; labelprefix : '@@'; labelmaxlen : -1; comment : '; '; dollarsign: '$'; ); as_i386_masm_info : tasminfo = ( id : as_i386_masm; idtxt : 'MASM'; asmbin : 'masm'; asmcmd : '/c /Cp $EXTRAOPT $ASM /Fo$OBJ'; supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince]; flags : [af_needar]; labelprefix : '@@'; labelmaxlen : -1; comment : '; '; dollarsign: '$'; ); as_i386_wasm_info : tasminfo = ( id : as_i386_wasm; idtxt : 'WASM'; asmbin : 'wasm'; asmcmd : '$ASM $EXTRAOPT -6s -fp6 -ms -zq -Fo=$OBJ'; supported_targets : [system_i386_watcom]; flags : [af_needar]; labelprefix : '@@'; labelmaxlen : 247; comment : '; '; dollarsign: '$'; ); {$endif i386} {$ifdef x86_64} as_x86_64_masm_info : tasminfo = ( id : as_x86_64_masm; idtxt : 'MASM'; asmbin : 'ml64'; asmcmd : '/c /Cp $EXTRAOPT $ASM /Fo$OBJ'; supported_targets : [system_x86_64_win64]; flags : [af_needar]; labelprefix : '@@'; labelmaxlen : -1; comment : '; '; dollarsign: '$'; ); {$endif x86_64} initialization {$ifdef x86_64} RegisterAssembler(as_x86_64_masm_info,tx86IntelAssembler); {$endif x86_64} {$ifdef i386} RegisterAssembler(as_i386_tasm_info,tx86IntelAssembler); RegisterAssembler(as_i386_masm_info,tx86IntelAssembler); RegisterAssembler(as_i386_wasm_info,tx86IntelAssembler); {$endif i386} end.