fpc/compiler/x86/agx86int.pas
nickysn 178dab45d3 + added new asm directive 'asd_cpu' (specifies the CPU's instruction set) in the
compiler's internal assembly representation. It is not yet generated by the
  compiler and is only implemented properly in the NASM writer (but will
  eventually be implemented in the other assembler writers as well, including
  the internal assembler). In the future, it is intended to allow:
  1) catching instructions, generated by the compiler and not supported by the
     target CPU, due to a bug in the code generator
  2) allowing a different instruction set to be used in inline asm blocks (I'm
     planning a new directive for that - {$asmcpu XXX}), because the code
     generator will be able to switch target CPU in the middle of the asm output
     stream

git-svn-id: trunk@33121 -
2016-02-25 21:47:13 +00:00

1050 lines
35 KiB
ObjectPascal

{
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,
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
procedure WriteTree(p:TAsmList);override;
procedure WriteAsmList;override;
Function DoAssemble:boolean;override;
procedure WriteExternals;
end;
implementation
uses
SysUtils,
cutils,globtype,globals,systems,cclasses,
verbose,finput,fmodule,script,cpuinfo,
itx86int,
cgbase
;
const
line_length = 70;
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 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;
function 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 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 : integer) : 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(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 ');
{$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}
end;
end;
WriteReference(o.ref^);
end
else
begin
writer.AsmWrite('offset ');
if assigned(o.ref^.symbol) then
writer.AsmWrite(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(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_secrel32_symbol] 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
);
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 : tai;
counter,
lines,
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_comment :
Begin
writer.AsmWrite(asminfo^.comment);
writer.AsmWritePChar(tai_comment(hp).str);
writer.AsmLn;
End;
ait_regalloc :
begin
if (cs_asm_regalloc in current_settings.globalswitches) then
writer.AsmWriteLn(asminfo^.comment+'Register '+masm_regname(tai_regalloc(hp).reg)+
regallocstr[tai_regalloc(hp).ratype]);
end;
ait_tempalloc :
begin
if (cs_asm_tempalloc in current_settings.globalswitches) then
WriteTempalloc(tai_tempalloc(hp));
end;
ait_section :
begin
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;
writer.AsmWriteLn('_'+secnames[tai_section(hp).sectype]+#9#9+
'SEGMENT'#9+alignstr(tai_section(hp).secalign)+' 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+tai_datablock(hp).sym.name);
writer.AsmWriteLn(PadTabs(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_rva_symbol,
aitconst_secrel32_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
s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
else
s:=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));
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;
{ 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:
writer.AsmWriteLn(#9#9'DD'#9+single2str(tai_realconst(hp).value.s32val));
aitrealconst_s64bit:
writer.AsmWriteLn(#9#9'DQ'#9+double2str(tai_realconst(hp).value.s64val));
aitrealconst_s80bit:
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(2014050604);
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(tai_label(hp).labsym.name);
if assigned(hp.next) and 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);
if tai_symbol(hp).is_global then
writer.AsmWriteLn(#9'PUBLIC'#9+tai_symbol(hp).sym.name);
writer.AsmWrite(tai_symbol(hp).sym.name);
if assigned(hp.next) and 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')
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;
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 :
writer.AsmWrite('import ');
asd_extern :
writer.AsmWrite('EXTRN ');
asd_cpu :
{ TODO: implement this properly for TASM/MASM/WASM (.686p, etc.) }
writer.AsmWrite(asminfo^.comment+' CPU ');
else
internalerror(200509192);
end;
writer.AsmWrite(tai_directive(hp).name);
writer.AsmLn;
end;
ait_seh_directive :
{ Ignore for now };
else
internalerror(10000);
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=AB_EXTERNAL then
begin
case asminfo^.id of
as_i386_masm,
as_i386_wasm :
writer.AsmWriteln(#9'EXTRN'#9+sym.name+': NEAR');
as_x86_64_masm :
writer.AsmWriteln(#9'EXTRN'#9+sym.name+': PROC');
else
writer.AsmWriteln(#9'EXTRN'#9+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
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 : '@@';
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 : '@@';
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 : '@@';
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 : '@@';
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.