fpc/compiler/x86/agx86nsm.pas
nickysn 6a7fff644a * align non-code sections with zeros, instead of nops in the nasm asm output
writer, so they match the behaviour of the internal object writer (so it
  becomes easier to compare to the binary output of the omf object writer)

git-svn-id: trunk@30472 -
2015-04-06 20:30:06 +00:00

1440 lines
48 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Florian Klaempfl
This unit implements an asmoutput class for the Nasm assembler with
Intel syntax for the 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.
****************************************************************************
}
unit agx86nsm;
{$i fpcdefs.inc}
interface
uses
cpubase,globtype,
aasmbase,aasmtai,aasmdata,aasmcpu,assemble,cgutils;
type
{ T386NasmAssembler }
TX86NasmAssembler = class(texternalassembler)
private
using_relative : boolean;
function CodeSectionName(const aname:string): string;
procedure WriteReference(var ref : treference);
procedure WriteOper(const o:toper;s : topsize; opcode: tasmop;ops:longint;dest : boolean);
procedure WriteOper_jmp(const o:toper; ai : taicpu);
procedure WriteSection(atype:TAsmSectiontype;const aname:string;alignment : byte);
protected
function single2str(d: single): string; override;
function double2str(d: double): string; override;
function extended2str(e: extended): string; override;
public
procedure WriteTree(p:TAsmList);override;
procedure WriteAsmList;override;
procedure WriteExternals;
procedure WriteSmartExternals;
procedure WriteHeader;
function MakeCmdLine: TCmdStr;override;
end;
implementation
uses
cutils,globals,systems,cclasses,
fmodule,finput,verbose,cpuinfo,cgbase
;
const
line_length = 64;
nasm_regname_table : array[tregisterindex] of string[7] = (
{r386nasm.inc contains the Nasm name of each register.}
{$if defined(x86_64)}
{$i r8664nasm.inc}
{$elseif defined(i386)}
{$i r386nasm.inc}
{$elseif defined(i8086)}
{$i r8086nasm.inc}
{$endif}
);
function nasm_regname(r:Tregister):string;
var
p : tregisterindex;
begin
p:=findreg_by_number(r);
if p<>0 then
result:=nasm_regname_table[p]
else
result:=generic_regname(r);
end;
function TX86NasmAssembler.single2str(d: single): string;
var
hs : string;
p : longint;
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 TX86NasmAssembler.double2str(d: double): string;
var
hs : string;
p : longint;
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 TX86NasmAssembler.extended2str(e: extended): string;
var
hs : string;
p : longint;
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 sizestr(s:topsize;dest:boolean):string;
begin
case s of
S_B : sizestr:='byte ';
S_W : sizestr:='word ';
S_L : sizestr:='dword ';
S_Q : sizestr:='qword ';
S_IS : sizestr:='word ';
S_IL : sizestr:='dword ';
S_IQ : sizestr:='qword ';
S_FS : sizestr:='dword ';
S_FL : sizestr:='qword ';
S_FX : sizestr:='tword ';
S_BW : if dest then
sizestr:='word '
else
sizestr:='byte ';
S_BL : if dest then
sizestr:='dword '
else
sizestr:='byte ';
S_WL : if dest then
sizestr:='dword '
else
sizestr:='word ';
{$ifdef x86_64}
S_BQ : if dest then
sizestr:='qword '
else
sizestr:='byte ';
S_WQ : if dest then
sizestr:='qword '
else
sizestr:='word ';
S_LQ : if dest then
sizestr:='qword '
else
sizestr:='dword ';
{ Nothing needed for XMM registers }
S_XMM: sizestr:='';
{$endif x86_64}
else { S_NO }
sizestr:='';
end;
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;
type
PExternChain = ^TExternChain;
TExternChain = Record
psym : pshortstring;
is_defined : boolean;
next : PExternChain;
end;
const
FEC : PExternChain = nil;
procedure AddSymbol(symname : string; defined : boolean);
var
EC : PExternChain;
begin
EC:=FEC;
while assigned(EC) do
begin
if EC^.psym^=symname then
begin
if defined then
EC^.is_defined:=true;
exit;
end;
EC:=EC^.next;
end;
New(EC);
EC^.next:=FEC;
FEC:=EC;
FEC^.psym:=stringdup(symname);
FEC^.is_defined := defined;
end;
procedure FreeExternChainList;
var
EC : PExternChain;
begin
EC:=FEC;
while assigned(EC) do
begin
FEC:=EC^.next;
stringdispose(EC^.psym);
Dispose(EC);
EC:=FEC;
end;
end;
{****************************************************************************
TX86NasmAssembler
****************************************************************************}
function TX86NasmAssembler.CodeSectionName(const aname:string): string;
begin
{$ifdef i8086}
if current_settings.x86memorymodel in x86_far_code_models then
begin
if cs_huge_code in current_settings.moduleswitches then
result:=aname + '_TEXT use16 class=code'
else
result:=current_module.modulename^ + '_TEXT';
end
else
{$endif}
result:='.text';
end;
procedure TX86NasmAssembler.WriteReference(var ref : treference);
var
first : boolean;
base_done : boolean;
begin
with ref do
begin
AsmWrite('[');
first:=true;
base_done:=false;
if (segment<>NR_NO) then
AsmWrite(nasm_regname(segment)+':');
{$ifdef x86_64}
if (base=NR_RIP) then
begin
{ nasm RIP is implicit for pic }
if not (ref.refaddr in [addr_pic,addr_pic_no_got]) and not using_relative then
AsmWrite('$ + ');
base_done:=true;
end;
{$endif x86_64}
if assigned(symbol) then
begin
AsmWrite(symbol.name);
if SmartAsm then
AddSymbol(symbol.name,false);
first:=false;
end;
if (base<>NR_NO) and not base_done then
begin
if not(first) then
AsmWrite('+')
else
first:=false;
AsmWrite(nasm_regname(base))
end;
if (index<>NR_NO) then
begin
if not(first) then
AsmWrite('+')
else
first:=false;
AsmWrite(nasm_regname(index));
if scalefactor<>0 then
AsmWrite('*'+tostr(scalefactor));
end;
if offset<0 then
begin
AsmWrite(tostr(offset));
first:=false;
end
else if (offset>0) then
begin
AsmWrite('+'+tostr(offset));
first:=false;
end;
if first then
AsmWrite('0');
AsmWrite(']');
end;
end;
procedure TX86NasmAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;ops:longint;dest : boolean);
begin
case o.typ of
top_reg :
AsmWrite(nasm_regname(o.reg));
top_const :
begin
if (ops=1) and (opcode<>A_RET) then
AsmWrite(sizestr(s,dest));
AsmWrite(tostr(longint(o.val)));
end;
top_ref :
begin
if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got] then
begin
if not ((opcode = A_LEA) or (opcode = A_LGS) or
(opcode = A_LSS) or (opcode = A_LFS) or
{$ifndef x86_64}
(opcode = A_LES) or (opcode = A_LDS) or
{$endif x86_64}
// (opcode = A_SHR) or (opcode = A_SHL) or
// (opcode = A_SAR) or (opcode = A_SAL) or
(opcode = A_OUT) or (opcode = A_IN)) then
AsmWrite(sizestr(s,dest));
WriteReference(o.ref^);
end
{$ifdef i8086}
else if o.ref^.refaddr=addr_dgroup then
begin
AsmWrite('dgroup');
end
{$endif i8086}
else
begin
{$ifdef x86_64}
if s=S_L then
asmwrite('dword ')
else
asmwrite('qword ');
{$endif}
{$ifdef i386}
asmwrite('dword ');
{$endif i386}
{$ifdef i8086}
if o.ref^.refaddr=addr_seg then
asmwrite('SEG ')
else
asmwrite('word ');
{$endif i8086}
if assigned(o.ref^.symbol) then
begin
if SmartAsm then
AddSymbol(o.ref^.symbol.name,false);
asmwrite(o.ref^.symbol.name);
if o.ref^.offset=0 then
exit;
end;
if o.ref^.offset>0 then
asmwrite('+');
asmwrite(tostr(o.ref^.offset));
end;
end;
else
internalerror(10001);
end;
end;
procedure TX86NasmAssembler.WriteOper_jmp(const o:toper; ai : taicpu);
begin
case o.typ of
top_reg :
AsmWrite(nasm_regname(o.reg));
top_ref :
if o.ref^.refaddr=addr_no then
begin
if ai.opsize=S_FAR then
AsmWrite('far ');
WriteReference(o.ref^);
end
else
begin
if ai.opsize=S_FAR then
AsmWrite('far ');
{ else
AsmWrite('near ') just disables short branches, increasing code size.
Omitting it does not cause any bad effects, tested with nasm 2.11. }
AsmWrite(o.ref^.symbol.name);
if SmartAsm then
AddSymbol(o.ref^.symbol.name,false);
if o.ref^.offset>0 then
AsmWrite('+'+tostr(o.ref^.offset))
else
if o.ref^.offset<0 then
AsmWrite(tostr(o.ref^.offset));
end;
top_const :
AsmWrite(tostr(aint(o.val)));
else
internalerror(10001);
end;
end;
const
ait_const2str : array[aitconst_128bit..aitconst_64bit_unaligned] of string[30]=(
#9'FIXME_128BIT'#9,#9'DQ'#9,#9'DD'#9,#9'DW'#9,#9'DB'#9,
#9'FIXME_SLEB128BIT'#9,#9'FIXME_ULEB128BIT'#9,
#9'RVA'#9,#9'SECREL32'#9,#9'FIXME_darwin_dwarf_delta64'#9,
#9'FIXME_darwin_dwarf_delta32'#9,#9'FIXME_half16bit'#9,#9'FIXME_gs'#9,
#9'DW'#9,#9'DD'#9,#9'FIXME_64BIT_UNALIGNED'#9
);
procedure TX86NasmAssembler.WriteSection(atype : TAsmSectiontype;
const aname : string; alignment : byte);
const
secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
'.text',
'.data',
'.data',
'.rodata',
'.bss',
'.tbss',
'.pdata',
'.text','.data','.data','.data','.data',
'.stab',
'.stabstr',
'.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
'.eh_frame',
'.debug_frame','.debug_info','.debug_line','.debug_abbrev',
'.fpc',
'',
'.init',
'.fini',
'.objc_class',
'.objc_meta_class',
'.objc_cat_cls_meth',
'.objc_cat_inst_meth',
'.objc_protocol',
'.objc_string_object',
'.objc_cls_meth',
'.objc_inst_meth',
'.objc_cls_refs',
'.objc_message_refs',
'.objc_symbols',
'.objc_category',
'.objc_class_vars',
'.objc_instance_vars',
'.objc_module_info',
'.objc_class_names',
'.objc_meth_var_types',
'.objc_meth_var_names',
'.objc_selector_strs',
'.objc_protocol_ext',
'.objc_class_ext',
'.objc_property',
'.objc_image_info',
'.objc_cstring_object',
'.objc_sel_fixup',
'__DATA,__objc_data',
'__DATA,__objc_const',
'.objc_superrefs',
'__DATA, __datacoal_nt,coalesced',
'.objc_classlist',
'.objc_nlclasslist',
'.objc_catlist',
'.obcj_nlcatlist',
'.objc_protolist',
'.stack',
'.heap'
);
begin
AsmLn;
AsmWrite('SECTION ');
{ go32v2 stub only loads .text and .data sections, and allocates space for .bss.
Thus, data which normally goes into .rodata and .rodata_norel sections must
end up in .data section }
if (atype in [sec_rodata,sec_rodata_norel]) and
(target_info.system=system_i386_go32v2) then
AsmWrite('.data')
else if (atype=sec_user) then
AsmWrite(aname)
else if (atype=sec_threadvar) and
(target_info.system in (systems_windows+systems_wince)) then
AsmWrite('.tls'#9'bss')
else if secnames[atype]='.text' then
AsmWrite(CodeSectionName(aname))
{$ifdef i8086}
else if (target_info.system=system_i8086_msdos) and
(atype=sec_stack) and
(current_settings.x86memorymodel in x86_far_data_models) then
AsmWrite('stack stack class=stack align=16')
else if (target_info.system=system_i8086_msdos) and
(atype=sec_heap) and
(current_settings.x86memorymodel in x86_far_data_models) then
AsmWrite('heap class=heap align=16')
{$endif i8086}
else
AsmWrite(secnames[atype]);
if create_smartlink_sections and
(atype<>sec_bss) and
(aname<>'') then
begin
AsmWrite('.');
AsmWrite(aname);
if atype in [sec_init, sec_fini, sec_stub, sec_code] then
AsmWrite(' code align='+tostr(alignment))
else if atype in [sec_rodata, sec_rodata_norel] then
AsmWrite(' rdata align='+tostr(alignment))
else
AsmWrite(' data align='+tostr(alignment))
end;
AsmLn;
LastSecType:=atype;
end;
procedure TX86NasmAssembler.WriteTree(p:TAsmList);
{$ifdef cpuextended}
type
t80bitarray = array[0..9] of byte;
{$endif cpuextended}
var
s : string;
hp : tai;
counter,
lines,
i,j,l : longint;
InlineLevel : longint;
consttype : taiconst_type;
do_line, SkipNewLine,
quoted : boolean;
co : comp;
sin : single;
d : double;
{$ifdef cpuextended}
e : extended;
{$endif cpuextended}
fixed_opcode: TAsmOp;
prefix, LastSecName : string;
LastAlign : Byte;
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]));
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) then
WriteSourceLine(hp as tailineinfo);
end;
case hp.typ of
ait_comment :
Begin
AsmWrite(target_asm.comment);
AsmWritePChar(tai_comment(hp).str);
AsmLn;
End;
ait_regalloc :
begin
if (cs_asm_regalloc in current_settings.globalswitches) then
AsmWriteLn(#9#9+target_asm.comment+'Register '+nasm_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
WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secalign);
LastSecType:=tai_section(hp).sectype;
end;
ait_align :
begin
if (tai_align(hp).aligntype>1) then
begin
if (LastSecType=sec_bss) or (
(LastSecType=sec_threadvar) and
(target_info.system in (systems_windows+systems_wince))
) then
AsmWriteLn(#9'ALIGNB '+tostr(tai_align(hp).aligntype))
else if tai_align_abstract(hp).use_op then
AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype)+',DB '+tostr(tai_align_abstract(hp).fillop))
else if LastSecType in [sec_code,sec_stub,sec_init,sec_fini] then
AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype))
else
AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype)+',DB 0');
end;
end;
ait_datablock :
begin
if tai_datablock(hp).is_global or SmartAsm then
begin
AsmWrite(#9'GLOBAL ');
AsmWriteLn(tai_datablock(hp).sym.name);
end;
AsmWrite(PadTabs(tai_datablock(hp).sym.name,':'));
if SmartAsm then
AddSymbol(tai_datablock(hp).sym.name,true);
AsmWriteLn('RESB'#9+tostr(tai_datablock(hp).size));
end;
ait_const:
begin
consttype:=tai_const(hp).consttype;
case consttype of
aitconst_64bit,
aitconst_64bit_unaligned:
begin
if assigned(tai_const(hp).sym) then
internalerror(200404292);
AsmWrite(ait_const2str[aitconst_32bit]);
AsmWrite(tostr(longint(lo(tai_const(hp).value))));
AsmWrite(',');
AsmWrite(tostr(longint(hi(tai_const(hp).value))));
AsmLn;
end;
aitconst_uleb128bit,
aitconst_sleb128bit,
aitconst_128bit:
begin
AsmWriteLn(target_asm.comment+'Unsupported const type '+
ait_const2str[consttype]);
end;
{$ifdef i8086}
aitconst_farptr:
begin
AsmWrite(ait_const2str[aitconst_16bit]);
if assigned(tai_const(hp).sym) then
begin
if SmartAsm then
AddSymbol(tai_const(hp).sym.name,false);
AsmWrite(tai_const(hp).sym.name);
if tai_const(hp).value<>0 then
AsmWrite(tostr_with_plus(tai_const(hp).value));
AsmLn;
AsmWrite(ait_const2str[aitconst_16bit]);
AsmWrite('SEG ');
AsmWrite(tai_const(hp).sym.name);
end
else
AsmWrite(tostr(lo(longint(tai_const(hp).value)))+','+
tostr(hi(longint(tai_const(hp).value))));
AsmLn;
end;
{$endif i8086}
aitconst_32bit,
aitconst_16bit,
aitconst_8bit,
aitconst_rva_symbol,
aitconst_secrel32_symbol,
aitconst_16bit_unaligned,
aitconst_32bit_unaligned:
begin
AsmWrite(ait_const2str[tai_const(hp).consttype]);
l:=0;
repeat
if assigned(tai_const(hp).sym) then
begin
if SmartAsm then
begin
AddSymbol(tai_const(hp).sym.name,false);
if assigned(tai_const(hp).endsym) then
AddSymbol(tai_const(hp).endsym.name,false);
end;
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);
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);
AsmWrite(',');
until false;
AsmLn;
end;
else
internalerror(200704252);
end;
end;
ait_realconst:
begin
WriteRealConstAsBytes(tai_realconst(hp),#9#9'DB'#9,do_line);
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
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
AsmWrite(',');
AsmWrite('"');
end;
AsmWrite(tai_string(hp).str[i]);
quoted:=true;
end { if > 31 and < 128 and ord('"') }
else
begin
if quoted then
AsmWrite('"');
if i>counter then
AsmWrite(',');
quoted:=false;
AsmWrite(tostr(ord(tai_string(hp).str[i])));
end;
end; { end for i:=0 to... }
if quoted then AsmWrite('"');
AsmWrite(target_info.newline);
inc(counter,line_length);
end; { end for j:=0 ... }
{ do last line of lines }
if counter<tai_string(hp).len then
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
AsmWrite(',');
AsmWrite('"');
end;
AsmWrite(tai_string(hp).str[i]);
quoted:=true;
end { if > 31 and < 128 and " }
else
begin
if quoted then
AsmWrite('"');
if i>counter then
AsmWrite(',');
quoted:=false;
AsmWrite(tostr(ord(tai_string(hp).str[i])));
end;
end; { end for i:=0 to... }
if quoted then
AsmWrite('"');
end;
AsmLn;
end;
ait_label :
begin
if tai_label(hp).labsym.is_used then
begin
if SmartAsm and (tai_label(hp).labsym.bind=AB_GLOBAL) then
begin
AsmWrite(#9'GLOBAL ');
AsmWriteLn(tai_label(hp).labsym.name);
end;
AsmWriteLn(tai_label(hp).labsym.name+':');
end;
if SmartAsm then
AddSymbol(tai_label(hp).labsym.name,true);
end;
ait_symbol :
begin
if tai_symbol(hp).has_value then
internalerror(2009090803);
if tai_symbol(hp).is_global or SmartAsm then
begin
AsmWrite(#9'GLOBAL ');
AsmWriteLn(tai_symbol(hp).sym.name);
end;
AsmWrite(tai_symbol(hp).sym.name);
if SmartAsm then
AddSymbol(tai_symbol(hp).sym.name,true);
if assigned(hp.next) and not(tai(hp.next).typ in
[ait_const,ait_realconst,ait_string]) then
AsmWriteLn(':')
end;
ait_symbol_end : ;
ait_instruction :
begin
fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes;
{ We need intel order, no At&t }
taicpu(hp).SetOperandOrder(op_intel);
{ LOCK must be on same line as opcode }
if (taicpu(hp).ops = 0) and
(fixed_opcode = A_LOCK) then
SkipNewLine:=true
else
SkipNewLine:=false;
s:='';
if ((fixed_opcode=A_FADDP) or
(fixed_opcode=A_FMULP))
and (taicpu(hp).ops=0) then
begin
taicpu(hp).allocate_oper(2);
taicpu(hp).oper[0]^.typ:=top_reg;
taicpu(hp).oper[0]^.reg:=NR_ST1;
taicpu(hp).oper[1]^.typ:=top_reg;
taicpu(hp).oper[1]^.reg:=NR_ST;
end;
{ NASM only accepts move for loading of
simple symbol address }
if ((taicpu(hp).opcode=A_LEA) and
(taicpu(hp).ops=2) and
(taicpu(hp).oper[0]^.typ=top_reg) and
(reg2opsize(taicpu(hp).oper[0]^.reg) in [S_NO,S_Q]) and
(taicpu(hp).oper[1]^.typ=top_ref) and
(taicpu(hp).oper[1]^.ref^.refaddr<>addr_no) and
assigned(taicpu(hp).oper[1]^.ref^.symbol) and
(taicpu(hp).oper[1]^.ref^.base=NR_NO)) then
begin
AsmWrite(target_asm.comment);
AsmWriteln('Converting LEA to MOV instruction');
taicpu(hp).opcode:=A_MOV;
end;
if fixed_opcode=A_FWAIT then
AsmWriteln(#9#9'DB'#9'09bh')
else
begin
prefix:='';
{$ifdef i8086}
{ nickysn note: I don't know if the 187 requires FWAIT before
every instruction like the 8087, so I'm including it just in case }
if (current_settings.cputype<=cpu_186) and
requires_fwait_on_8087(fixed_opcode) then
prefix:='wait '+prefix;
{$endif i8086}
{$ifndef i8086}
{ 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
AsmWriteln(#9#9'DB'#9'066h');
{$endif not i8086}
AsmWrite(#9#9+prefix+std_op2str[fixed_opcode]+cond2str[taicpu(hp).condition]);
if taicpu(hp).ops<>0 then
begin
if is_calljmp(fixed_opcode) then
begin
AsmWrite(#9);
WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp));
end
else
begin
for i:=0 to taicpu(hp).ops-1 do
begin
if i=0 then
AsmWrite(#9)
else
AsmWrite(',');
WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,fixed_opcode,taicpu(hp).ops,(i=2));
end;
end;
end;
if not SkipNewLine then
AsmLn;
end;
end;
ait_stab,
ait_force_line,
ait_function_name : ;
ait_cutobject :
begin
if SmartAsm then
begin
{ only reset buffer if nothing has changed }
if AsmSize=AsmStartSize then
AsmClear
else
begin
if SmartAsm then
begin
WriteSmartExternals;
FreeExternChainList;
end;
AsmClose;
DoAssemble;
AsmCreate(tai_cutobject(hp).place);
WriteHeader;
end;
{ avoid empty files }
LastSecType:=sec_none;
LastSecName:='';
LastAlign:=4;
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
begin
LastSecType:=tai_section(hp.next).sectype;
LastSecName:=tai_section(hp.next).name^;
LastAlign:=tai_section(hp.next).secalign;
end;
hp:=tai(hp.next);
end;
if LastSecType<>sec_none then
WriteSection(LastSecType,LastSecName,LastAlign);
AsmStartSize:=AsmSize;
end;
end;
ait_marker :
if tai_marker(hp).kind=mark_NoLineInfoStart then
inc(InlineLevel)
else if tai_marker(hp).kind=mark_NoLineInfoEnd then
dec(InlineLevel);
ait_directive :
begin
case tai_directive(hp).directive of
asd_nasm_import :
AsmWrite('import ');
asd_extern :
AsmWrite('EXTERN ');
else
internalerror(200509191);
end;
if tai_directive(hp).name<>'' then
begin
if SmartAsm then
AddSymbol(tai_directive(hp).name,false);
AsmWrite(tai_directive(hp).name);
end;
AsmLn;
end;
ait_seh_directive :
{ Ignore for now };
ait_varloc:
begin
if tai_varloc(hp).newlocationhi<>NR_NO then
AsmWriteLn(target_asm.comment+'Var '+tai_varloc(hp).varsym.realname+' located in register '+
std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation))
else
AsmWriteLn(target_asm.comment+'Var '+tai_varloc(hp).varsym.realname+' located in register '+
std_regname(tai_varloc(hp).newlocation));
end;
else
internalerror(10000);
end;
hp:=tai(hp.next);
end;
end;
procedure TX86NasmAssembler.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
AsmWriteln('EXTERN'#9+sym.name);
end;
end;
procedure TX86NasmAssembler.WriteSmartExternals;
var
EC : PExternChain;
begin
EC:=FEC;
while assigned(EC) do
begin
if not EC^.is_defined then
AsmWriteln('EXTERN'#9+EC^.psym^);
EC:=EC^.next;
end;
end;
procedure TX86NasmAssembler.WriteHeader;
begin
{$if defined(i8086)}
AsmWriteLn('BITS 16');
case current_settings.cputype of
cpu_8086: AsmWriteLn('CPU 8086');
cpu_186: AsmWriteLn('CPU 186');
cpu_286: AsmWriteLn('CPU 286');
cpu_386: AsmWriteLn('CPU 386');
cpu_Pentium: AsmWriteLn('CPU PENTIUM');
cpu_Pentium2: AsmWriteLn('CPU P2');
cpu_Pentium3: AsmWriteLn('CPU P3');
cpu_Pentium4: AsmWriteLn('CPU P4');
cpu_PentiumM: AsmWriteLn('CPU P4');
else
internalerror(2013050101);
end;
if not (cs_huge_code in current_settings.moduleswitches) then
AsmWriteLn('SECTION ' + CodeSectionName(current_module.modulename^) + ' use16 class=code');
{ NASM complains if you put a missing section in the GROUP directive, so }
{ we add empty declarations to make sure they exist, even if empty }
AsmWriteLn('SECTION .rodata class=data');
AsmWriteLn('SECTION .data class=data');
AsmWriteLn('SECTION .fpc class=data');
{ WLINK requires class=bss in order to leave the BSS section out of the executable }
AsmWriteLn('SECTION .bss class=bss');
if (current_settings.x86memorymodel<>mm_tiny) and
(current_settings.x86memorymodel in x86_near_data_models) then
AsmWriteLn('SECTION stack stack class=stack align=16');
if current_settings.x86memorymodel in x86_near_data_models then
AsmWriteLn('SECTION heap class=heap align=16');
{ group these sections in the same segment }
if current_settings.x86memorymodel=mm_tiny then
AsmWriteLn('GROUP dgroup text rodata data fpc bss heap')
else if current_settings.x86memorymodel in x86_near_data_models then
AsmWriteLn('GROUP dgroup rodata data fpc bss stack heap')
else
AsmWriteLn('GROUP dgroup rodata data fpc bss');
if paratargetdbg in [dbg_dwarf2,dbg_dwarf3,dbg_dwarf4] then
begin
AsmWriteLn('SECTION .debug_frame use32 class=DWARF');
AsmWriteLn('SECTION .debug_info use32 class=DWARF');
AsmWriteLn('SECTION .debug_line use32 class=DWARF');
AsmWriteLn('SECTION .debug_abbrev use32 class=DWARF');
end;
if not (cs_huge_code in current_settings.moduleswitches) then
AsmWriteLn('SECTION ' + CodeSectionName(current_module.modulename^));
{$elseif defined(i386)}
AsmWriteLn('BITS 32');
using_relative:=false;
{$elseif defined(x86_64)}
AsmWriteLn('BITS 64');
AsmWriteLn('default rel');
using_relative:=true;
{$endif}
end;
procedure TX86NasmAssembler.WriteAsmList;
var
hal : tasmlisttype;
begin
{$ifdef EXTDEBUG}
if current_module.mainsource<>'' then
comment(v_info,'Start writing nasm-styled assembler output for '+current_module.mainsource);
{$endif}
WriteHeader;
AsmLn;
WriteExternals;
for hal:=low(TasmlistType) to high(TasmlistType) do
begin
if not (current_asmdata.asmlists[hal].empty) then
begin
AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmListTypeStr[hal]);
writetree(current_asmdata.asmlists[hal]);
AsmWriteLn(target_asm.comment+'End asmlist '+AsmListTypeStr[hal]);
end;
end;
AsmLn;
if SmartAsm then
begin
WriteSmartExternals;
FreeExternChainList;
end;
{$ifdef EXTDEBUG}
if current_module.mainsource<>'' then
comment(v_info,'Done writing nasm-styled assembler output for '+current_module.mainsource);
{$endif EXTDEBUG}
end;
function TX86NasmAssembler.MakeCmdLine: TCmdStr;
var
FormatName : string;
begin
result:=Inherited MakeCmdLine;
{$ifdef i8086}
case target_info.system of
system_i8086_msdos:
FormatName:='obj';
else
internalerror(2014082060);
end;
{$endif i8086}
{$ifdef i386}
case target_info.system of
system_i386_go32v2:
FormatName:='coff';
system_i386_wdosx,
system_i386_win32:
FormatName:='win32';
system_i386_embedded:
FormatName:='obj';
system_i386_linux,
system_i386_beos:
FormatName:='elf';
system_i386_darwin:
FormatName:='macho32';
else
FormatName:='elf';
end;
{$endif i386}
{$ifdef x86_64}
case target_info.system of
system_x86_64_win64:
FormatName:='win64';
system_x86_64_darwin:
FormatName:='macho64';
system_x86_64_linux:
FormatName:='elf64';
else
FormatName:='elf64';
end;
{$endif x86_64}
Replace(result,'$FORMAT',FormatName);
end;
{*****************************************************************************
Initialize
*****************************************************************************}
{$ifdef i8086}
const
as_i8086_nasm_info : tasminfo =
(
id : as_i8086_nasm;
idtxt : 'NASM';
asmbin : 'nasm';
asmcmd : '-f $FORMAT -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i8086_msdos];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i8086_nasmobj_info : tasminfo =
(
id : as_i8086_nasmobj;
idtxt : 'NASMOBJ';
asmbin : 'nasm';
asmcmd : '-f obj -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i8086_msdos];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
{$endif i8086}
{$ifdef i386}
const
as_i386_nasmcoff_info : tasminfo =
(
id : as_i386_nasmcoff;
idtxt : 'NASMCOFF';
asmbin : 'nasm';
asmcmd : '-f coff -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_go32v2];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasmwin32_info : tasminfo =
(
id : as_i386_nasmwin32;
idtxt : 'NASMWIN32';
asmbin : 'nasm';
asmcmd : '-f win32 -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_win32];
flags : [af_needar,af_no_debug,af_smartlink_sections];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasmobj_info : tasminfo =
(
id : as_i386_nasmobj;
idtxt : 'NASMOBJ';
asmbin : 'nasm';
asmcmd : '-f obj -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_embedded, system_i8086_msdos];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasmwdosx_info : tasminfo =
(
id : as_i386_nasmwdosx;
idtxt : 'NASMWDOSX';
asmbin : 'nasm';
asmcmd : '-f win32 -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_wdosx];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasmelf_info : tasminfo =
(
id : as_i386_nasmelf;
idtxt : 'NASMELF';
asmbin : 'nasm';
asmcmd : '-f elf -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_linux];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasmdarwin_info : tasminfo =
(
id : as_i386_nasmdarwin;
idtxt : 'NASMDARWIN';
asmbin : 'nasm';
asmcmd : '-f macho32 -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_darwin];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasmbeos_info : tasminfo =
(
id : as_i386_nasmbeos;
idtxt : 'NASMELF';
asmbin : 'nasm';
asmcmd : '-f elf -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_beos];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasmhaiku_info : tasminfo =
(
id : as_i386_nasmhaiku;
idtxt : 'NASMELF';
asmbin : 'nasm';
asmcmd : '-f elf -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_i386_haiku];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_i386_nasm_info : tasminfo =
(
id : as_i386_nasm;
idtxt : 'NASM';
asmbin : 'nasm';
asmcmd : '-f $FORMAT -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_any];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
{$endif i386}
{$ifdef x86_64}
const
as_x86_64_nasm_info : tasminfo =
(
id : as_x86_64_nasm;
idtxt : 'NASM';
asmbin : 'nasm';
asmcmd : '-f $FORMAT -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_any];
flags : [af_needar{,af_no_debug}];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_x86_64_nasmwin64_info : tasminfo =
(
id : as_x86_64_nasmwin64;
idtxt : 'NASMWIN64';
asmbin : 'nasm';
asmcmd : '-f win64 -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_x86_64_win64];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_x86_64_nasmelf_info : tasminfo =
(
id : as_x86_64_nasmelf;
idtxt : 'NASMELF';
asmbin : 'nasm';
asmcmd : '-f elf64 -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_x86_64_linux];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
as_x86_64_nasmdarwin_info : tasminfo =
(
id : as_x86_64_nasmdarwin;
idtxt : 'NASMDARWIN';
asmbin : 'nasm';
asmcmd : '-f macho64 -o $OBJ -w-orphan-labels $EXTRAOPT $ASM';
supported_targets : [system_x86_64_darwin];
flags : [af_needar,af_no_debug];
labelprefix : '..@';
comment : '; ';
dollarsign: '$';
);
{$endif x86_64}
initialization
{$ifdef i8086}
RegisterAssembler(as_i8086_nasm_info,TX86NasmAssembler);
RegisterAssembler(as_i8086_nasmobj_info,TX86NasmAssembler);
{$endif i8086}
{$ifdef i386}
RegisterAssembler(as_i386_nasmcoff_info,TX86NasmAssembler);
RegisterAssembler(as_i386_nasmwin32_info,TX86NasmAssembler);
RegisterAssembler(as_i386_nasmwdosx_info,TX86NasmAssembler);
RegisterAssembler(as_i386_nasmobj_info,TX86NasmAssembler);
RegisterAssembler(as_i386_nasmbeos_info,TX86NasmAssembler);
RegisterAssembler(as_i386_nasmhaiku_info,TX86NasmAssembler);
RegisterAssembler(as_i386_nasmelf_info,TX86NasmAssembler);
RegisterAssembler(as_i386_nasm_info,TX86NasmAssembler);
{$endif i386}
{$ifdef x86_64}
RegisterAssembler(as_x86_64_nasm_info,TX86NasmAssembler);
RegisterAssembler(as_x86_64_nasmwin64_info,TX86NasmAssembler);
RegisterAssembler(as_x86_64_nasmelf_info,TX86NasmAssembler);
RegisterAssembler(as_x86_64_nasmdarwin_info,TX86NasmAssembler);
{$endif x86_64}
end.