mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-27 12:53:42 +02:00

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 -
1806 lines
67 KiB
ObjectPascal
1806 lines
67 KiB
ObjectPascal
{
|
|
Copyright (c) 1998-2006 by the Free Pascal team
|
|
|
|
This unit implements the generic part of the GNU assembler
|
|
(v2.8 or later) writer
|
|
|
|
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.
|
|
|
|
****************************************************************************
|
|
}
|
|
{ Base unit for writing GNU assembler output.
|
|
}
|
|
unit aggas;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
{ $define DEBUG_AGGAS}
|
|
|
|
interface
|
|
|
|
uses
|
|
globtype,globals,
|
|
aasmbase,aasmtai,aasmdata,
|
|
assemble;
|
|
|
|
type
|
|
TCPUInstrWriter = class;
|
|
{# This is a derived class which is used to write
|
|
GAS styled assembler.
|
|
}
|
|
|
|
{ TGNUAssembler }
|
|
|
|
TGNUAssembler=class(texternalassembler)
|
|
protected
|
|
function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;virtual;
|
|
function sectionattrs_coff(atype:TAsmSectiontype):string;virtual;
|
|
function sectionalignment_aix(atype:TAsmSectiontype;secalign: byte):string;
|
|
procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder;secalign:byte);
|
|
procedure WriteExtraHeader;virtual;
|
|
procedure WriteExtraFooter;virtual;
|
|
procedure WriteInstruction(hp: tai);
|
|
procedure WriteWeakSymbolRef(s: tasmsymbol); virtual;
|
|
procedure WriteAixStringConst(hp: tai_string);
|
|
procedure WriteAixIntConst(hp: tai_const);
|
|
procedure WriteUnalignedIntConst(hp: tai_const);
|
|
procedure WriteDirectiveName(dir: TAsmDirective); virtual;
|
|
public
|
|
function MakeCmdLine: TCmdStr; override;
|
|
procedure WriteTree(p:TAsmList);override;
|
|
procedure WriteAsmList;override;
|
|
destructor destroy; override;
|
|
private
|
|
setcount: longint;
|
|
procedure WriteDecodedSleb128(a: int64);
|
|
procedure WriteDecodedUleb128(a: qword);
|
|
function NextSetLabel: string;
|
|
protected
|
|
InstrWriter: TCPUInstrWriter;
|
|
end;
|
|
|
|
|
|
{# This is the base class for writing instructions.
|
|
|
|
The WriteInstruction() method must be overridden
|
|
to write a single instruction to the assembler
|
|
file.
|
|
}
|
|
TCPUInstrWriter = class
|
|
constructor create(_owner: TGNUAssembler);
|
|
procedure WriteInstruction(hp : tai); virtual; abstract;
|
|
protected
|
|
owner: TGNUAssembler;
|
|
end;
|
|
|
|
|
|
{ TAppleGNUAssembler }
|
|
|
|
TAppleGNUAssembler=class(TGNUAssembler)
|
|
protected
|
|
function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
|
|
procedure WriteWeakSymbolRef(s: tasmsymbol); override;
|
|
procedure WriteDirectiveName(dir: TAsmDirective); override;
|
|
end;
|
|
|
|
|
|
TAoutGNUAssembler=class(TGNUAssembler)
|
|
function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils,
|
|
cutils,cfileutl,systems,
|
|
fmodule,verbose,
|
|
{$ifndef DISABLE_WIN64_SEH}
|
|
itcpugas,
|
|
{$endif DISABLE_WIN64_SEH}
|
|
{$ifdef m68k}
|
|
cpuinfo,aasmcpu,
|
|
{$endif m68k}
|
|
cpubase,objcasm;
|
|
|
|
const
|
|
line_length = 70;
|
|
|
|
var
|
|
symendcount : longint;
|
|
|
|
{****************************************************************************}
|
|
{ Support routines }
|
|
{****************************************************************************}
|
|
|
|
const
|
|
ait_const2str : array[aitconst_128bit..aitconst_64bit_unaligned] of string[20]=(
|
|
#9'.fixme128'#9,#9'.quad'#9,#9'.long'#9,#9'.short'#9,#9'.byte'#9,
|
|
#9'.sleb128'#9,#9'.uleb128'#9,
|
|
#9'.rva'#9,#9'.secrel32'#9,#9'.quad'#9,#9'.long'#9,#9'.short'#9,#9'.short'#9,
|
|
#9'.short'#9,#9'.long'#9,#9'.quad'#9
|
|
);
|
|
|
|
ait_solaris_const2str : array[aitconst_128bit..aitconst_64bit_unaligned] of string[20]=(
|
|
#9'.fixme128'#9,#9'.8byte'#9,#9'.4byte'#9,#9'.2byte'#9,#9'.byte'#9,
|
|
#9'.sleb128'#9,#9'.uleb128'#9,
|
|
#9'.rva'#9,#9'.secrel32'#9,#9'.8byte'#9,#9'.4byte'#9,#9'.2byte'#9,#9'.2byte'#9,
|
|
#9'.2byte'#9,#9'.4byte'#9,#9'.8byte'#9
|
|
);
|
|
|
|
ait_unaligned_consts = [aitconst_16bit_unaligned..aitconst_64bit_unaligned];
|
|
|
|
{ Sparc type of unaligned pseudo-instructions }
|
|
use_ua_sparc_systems = [system_sparc_linux];
|
|
ait_ua_sparc_const2str : array[aitconst_16bit_unaligned..aitconst_64bit_unaligned]
|
|
of string[20]=(
|
|
#9'.uahalf'#9,#9'.uaword'#9,#9'.uaxword'#9
|
|
);
|
|
|
|
{ Generic unaligned pseudo-instructions, seems ELF specific }
|
|
use_ua_elf_systems = [system_mipsel_linux,system_mipseb_linux,system_mipsel_android,system_mipsel_embedded,system_mipseb_embedded];
|
|
ait_ua_elf_const2str : array[aitconst_16bit_unaligned..aitconst_64bit_unaligned]
|
|
of string[20]=(
|
|
#9'.2byte'#9,#9'.4byte'#9,#9'.8byte'#9
|
|
);
|
|
|
|
|
|
|
|
{****************************************************************************}
|
|
{ GNU Assembler writer }
|
|
{****************************************************************************}
|
|
|
|
destructor TGNUAssembler.Destroy;
|
|
begin
|
|
InstrWriter.free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
|
|
function TGNUAssembler.MakeCmdLine: TCmdStr;
|
|
begin
|
|
result := inherited MakeCmdLine;
|
|
// MWE: disabled again. It generates dwarf info for the generated .s
|
|
// files as well. This conflicts with the info we generate
|
|
// if target_dbg.id = dbg_dwarf then
|
|
// result := result + ' --gdwarf-2';
|
|
end;
|
|
|
|
|
|
function TGNUAssembler.NextSetLabel: string;
|
|
begin
|
|
inc(setcount);
|
|
result := asminfo^.labelprefix+'$set$'+tostr(setcount);
|
|
end;
|
|
|
|
function is_smart_section(atype:TAsmSectiontype):boolean;
|
|
begin
|
|
{ For bss we need to set some flags that are target dependent,
|
|
it is easier to disable it for smartlinking. It doesn't take up
|
|
filespace }
|
|
result:=not(target_info.system in systems_darwin) and
|
|
create_smartlink_sections and
|
|
(atype<>sec_toc) and
|
|
(atype<>sec_user) and
|
|
{ on embedded systems every byte counts, so smartlink bss too }
|
|
((atype<>sec_bss) or (target_info.system in systems_embedded));
|
|
end;
|
|
|
|
function TGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
|
|
const
|
|
secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
|
|
'.text',
|
|
'.data',
|
|
{ why doesn't .rodata work? (FK) }
|
|
{ sometimes we have to create a data.rel.ro instead of .rodata, e.g. for }
|
|
{ vtables (and anything else containing relocations), otherwise those are }
|
|
{ not relocated properly on e.g. linux/ppc64. g++ generates there for a }
|
|
{ vtable for a class called Window: }
|
|
{ .section .data.rel.ro._ZTV6Window,"awG",@progbits,_ZTV6Window,comdat }
|
|
{ TODO: .data.ro not yet working}
|
|
{$if defined(arm) or defined(powerpc)}
|
|
'.rodata',
|
|
{$else arm}
|
|
'.data',
|
|
{$endif arm}
|
|
{$if defined(m68k)} { Amiga/m68k GNU AS doesn't seem to like .rodata (KB) }
|
|
'.data',
|
|
{$else}
|
|
'.rodata',
|
|
{$endif}
|
|
'.bss',
|
|
'.threadvar',
|
|
'.pdata',
|
|
'', { stubs }
|
|
'__DATA,__nl_symbol_ptr',
|
|
'__DATA,__la_symbol_ptr',
|
|
'__DATA,__mod_init_func',
|
|
'__DATA,__mod_term_func',
|
|
'.stab',
|
|
'.stabstr',
|
|
'.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
|
|
'.eh_frame',
|
|
'.debug_frame','.debug_info','.debug_line','.debug_abbrev',
|
|
'.fpc',
|
|
'.toc',
|
|
'.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'
|
|
);
|
|
secnames_pic : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
|
|
'.text',
|
|
'.data.rel',
|
|
'.data.rel',
|
|
'.data.rel',
|
|
'.bss',
|
|
'.threadvar',
|
|
'.pdata',
|
|
'', { stubs }
|
|
'__DATA,__nl_symbol_ptr',
|
|
'__DATA,__la_symbol_ptr',
|
|
'__DATA,__mod_init_func',
|
|
'__DATA,__mod_term_func',
|
|
'.stab',
|
|
'.stabstr',
|
|
'.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
|
|
'.eh_frame',
|
|
'.debug_frame','.debug_info','.debug_line','.debug_abbrev',
|
|
'.fpc',
|
|
'.toc',
|
|
'.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'
|
|
);
|
|
var
|
|
sep : string[3];
|
|
secname : string;
|
|
begin
|
|
if (cs_create_pic in current_settings.moduleswitches) and
|
|
not(target_info.system in systems_darwin) then
|
|
secname:=secnames_pic[atype]
|
|
else
|
|
secname:=secnames[atype];
|
|
{$ifdef m68k}
|
|
{ old Amiga GNU AS doesn't support .section .fpc }
|
|
if (atype=sec_fpc) and (target_info.system = system_m68k_amiga) then
|
|
secname:=secnames[sec_data];
|
|
{$endif}
|
|
if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
|
|
begin
|
|
result:=secname+'.'+aname;
|
|
exit;
|
|
end;
|
|
|
|
if (atype=sec_threadvar) and
|
|
(target_info.system in (systems_windows+systems_wince)) then
|
|
secname:='.tls';
|
|
|
|
{ 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
|
|
secname:='.data';
|
|
|
|
{ section type user gives the user full controll on the section name }
|
|
if atype=sec_user then
|
|
secname:=aname;
|
|
|
|
if is_smart_section(atype) and (aname<>'') then
|
|
begin
|
|
case aorder of
|
|
secorder_begin :
|
|
sep:='.b_';
|
|
secorder_end :
|
|
sep:='.z_';
|
|
else
|
|
sep:='.n_';
|
|
end;
|
|
result:=secname+sep+aname
|
|
end
|
|
else
|
|
result:=secname;
|
|
end;
|
|
|
|
|
|
function TGNUAssembler.sectionattrs_coff(atype:TAsmSectiontype):string;
|
|
begin
|
|
case atype of
|
|
sec_code, sec_init, sec_fini, sec_stub:
|
|
result:='x';
|
|
|
|
{ TODO: must be individual for each section }
|
|
sec_user:
|
|
result:='d';
|
|
|
|
sec_data, sec_data_lazy, sec_data_nonlazy, sec_fpc,
|
|
sec_idata2, sec_idata4, sec_idata5, sec_idata6, sec_idata7:
|
|
result:='d';
|
|
|
|
{ TODO: these need a fix to become read-only }
|
|
sec_rodata, sec_rodata_norel:
|
|
result:='d';
|
|
|
|
sec_bss:
|
|
result:='b';
|
|
|
|
{ TODO: Somewhat questionable. FPC does not allow initialized threadvars,
|
|
so no sense to mark it as containing data. But Windows allows it to
|
|
contain data, and Linux even has .tdata and .tbss }
|
|
sec_threadvar:
|
|
result:='b';
|
|
|
|
sec_pdata, sec_edata, sec_eh_frame, sec_toc:
|
|
result:='r';
|
|
|
|
sec_stab,sec_stabstr,
|
|
sec_debug_frame,sec_debug_info,sec_debug_line,sec_debug_abbrev:
|
|
result:='n';
|
|
else
|
|
result:=''; { defaults to data+load }
|
|
end;
|
|
end;
|
|
|
|
|
|
function TGNUAssembler.sectionalignment_aix(atype:TAsmSectiontype;secalign: byte): string;
|
|
var
|
|
l: longint;
|
|
begin
|
|
if (secalign=0) or
|
|
not(atype in [sec_code,sec_bss,sec_rodata_norel,sec_rodata,sec_data]) then
|
|
begin
|
|
result:='';
|
|
exit;
|
|
end;
|
|
if not ispowerof2(secalign,l) then
|
|
internalerror(2012022201);
|
|
result:=tostr(l);
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder;secalign:byte);
|
|
var
|
|
s : string;
|
|
begin
|
|
writer.AsmLn;
|
|
case target_info.system of
|
|
system_i386_OS2,
|
|
system_i386_EMX,
|
|
system_m68k_amiga: ; { amiga has old GNU AS (2.14), which blews up from .section (KB) }
|
|
system_powerpc_darwin,
|
|
system_i386_darwin,
|
|
system_i386_iphonesim,
|
|
system_powerpc64_darwin,
|
|
system_x86_64_darwin,
|
|
system_arm_darwin,
|
|
system_aarch64_darwin,
|
|
system_x86_64_iphonesim,
|
|
system_powerpc_aix,
|
|
system_powerpc64_aix:
|
|
begin
|
|
if (atype in [sec_stub]) then
|
|
writer.AsmWrite('.section ');
|
|
end
|
|
else
|
|
writer.AsmWrite('.section ');
|
|
end;
|
|
s:=sectionname(atype,aname,aorder);
|
|
writer.AsmWrite(s);
|
|
case atype of
|
|
sec_fpc :
|
|
if aname = 'resptrs' then
|
|
writer.AsmWrite(', "a", @progbits');
|
|
sec_stub :
|
|
begin
|
|
case target_info.system of
|
|
{ there are processor-independent shortcuts available }
|
|
{ for this, namely .symbol_stub and .picsymbol_stub, but }
|
|
{ they don't work and gcc doesn't use them either... }
|
|
system_powerpc_darwin,
|
|
system_powerpc64_darwin:
|
|
if (cs_create_pic in current_settings.moduleswitches) then
|
|
writer.AsmWriteln('__TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32')
|
|
else
|
|
writer.AsmWriteln('__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,16');
|
|
system_i386_darwin,
|
|
system_i386_iphonesim:
|
|
writer.AsmWriteln('__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5');
|
|
system_arm_darwin:
|
|
if (cs_create_pic in current_settings.moduleswitches) then
|
|
writer.AsmWriteln('__TEXT,__picsymbolstub4,symbol_stubs,none,16')
|
|
else
|
|
writer.AsmWriteln('__TEXT,__symbol_stub4,symbol_stubs,none,12')
|
|
{ darwin/(x86-64/AArch64) uses PC-based GOT addressing, no
|
|
explicit symbol stubs }
|
|
else
|
|
internalerror(2006031101);
|
|
end;
|
|
end;
|
|
else
|
|
{ GNU AS won't recognize '.text.n_something' section name as belonging
|
|
to '.text' and assigns default attributes to it, which is not
|
|
always correct. We have to fix it.
|
|
|
|
TODO: This likely applies to all systems which smartlink without
|
|
creating libraries }
|
|
if (target_info.system in [system_i386_win32,system_x86_64_win64]) and
|
|
is_smart_section(atype) and (aname<>'') then
|
|
begin
|
|
s:=sectionattrs_coff(atype);
|
|
if (s<>'') then
|
|
writer.AsmWrite(',"'+s+'"');
|
|
end
|
|
else if target_info.system in systems_aix then
|
|
begin
|
|
s:=sectionalignment_aix(atype,secalign);
|
|
if s<>'' then
|
|
writer.AsmWrite(','+s);
|
|
end;
|
|
end;
|
|
writer.AsmLn;
|
|
LastSecType:=atype;
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteDecodedUleb128(a: qword);
|
|
var
|
|
i,len : longint;
|
|
buf : array[0..63] of byte;
|
|
begin
|
|
len:=EncodeUleb128(a,buf);
|
|
for i:=0 to len-1 do
|
|
begin
|
|
if (i > 0) then
|
|
writer.AsmWrite(',');
|
|
writer.AsmWrite(tostr(buf[i]));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteDecodedSleb128(a: int64);
|
|
var
|
|
i,len : longint;
|
|
buf : array[0..255] of byte;
|
|
begin
|
|
len:=EncodeSleb128(a,buf);
|
|
for i:=0 to len-1 do
|
|
begin
|
|
if (i > 0) then
|
|
writer.AsmWrite(',');
|
|
writer.AsmWrite(tostr(buf[i]));
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteTree(p:TAsmList);
|
|
|
|
function needsObject(hp : tai_symbol) : boolean;
|
|
begin
|
|
needsObject :=
|
|
(
|
|
assigned(hp.next) and
|
|
(tai(hp.next).typ in [ait_const,ait_datablock,ait_realconst])
|
|
) or
|
|
(hp.sym.typ=AT_DATA);
|
|
|
|
end;
|
|
|
|
|
|
procedure doalign(alignment: byte; use_op: boolean; fillop: byte; out last_align: longint;lasthp:tai);
|
|
var
|
|
i: longint;
|
|
{$ifdef m68k}
|
|
instr : string;
|
|
{$endif}
|
|
begin
|
|
last_align:=alignment;
|
|
if alignment>1 then
|
|
begin
|
|
if not(target_info.system in (systems_darwin+systems_aix)) then
|
|
begin
|
|
{$ifdef m68k}
|
|
if not use_op and (lastsectype=sec_code) then
|
|
begin
|
|
if not ispowerof2(alignment,i) then
|
|
internalerror(2014022201);
|
|
{ the Coldfire manual suggests the TBF instruction for
|
|
alignments, but somehow QEMU does not interpret that
|
|
correctly... }
|
|
{if current_settings.cputype in cpu_coldfire then
|
|
instr:='0x51fc'
|
|
else}
|
|
instr:='0x4e71';
|
|
writer.AsmWrite(#9'.balignw '+tostr(alignment)+','+instr);
|
|
end
|
|
else
|
|
begin
|
|
{$endif m68k}
|
|
writer.AsmWrite(#9'.balign '+tostr(alignment));
|
|
if use_op then
|
|
writer.AsmWrite(','+tostr(fillop))
|
|
{$ifdef x86}
|
|
{ force NOP as alignment op code }
|
|
else if (LastSecType=sec_code) and (asminfo^.id<>as_solaris_as) then
|
|
writer.AsmWrite(',0x90');
|
|
{$endif x86}
|
|
{$ifdef m68k}
|
|
end;
|
|
{$endif m68k}
|
|
end
|
|
else
|
|
begin
|
|
{ darwin and aix as only support .align }
|
|
if not ispowerof2(alignment,i) then
|
|
internalerror(2003010305);
|
|
writer.AsmWrite(#9'.align '+tostr(i));
|
|
last_align:=i;
|
|
end;
|
|
writer.AsmLn;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ch : char;
|
|
lasthp,
|
|
hp : tai;
|
|
constdef : taiconst_type;
|
|
s,t : string;
|
|
i,pos,l : longint;
|
|
InlineLevel : cardinal;
|
|
last_align : longint;
|
|
do_line : boolean;
|
|
|
|
sepChar : char;
|
|
replaceforbidden: boolean;
|
|
begin
|
|
if not assigned(p) then
|
|
exit;
|
|
replaceforbidden:=asminfo^.dollarsign<>'$';
|
|
|
|
last_align := 2;
|
|
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]));
|
|
lasthp:=nil;
|
|
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
|
|
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
|
|
begin
|
|
writer.AsmWrite(#9+asminfo^.comment+'Register ');
|
|
repeat
|
|
writer.AsmWrite(std_regname(Tai_regalloc(hp).reg));
|
|
if (hp.next=nil) or
|
|
(tai(hp.next).typ<>ait_regalloc) or
|
|
(tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
|
|
break;
|
|
hp:=tai(hp.next);
|
|
writer.AsmWrite(',');
|
|
until false;
|
|
writer.AsmWrite(' ');
|
|
writer.AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
|
|
end;
|
|
end;
|
|
|
|
ait_tempalloc :
|
|
begin
|
|
if (cs_asm_tempalloc in current_settings.globalswitches) then
|
|
WriteTempalloc(tai_tempalloc(hp));
|
|
end;
|
|
|
|
ait_align :
|
|
begin
|
|
doalign(tai_align_abstract(hp).aligntype,tai_align_abstract(hp).use_op,tai_align_abstract(hp).fillop,last_align,lasthp);
|
|
end;
|
|
|
|
ait_section :
|
|
begin
|
|
if tai_section(hp).sectype<>sec_none then
|
|
if replaceforbidden then
|
|
WriteSection(tai_section(hp).sectype,ReplaceForbiddenAsmSymbolChars(tai_section(hp).name^),tai_section(hp).secorder,tai_section(hp).secalign)
|
|
else
|
|
WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secorder,tai_section(hp).secalign)
|
|
else
|
|
begin
|
|
{$ifdef EXTDEBUG}
|
|
writer.AsmWrite(asminfo^.comment);
|
|
writer.AsmWriteln(' sec_none');
|
|
{$endif EXTDEBUG}
|
|
end;
|
|
end;
|
|
|
|
ait_datablock :
|
|
begin
|
|
if (target_info.system in systems_darwin) then
|
|
begin
|
|
{ On Mac OS X you can't have common symbols in a shared library
|
|
since those are in the TEXT section and the text section is
|
|
read-only in shared libraries (so it can be shared among different
|
|
processes). The alternate code creates some kind of common symbols
|
|
in the data segment.
|
|
}
|
|
if tai_datablock(hp).is_global then
|
|
begin
|
|
writer.AsmWrite('.globl ');
|
|
writer.AsmWriteln(tai_datablock(hp).sym.name);
|
|
writer.AsmWriteln('.data');
|
|
writer.AsmWrite('.zerofill __DATA, __common, ');
|
|
writer.AsmWrite(tai_datablock(hp).sym.name);
|
|
writer.AsmWriteln(', '+tostr(tai_datablock(hp).size)+','+tostr(last_align));
|
|
if not(LastSecType in [sec_data,sec_none]) then
|
|
writesection(LastSecType,'',secorder_default,1 shl last_align);
|
|
end
|
|
else
|
|
begin
|
|
writer.AsmWrite(#9'.lcomm'#9);
|
|
writer.AsmWrite(tai_datablock(hp).sym.name);
|
|
writer.AsmWrite(','+tostr(tai_datablock(hp).size));
|
|
writer.AsmWrite(','+tostr(last_align));
|
|
writer.AsmLn;
|
|
end;
|
|
end
|
|
else if target_info.system in systems_aix then
|
|
begin
|
|
if tai_datablock(hp).is_global then
|
|
begin
|
|
writer.AsmWrite(#9'.globl ');
|
|
writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
|
|
writer.AsmWriteln(':');
|
|
writer.AsmWrite(#9'.space ');
|
|
writer.AsmWriteln(tostr(tai_datablock(hp).size));
|
|
if not(LastSecType in [sec_data,sec_none]) then
|
|
writesection(LastSecType,'',secorder_default,1 shl last_align);
|
|
end
|
|
else
|
|
begin
|
|
writer.AsmWrite(#9'.lcomm ');
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
|
|
writer.AsmWrite(',');
|
|
writer.AsmWrite(tostr(tai_datablock(hp).size)+',');
|
|
writer.AsmWrite('_data.bss_,');
|
|
writer.AsmWriteln(tostr(last_align));
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
{$ifdef USE_COMM_IN_BSS}
|
|
if writingpackages then
|
|
begin
|
|
{ The .comm is required for COMMON symbols. These are used
|
|
in the shared library loading. All the symbols declared in
|
|
the .so file need to resolve to the data allocated in the main
|
|
program (PFV) }
|
|
if tai_datablock(hp).is_global then
|
|
begin
|
|
writer.AsmWrite(#9'.comm'#9);
|
|
if replaceforbidden then
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name))
|
|
else
|
|
writer.AsmWrite(tai_datablock(hp).sym.name);
|
|
writer.AsmWrite(','+tostr(tai_datablock(hp).size));
|
|
writer.AsmWrite(','+tostr(last_align));
|
|
writer.AsmLn;
|
|
end
|
|
else
|
|
begin
|
|
writer.AsmWrite(#9'.lcomm'#9);
|
|
if replaceforbidden then
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name));
|
|
else
|
|
writer.AsmWrite(tai_datablock(hp).sym.name);
|
|
writer.AsmWrite(','+tostr(tai_datablock(hp).size));
|
|
writer.AsmWrite(','+tostr(last_align));
|
|
writer.AsmLn;
|
|
end
|
|
end
|
|
else
|
|
{$endif USE_COMM_IN_BSS}
|
|
begin
|
|
if Tai_datablock(hp).is_global then
|
|
begin
|
|
writer.AsmWrite(#9'.globl ');
|
|
if replaceforbidden then
|
|
writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name))
|
|
else
|
|
writer.AsmWriteln(Tai_datablock(hp).sym.name);
|
|
end;
|
|
if ((target_info.system <> system_arm_linux) and (target_info.system <> system_arm_android)) then
|
|
sepChar := '@'
|
|
else
|
|
sepChar := '%';
|
|
if replaceforbidden then
|
|
begin
|
|
if (tf_needs_symbol_type in target_info.flags) then
|
|
writer.AsmWriteln(#9'.type '+ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name)+','+sepChar+'object');
|
|
if (tf_needs_symbol_size in target_info.flags) and (tai_datablock(hp).size > 0) then
|
|
writer.AsmWriteln(#9'.size '+ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name)+','+tostr(Tai_datablock(hp).size));
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name))
|
|
end
|
|
else
|
|
begin
|
|
if (tf_needs_symbol_type in target_info.flags) then
|
|
writer.AsmWriteln(#9'.type '+Tai_datablock(hp).sym.name+','+sepChar+'object');
|
|
if (tf_needs_symbol_size in target_info.flags) and (tai_datablock(hp).size > 0) then
|
|
writer.AsmWriteln(#9'.size '+Tai_datablock(hp).sym.name+','+tostr(Tai_datablock(hp).size));
|
|
writer.AsmWrite(Tai_datablock(hp).sym.name);
|
|
end;
|
|
writer.AsmWriteln(':');
|
|
writer.AsmWriteln(#9'.zero '+tostr(Tai_datablock(hp).size));
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
ait_const:
|
|
begin
|
|
constdef:=tai_const(hp).consttype;
|
|
case constdef of
|
|
{$ifndef cpu64bitaddr}
|
|
aitconst_128bit :
|
|
begin
|
|
internalerror(200404291);
|
|
end;
|
|
|
|
aitconst_64bit :
|
|
begin
|
|
if assigned(tai_const(hp).sym) then
|
|
internalerror(200404292);
|
|
if not(target_info.system in systems_aix) then
|
|
begin
|
|
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;
|
|
end
|
|
else
|
|
WriteAixIntConst(tai_const(hp));
|
|
writer.AsmLn;
|
|
end;
|
|
{$endif cpu64bitaddr}
|
|
aitconst_got:
|
|
begin
|
|
if tai_const(hp).symofs<>0 then
|
|
InternalError(2015091401); // No symbol offset is allowed for GOT.
|
|
writer.AsmWrite(#9'.word'#9+tai_const(hp).sym.name+'(GOT)');
|
|
writer.AsmLn;
|
|
end;
|
|
|
|
aitconst_gotoff_symbol:
|
|
begin
|
|
if (tai_const(hp).sym=nil) then
|
|
InternalError(2014022601);
|
|
case target_info.cpu of
|
|
|
|
cpu_mipseb,cpu_mipsel:
|
|
begin
|
|
writer.AsmWrite(#9'.gpword'#9);
|
|
writer.AsmWrite(tai_const(hp).sym.name);
|
|
end;
|
|
|
|
cpu_i386:
|
|
begin
|
|
writer.AsmWrite(ait_const2str[aitconst_32bit]);
|
|
writer.AsmWrite(tai_const(hp).sym.name+'-_GLOBAL_OFFSET_TABLE_');
|
|
end;
|
|
else
|
|
InternalError(2014022602);
|
|
end;
|
|
if (tai_const(hp).value<>0) then
|
|
writer.AsmWrite(tostr_with_plus(tai_const(hp).value));
|
|
writer.AsmLn;
|
|
end;
|
|
|
|
aitconst_uleb128bit,
|
|
aitconst_sleb128bit,
|
|
{$ifdef cpu64bitaddr}
|
|
aitconst_128bit,
|
|
aitconst_64bit,
|
|
{$endif cpu64bitaddr}
|
|
aitconst_32bit,
|
|
aitconst_16bit,
|
|
aitconst_8bit,
|
|
aitconst_rva_symbol,
|
|
aitconst_secrel32_symbol,
|
|
aitconst_darwin_dwarf_delta32,
|
|
aitconst_darwin_dwarf_delta64,
|
|
aitconst_half16bit,
|
|
aitconst_gs,
|
|
aitconst_16bit_unaligned,
|
|
aitconst_32bit_unaligned,
|
|
aitconst_64bit_unaligned:
|
|
begin
|
|
{ the AIX assembler (and for compatibility, the GNU
|
|
assembler when targeting AIX) automatically aligns
|
|
.short/.long/.llong to a multiple of 2/4/8 bytes. We
|
|
don't want that, since this may be data inside a packed
|
|
record -> use .vbyte instead (byte stream of fixed
|
|
length) }
|
|
if (target_info.system in systems_aix) and
|
|
(constdef in [aitconst_128bit,aitconst_64bit,aitconst_32bit,aitconst_16bit]) and
|
|
not assigned(tai_const(hp).sym) then
|
|
begin
|
|
WriteAixIntConst(tai_const(hp));
|
|
end
|
|
else if (target_info.system in systems_darwin) and
|
|
(constdef in [aitconst_uleb128bit,aitconst_sleb128bit]) then
|
|
begin
|
|
writer.AsmWrite(ait_const2str[aitconst_8bit]);
|
|
case tai_const(hp).consttype of
|
|
aitconst_uleb128bit:
|
|
WriteDecodedUleb128(qword(tai_const(hp).value));
|
|
aitconst_sleb128bit:
|
|
WriteDecodedSleb128(int64(tai_const(hp).value));
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
if (constdef in ait_unaligned_consts) and
|
|
(target_info.system in use_ua_sparc_systems) then
|
|
writer.AsmWrite(ait_ua_sparc_const2str[constdef])
|
|
else if (constdef in ait_unaligned_consts) and
|
|
(target_info.system in use_ua_elf_systems) then
|
|
writer.AsmWrite(ait_ua_elf_const2str[constdef])
|
|
{ we can also have unaligned pointers in packed record
|
|
constants, which don't get translated into
|
|
unaligned tai -> always use vbyte }
|
|
else if target_info.system in systems_aix then
|
|
writer.AsmWrite(#9'.vbyte'#9+tostr(tai_const(hp).size)+',')
|
|
else if (asminfo^.id=as_solaris_as) then
|
|
writer.AsmWrite(ait_solaris_const2str[constdef])
|
|
else
|
|
writer.AsmWrite(ait_const2str[constdef]);
|
|
l:=0;
|
|
t := '';
|
|
repeat
|
|
if assigned(tai_const(hp).sym) then
|
|
begin
|
|
if assigned(tai_const(hp).endsym) then
|
|
begin
|
|
if (constdef in [aitconst_darwin_dwarf_delta32,aitconst_darwin_dwarf_delta64]) then
|
|
begin
|
|
s := NextSetLabel;
|
|
t := #9'.set '+s+','+tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name;
|
|
end
|
|
else
|
|
s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
|
|
end
|
|
else
|
|
s:=tai_const(hp).sym.name;
|
|
if replaceforbidden then
|
|
s:=ReplaceForbiddenAsmSymbolChars(s);
|
|
if tai_const(hp).value<>0 then
|
|
s:=s+tostr_with_plus(tai_const(hp).value);
|
|
end
|
|
else
|
|
{$ifdef cpu64bitaddr}
|
|
s:=tostr(tai_const(hp).value);
|
|
{$else cpu64bitaddr}
|
|
{ 64 bit constants are already handled above in this case }
|
|
s:=tostr(longint(tai_const(hp).value));
|
|
{$endif cpu64bitaddr}
|
|
if constdef = aitconst_half16bit then
|
|
s:='('+s+')/2';
|
|
if constdef = aitconst_gs then
|
|
s:='gs('+s+')';
|
|
|
|
writer.AsmWrite(s);
|
|
inc(l,length(s));
|
|
{ Values with symbols are written on a single line to improve
|
|
reading of the .s file (PFV) }
|
|
if assigned(tai_const(hp).sym) or
|
|
not(LastSecType in [sec_data,sec_rodata,sec_rodata_norel]) or
|
|
(l>line_length) or
|
|
(hp.next=nil) or
|
|
(tai(hp.next).typ<>ait_const) or
|
|
(tai_const(hp.next).consttype<>constdef) or
|
|
assigned(tai_const(hp.next).sym) then
|
|
break;
|
|
hp:=tai(hp.next);
|
|
writer.AsmWrite(',');
|
|
until false;
|
|
if (t <> '') then
|
|
begin
|
|
writer.AsmLn;
|
|
writer.AsmWrite(t);
|
|
end;
|
|
end;
|
|
writer.AsmLn;
|
|
end;
|
|
else
|
|
internalerror(200704251);
|
|
end;
|
|
end;
|
|
|
|
ait_realconst :
|
|
begin
|
|
WriteRealConstAsBytes(tai_realconst(hp),#9'.byte'#9,do_line);
|
|
end;
|
|
|
|
ait_string :
|
|
begin
|
|
pos:=0;
|
|
if not(target_info.system in systems_aix) then
|
|
begin
|
|
for i:=1 to tai_string(hp).len do
|
|
begin
|
|
if pos=0 then
|
|
begin
|
|
writer.AsmWrite(#9'.ascii'#9'"');
|
|
pos:=20;
|
|
end;
|
|
ch:=tai_string(hp).str[i-1];
|
|
case ch of
|
|
#0, {This can't be done by range, because a bug in FPC}
|
|
#1..#31,
|
|
#128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
|
|
'"' : s:='\"';
|
|
'\' : s:='\\';
|
|
else
|
|
s:=ch;
|
|
end;
|
|
writer.AsmWrite(s);
|
|
inc(pos,length(s));
|
|
if (pos>line_length) or (i=tai_string(hp).len) then
|
|
begin
|
|
writer.AsmWriteLn('"');
|
|
pos:=0;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
WriteAixStringConst(tai_string(hp));
|
|
end;
|
|
|
|
ait_label :
|
|
begin
|
|
if (tai_label(hp).labsym.is_used) then
|
|
begin
|
|
if (tai_label(hp).labsym.bind=AB_PRIVATE_EXTERN) then
|
|
begin
|
|
writer.AsmWrite(#9'.private_extern ');
|
|
writer.AsmWriteln(tai_label(hp).labsym.name);
|
|
end;
|
|
if tai_label(hp).labsym.bind in [AB_GLOBAL,AB_PRIVATE_EXTERN] then
|
|
begin
|
|
{$ifdef arm}
|
|
{ do no change arm mode accidently, .globl seems to reset the mode }
|
|
if GenerateThumbCode or GenerateThumb2Code then
|
|
writer.AsmWriteln(#9'.thumb_func'#9);
|
|
{$endif arm}
|
|
writer.AsmWrite('.globl'#9);
|
|
if replaceforbidden then
|
|
writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
|
|
else
|
|
writer.AsmWriteLn(tai_label(hp).labsym.name);
|
|
end;
|
|
if replaceforbidden then
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name))
|
|
else
|
|
writer.AsmWrite(tai_label(hp).labsym.name);
|
|
writer.AsmWriteLn(':');
|
|
end;
|
|
end;
|
|
|
|
ait_symbol :
|
|
begin
|
|
if (tai_symbol(hp).sym.bind=AB_PRIVATE_EXTERN) then
|
|
begin
|
|
writer.AsmWrite(#9'.private_extern ');
|
|
if replaceforbidden then
|
|
writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name))
|
|
else
|
|
writer.AsmWriteln(tai_symbol(hp).sym.name);
|
|
end;
|
|
if (target_info.system=system_powerpc64_linux) and
|
|
(tai_symbol(hp).sym.typ=AT_FUNCTION) and
|
|
(cs_profile in current_settings.moduleswitches) then
|
|
writer.AsmWriteLn('.globl _mcount');
|
|
|
|
if tai_symbol(hp).is_global then
|
|
begin
|
|
writer.AsmWrite('.globl'#9);
|
|
if replaceforbidden then
|
|
writer.AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name))
|
|
else
|
|
writer.AsmWriteln(tai_symbol(hp).sym.name);
|
|
end;
|
|
if (target_info.system=system_powerpc64_linux) and
|
|
use_dotted_functions and
|
|
(tai_symbol(hp).sym.typ=AT_FUNCTION) then
|
|
begin
|
|
writer.AsmWriteLn('.section ".opd", "aw"');
|
|
writer.AsmWriteLn('.align 3');
|
|
writer.AsmWriteLn(tai_symbol(hp).sym.name + ':');
|
|
writer.AsmWriteLn('.quad .' + tai_symbol(hp).sym.name + ', .TOC.@tocbase, 0');
|
|
writer.AsmWriteLn('.previous');
|
|
writer.AsmWriteLn('.size ' + tai_symbol(hp).sym.name + ', 24');
|
|
if (tai_symbol(hp).is_global) then
|
|
writer.AsmWriteLn('.globl .' + tai_symbol(hp).sym.name);
|
|
writer.AsmWriteLn('.type .' + tai_symbol(hp).sym.name + ', @function');
|
|
{ the dotted name is the name of the actual function entry }
|
|
writer.AsmWrite('.');
|
|
end
|
|
else if (target_info.system in systems_aix) and
|
|
(tai_symbol(hp).sym.typ = AT_FUNCTION) then
|
|
begin
|
|
if target_info.system=system_powerpc_aix then
|
|
begin
|
|
s:=#9'.long .';
|
|
ch:='2';
|
|
end
|
|
else
|
|
begin
|
|
s:=#9'.llong .';
|
|
ch:='3';
|
|
end;
|
|
writer.AsmWriteLn(#9'.csect '+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+'[DS],'+ch);
|
|
writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+':');
|
|
writer.AsmWriteln(s+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+', TOC[tc0], 0');
|
|
writer.AsmWriteln(#9'.csect .text[PR]');
|
|
if (tai_symbol(hp).is_global) then
|
|
writer.AsmWriteLn('.globl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name))
|
|
else
|
|
writer.AsmWriteLn('.lglobl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name));
|
|
{ the dotted name is the name of the actual function entry }
|
|
writer.AsmWrite('.');
|
|
end
|
|
else
|
|
begin
|
|
if ((target_info.system <> system_arm_linux) and (target_info.system <> system_arm_android)) then
|
|
sepChar := '@'
|
|
else
|
|
sepChar := '#';
|
|
if (tf_needs_symbol_type in target_info.flags) then
|
|
begin
|
|
writer.AsmWrite(#9'.type'#9 + tai_symbol(hp).sym.name);
|
|
if (needsObject(tai_symbol(hp))) then
|
|
writer.AsmWriteLn(',' + sepChar + 'object')
|
|
else
|
|
writer.AsmWriteLn(',' + sepChar + 'function');
|
|
end;
|
|
end;
|
|
if replaceforbidden then
|
|
if not(tai_symbol(hp).has_value) then
|
|
writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name + ':'))
|
|
else
|
|
writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name + '=' + tostr(tai_symbol(hp).value)))
|
|
else if not(tai_symbol(hp).has_value) then
|
|
writer.AsmWriteLn(tai_symbol(hp).sym.name + ':')
|
|
else
|
|
writer.AsmWriteLn(tai_symbol(hp).sym.name + '=' + tostr(tai_symbol(hp).value));
|
|
end;
|
|
ait_symbolpair:
|
|
begin
|
|
writer.AsmWrite(#9);
|
|
writer.AsmWrite(symbolpairkindstr[tai_symbolpair(hp).kind]);
|
|
writer.AsmWrite(' ');
|
|
if tai_symbolpair(hp).kind<>spk_localentry then
|
|
s:=', '
|
|
else
|
|
{ the .localentry directive has to specify the size from the
|
|
start till here of the non-local entry code as second argument }
|
|
s:=', .-';
|
|
if replaceforbidden then
|
|
begin
|
|
{ avoid string truncation }
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^)+s);
|
|
writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).value^));
|
|
end
|
|
else
|
|
begin
|
|
{ avoid string truncation }
|
|
writer.AsmWrite(tai_symbolpair(hp).sym^+s);
|
|
writer.AsmWriteLn(tai_symbolpair(hp).value^);
|
|
end;
|
|
end;
|
|
ait_symbol_end :
|
|
begin
|
|
if tf_needs_symbol_size in target_info.flags then
|
|
begin
|
|
s:=asminfo^.labelprefix+'e'+tostr(symendcount);
|
|
inc(symendcount);
|
|
writer.AsmWriteLn(s+':');
|
|
writer.AsmWrite(#9'.size'#9);
|
|
if (target_info.system=system_powerpc64_linux) and
|
|
use_dotted_functions and
|
|
(tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
|
|
writer.AsmWrite('.');
|
|
if replaceforbidden then
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name))
|
|
else
|
|
writer.AsmWrite(tai_symbol_end(hp).sym.name);
|
|
writer.AsmWrite(', '+s+' - ');
|
|
if (target_info.system=system_powerpc64_linux) and
|
|
use_dotted_functions and
|
|
(tai_symbol_end(hp).sym.typ=AT_FUNCTION) then
|
|
writer.AsmWrite('.');
|
|
if replaceforbidden then
|
|
writer.AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name))
|
|
else
|
|
writer.AsmWriteLn(tai_symbol_end(hp).sym.name);
|
|
end;
|
|
end;
|
|
|
|
ait_instruction :
|
|
begin
|
|
WriteInstruction(hp);
|
|
end;
|
|
|
|
ait_stab :
|
|
begin
|
|
if assigned(tai_stab(hp).str) then
|
|
begin
|
|
writer.AsmWrite(#9'.'+stabtypestr[tai_stab(hp).stabtype]+' ');
|
|
writer.AsmWritePChar(tai_stab(hp).str);
|
|
writer.AsmLn;
|
|
end;
|
|
end;
|
|
|
|
ait_force_line,
|
|
ait_function_name :
|
|
begin
|
|
{$ifdef DEBUG_AGGAS}
|
|
WriteStr(s,hp.typ);
|
|
writer.AsmWriteLn('# '+s);
|
|
{$endif DEBUG_AGGAS}
|
|
end;
|
|
|
|
ait_cutobject :
|
|
begin
|
|
{$ifdef DEBUG_AGGAS}
|
|
writer.AsmWriteLn('# ait_cutobject');
|
|
{$endif DEBUG_AGGAS}
|
|
if SmartAsm then
|
|
begin
|
|
{ only reset buffer if nothing has changed }
|
|
if not(writer.ClearIfEmpty) then
|
|
begin
|
|
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 LastSecType<>sec_none then
|
|
WriteSection(LastSecType,'',secorder_default,last_align);
|
|
writer.MarkEmpty;
|
|
end;
|
|
end;
|
|
|
|
ait_marker :
|
|
begin
|
|
{$ifdef DEBUG_AGGAS}
|
|
WriteStr(s,tai_marker(hp).Kind);
|
|
writer.AsmWriteLn('# ait_marker, kind: '+s);
|
|
{$endif DEBUG_AGGAS}
|
|
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
|
|
WriteDirectiveName(tai_directive(hp).directive);
|
|
if tai_directive(hp).name <>'' then
|
|
begin
|
|
if replaceforbidden then
|
|
writer.AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_directive(hp).name))
|
|
else
|
|
writer.AsmWrite(tai_directive(hp).name);
|
|
end;
|
|
writer.AsmLn;
|
|
end;
|
|
|
|
ait_seh_directive :
|
|
begin
|
|
{$ifndef DISABLE_WIN64_SEH}
|
|
writer.AsmWrite(sehdirectivestr[tai_seh_directive(hp).kind]);
|
|
case tai_seh_directive(hp).datatype of
|
|
sd_none:;
|
|
sd_string:
|
|
begin
|
|
writer.AsmWrite(' '+tai_seh_directive(hp).data.name^);
|
|
if (tai_seh_directive(hp).data.flags and 1)<>0 then
|
|
writer.AsmWrite(',@except');
|
|
if (tai_seh_directive(hp).data.flags and 2)<>0 then
|
|
writer.AsmWrite(',@unwind');
|
|
end;
|
|
sd_reg:
|
|
writer.AsmWrite(' '+gas_regname(tai_seh_directive(hp).data.reg));
|
|
sd_offset:
|
|
writer.AsmWrite(' '+tostr(tai_seh_directive(hp).data.offset));
|
|
sd_regoffset:
|
|
writer.AsmWrite(' '+gas_regname(tai_seh_directive(hp).data.reg)+', '+
|
|
tostr(tai_seh_directive(hp).data.offset));
|
|
end;
|
|
writer.AsmLn;
|
|
{$endif DISABLE_WIN64_SEH}
|
|
end;
|
|
|
|
ait_varloc:
|
|
begin
|
|
if tai_varloc(hp).newlocationhi<>NR_NO then
|
|
writer.AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
|
|
std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation)))
|
|
else
|
|
writer.AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+
|
|
std_regname(tai_varloc(hp).newlocation)));
|
|
writer.AsmLn;
|
|
end;
|
|
else
|
|
internalerror(2006012201);
|
|
end;
|
|
lasthp:=hp;
|
|
hp:=tai(hp.next);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteExtraHeader;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteExtraFooter;
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteInstruction(hp: tai);
|
|
begin
|
|
InstrWriter.WriteInstruction(hp);
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteWeakSymbolRef(s: tasmsymbol);
|
|
begin
|
|
writer.AsmWriteLn(#9'.weak '+s.name);
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteAixStringConst(hp: tai_string);
|
|
type
|
|
tterminationkind = (term_none,term_string,term_nostring);
|
|
|
|
var
|
|
i: longint;
|
|
pos: longint;
|
|
s: string;
|
|
ch: char;
|
|
instring: boolean;
|
|
|
|
procedure newstatement(terminationkind: tterminationkind);
|
|
begin
|
|
case terminationkind of
|
|
term_none: ;
|
|
term_string:
|
|
writer.AsmWriteLn('"');
|
|
term_nostring:
|
|
writer.AsmLn;
|
|
end;
|
|
writer.AsmWrite(#9'.byte'#9);
|
|
pos:=20;
|
|
instring:=false;
|
|
end;
|
|
|
|
begin
|
|
pos:=0;
|
|
instring:=false;
|
|
for i:=1 to hp.len do
|
|
begin
|
|
if pos=0 then
|
|
newstatement(term_none);
|
|
ch:=hp.str[i-1];
|
|
case ch of
|
|
#0..#31,
|
|
#127..#255 :
|
|
begin
|
|
if instring then
|
|
newstatement(term_string);
|
|
if pos=20 then
|
|
s:=tostr(ord(ch))
|
|
else
|
|
s:=', '+tostr(ord(ch))
|
|
end;
|
|
'"' :
|
|
if instring then
|
|
s:='""'
|
|
else
|
|
begin
|
|
if pos<>20 then
|
|
newstatement(term_nostring);
|
|
s:='"""';
|
|
instring:=true;
|
|
end;
|
|
else
|
|
if not instring then
|
|
begin
|
|
if (pos<>20) then
|
|
newstatement(term_nostring);
|
|
s:='"'+ch;
|
|
instring:=true;
|
|
end
|
|
else
|
|
s:=ch;
|
|
end;
|
|
writer.AsmWrite(s);
|
|
inc(pos,length(s));
|
|
if (pos>line_length) or (i=tai_string(hp).len) then
|
|
begin
|
|
if instring then
|
|
writer.AsmWriteLn('"')
|
|
else
|
|
writer.AsmLn;
|
|
pos:=0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteAixIntConst(hp: tai_const);
|
|
var
|
|
pos, size: longint;
|
|
begin
|
|
{ only big endian AIX supported for now }
|
|
if target_info.endian<>endian_big then
|
|
internalerror(2012010401);
|
|
{ limitation: can only write 4 bytes at a time }
|
|
pos:=0;
|
|
size:=tai_const(hp).size;
|
|
while pos<(size-4) do
|
|
begin
|
|
writer.AsmWrite(#9'.vbyte'#9'4, ');
|
|
writer.AsmWriteln(tostr(longint(tai_const(hp).value shr ((size-pos-4)*8))));
|
|
inc(pos,4);
|
|
end;
|
|
writer.AsmWrite(#9'.vbyte'#9);
|
|
writer.AsmWrite(tostr(size-pos));
|
|
writer.AsmWrite(', ');
|
|
case size-pos of
|
|
1: writer.AsmWrite(tostr(byte(tai_const(hp).value)));
|
|
2: writer.AsmWrite(tostr(word(tai_const(hp).value)));
|
|
4: writer.AsmWrite(tostr(longint(tai_const(hp).value)));
|
|
else
|
|
internalerror(2012010402);
|
|
end;
|
|
end;
|
|
|
|
procedure TGNUAssembler.WriteUnalignedIntConst(hp: tai_const);
|
|
var
|
|
pos, size: longint;
|
|
begin
|
|
size:=tai_const(hp).size;
|
|
writer.AsmWrite(#9'.byte'#9);
|
|
if target_info.endian=endian_big then
|
|
begin
|
|
pos:=size-1;
|
|
while pos>=0 do
|
|
begin
|
|
writer.AsmWrite(tostr((tai_const(hp).value shr (pos*8)) and $ff));
|
|
dec(pos);
|
|
if pos>=0 then
|
|
writer.AsmWrite(', ')
|
|
else
|
|
writer.AsmLn;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
pos:=0;
|
|
while pos<size do
|
|
begin
|
|
writer.AsmWriteln(tostr((tai_const(hp).value shr (pos*8)) and $ff));
|
|
inc(pos);
|
|
if pos<=size then
|
|
writer.AsmWrite(', ')
|
|
else
|
|
writer.AsmLn;
|
|
end;
|
|
end;
|
|
writer.AsmLn;
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteDirectiveName(dir: TAsmDirective);
|
|
begin
|
|
{ TODO: implement asd_cpu for GAS => usually .arch or .cpu, but the CPU
|
|
name has to be translated as well }
|
|
if dir=asd_cpu then
|
|
writer.AsmWrite(asminfo^.comment+' CPU ')
|
|
else
|
|
writer.AsmWrite('.'+directivestr[dir]+' ');
|
|
end;
|
|
|
|
|
|
procedure TGNUAssembler.WriteAsmList;
|
|
var
|
|
n : string;
|
|
hal : tasmlisttype;
|
|
i: longint;
|
|
begin
|
|
{$ifdef EXTDEBUG}
|
|
if current_module.mainsource<>'' then
|
|
Comment(V_Debug,'Start writing gas-styled assembler output for '+current_module.mainsource);
|
|
{$endif}
|
|
|
|
if current_module.mainsource<>'' then
|
|
n:=ExtractFileName(current_module.mainsource)
|
|
else
|
|
n:=InputFileName;
|
|
|
|
{ gcc does not add it either for Darwin. Grep for
|
|
TARGET_ASM_FILE_START_FILE_DIRECTIVE in gcc/config/*.h
|
|
}
|
|
if not(target_info.system in systems_darwin) then
|
|
writer.AsmWriteLn(#9'.file "'+FixFileName(n)+'"');
|
|
|
|
WriteExtraHeader;
|
|
writer.MarkEmpty;
|
|
symendcount:=0;
|
|
|
|
for hal:=low(TasmlistType) to high(TasmlistType) do
|
|
begin
|
|
if not (current_asmdata.asmlists[hal].empty) then
|
|
begin
|
|
writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
|
|
writetree(current_asmdata.asmlists[hal]);
|
|
writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmlistTypeStr[hal]);
|
|
end;
|
|
end;
|
|
|
|
{ add weak symbol markers }
|
|
for i:=0 to current_asmdata.asmsymboldict.count-1 do
|
|
if (tasmsymbol(current_asmdata.asmsymboldict[i]).bind=AB_WEAK_EXTERNAL) then
|
|
WriteWeakSymbolRef(tasmsymbol(current_asmdata.asmsymboldict[i]));
|
|
|
|
if create_smartlink_sections and
|
|
(target_info.system in systems_darwin) then
|
|
writer.AsmWriteLn(#9'.subsections_via_symbols');
|
|
|
|
{ "no executable stack" marker }
|
|
{ TODO: used by OpenBSD/NetBSD as well? }
|
|
if (target_info.system in (systems_linux + systems_android + systems_freebsd + systems_dragonfly)) and
|
|
not(cs_executable_stack in current_settings.moduleswitches) then
|
|
begin
|
|
writer.AsmWriteLn('.section .note.GNU-stack,"",%progbits');
|
|
end;
|
|
|
|
writer.AsmLn;
|
|
WriteExtraFooter;
|
|
{$ifdef EXTDEBUG}
|
|
if current_module.mainsource<>'' then
|
|
Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource);
|
|
{$endif EXTDEBUG}
|
|
end;
|
|
|
|
|
|
{****************************************************************************}
|
|
{ Apple/GNU Assembler writer }
|
|
{****************************************************************************}
|
|
|
|
function TAppleGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
|
|
begin
|
|
if (target_info.system in systems_darwin) then
|
|
case atype of
|
|
sec_user:
|
|
begin
|
|
result:='.section '+aname;
|
|
exit;
|
|
end;
|
|
sec_bss:
|
|
{ all bss (lcomm) symbols are automatically put in the right }
|
|
{ place by using the lcomm assembler directive }
|
|
atype := sec_none;
|
|
sec_debug_frame,
|
|
sec_eh_frame:
|
|
begin
|
|
result := '.section __DWARF,__debug_info,regular,debug';
|
|
exit;
|
|
end;
|
|
sec_debug_line:
|
|
begin
|
|
result := '.section __DWARF,__debug_line,regular,debug';
|
|
exit;
|
|
end;
|
|
sec_debug_info:
|
|
begin
|
|
result := '.section __DWARF,__debug_info,regular,debug';
|
|
exit;
|
|
end;
|
|
sec_debug_abbrev:
|
|
begin
|
|
result := '.section __DWARF,__debug_abbrev,regular,debug';
|
|
exit;
|
|
end;
|
|
sec_rodata:
|
|
begin
|
|
result := '.const_data';
|
|
exit;
|
|
end;
|
|
sec_rodata_norel:
|
|
begin
|
|
result := '.const';
|
|
exit;
|
|
end;
|
|
sec_fpc:
|
|
begin
|
|
result := '.section __TEXT, .fpc, regular, no_dead_strip';
|
|
exit;
|
|
end;
|
|
sec_code:
|
|
begin
|
|
if (aname='fpc_geteipasebx') or
|
|
(aname='fpc_geteipasecx') then
|
|
begin
|
|
result:='.section __TEXT,__textcoal_nt,coalesced,pure_instructions'#10'.weak_definition '+aname+
|
|
#10'.private_extern '+aname;
|
|
exit;
|
|
end;
|
|
end;
|
|
sec_data_nonlazy:
|
|
begin
|
|
result:='.section __DATA, __nl_symbol_ptr,non_lazy_symbol_pointers';
|
|
exit;
|
|
end;
|
|
sec_data_lazy:
|
|
begin
|
|
result:='.section __DATA, __la_symbol_ptr,lazy_symbol_pointers';
|
|
exit;
|
|
end;
|
|
sec_init_func:
|
|
begin
|
|
result:='.section __DATA, __mod_init_func, mod_init_funcs';
|
|
exit;
|
|
end;
|
|
sec_term_func:
|
|
begin
|
|
result:='.section __DATA, __mod_term_func, mod_term_funcs';
|
|
exit;
|
|
end;
|
|
low(TObjCAsmSectionType)..high(TObjCAsmSectionType):
|
|
begin
|
|
result:='.section '+objc_section_name(atype);
|
|
exit
|
|
end;
|
|
end;
|
|
result := inherited sectionname(atype,aname,aorder);
|
|
end;
|
|
|
|
|
|
procedure TAppleGNUAssembler.WriteWeakSymbolRef(s: tasmsymbol);
|
|
begin
|
|
writer.AsmWriteLn(#9'.weak_reference '+s.name);
|
|
end;
|
|
|
|
procedure TAppleGNUAssembler.WriteDirectiveName(dir: TAsmDirective);
|
|
begin
|
|
case dir of
|
|
asd_weak_reference:
|
|
writer.AsmWrite('.weak_reference ');
|
|
asd_weak_definition:
|
|
writer.AsmWrite('.weak_definition ');
|
|
else
|
|
inherited;
|
|
end;
|
|
end;
|
|
|
|
|
|
{****************************************************************************}
|
|
{ a.out/GNU Assembler writer }
|
|
{****************************************************************************}
|
|
|
|
function TAoutGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
|
|
const
|
|
(* Translation table - replace unsupported section types with basic ones. *)
|
|
SecXTable: array[TAsmSectionType] of TAsmSectionType = (
|
|
sec_none,
|
|
sec_none,
|
|
sec_code,
|
|
sec_data,
|
|
sec_data (* sec_rodata *),
|
|
sec_data (* sec_rodata_norel *),
|
|
sec_bss,
|
|
sec_data (* sec_threadvar *),
|
|
{ used for wince exception handling }
|
|
sec_code (* sec_pdata *),
|
|
{ used for darwin import stubs }
|
|
sec_code (* sec_stub *),
|
|
sec_data,(* sec_data_nonlazy *)
|
|
sec_data,(* sec_data_lazy *)
|
|
sec_data,(* sec_init_func *)
|
|
sec_data,(* sec_term_func *)
|
|
{ stabs }
|
|
sec_stab,sec_stabstr,
|
|
{ win32 }
|
|
sec_data (* sec_idata2 *),
|
|
sec_data (* sec_idata4 *),
|
|
sec_data (* sec_idata5 *),
|
|
sec_data (* sec_idata6 *),
|
|
sec_data (* sec_idata7 *),
|
|
sec_data (* sec_edata *),
|
|
{ C++ exception handling unwinding (uses dwarf) }
|
|
sec_eh_frame,
|
|
{ dwarf }
|
|
sec_debug_frame,
|
|
sec_debug_info,
|
|
sec_debug_line,
|
|
sec_debug_abbrev,
|
|
{ ELF resources (+ references to stabs debug information sections) }
|
|
sec_code (* sec_fpc *),
|
|
{ Table of contents section }
|
|
sec_code (* sec_toc *),
|
|
sec_code (* sec_init *),
|
|
sec_code (* sec_fini *),
|
|
sec_none (* sec_objc_class *),
|
|
sec_none (* sec_objc_meta_class *),
|
|
sec_none (* sec_objc_cat_cls_meth *),
|
|
sec_none (* sec_objc_cat_inst_meth *),
|
|
sec_none (* sec_objc_protocol *),
|
|
sec_none (* sec_objc_string_object *),
|
|
sec_none (* sec_objc_cls_meth *),
|
|
sec_none (* sec_objc_inst_meth *),
|
|
sec_none (* sec_objc_cls_refs *),
|
|
sec_none (* sec_objc_message_refs *),
|
|
sec_none (* sec_objc_symbols *),
|
|
sec_none (* sec_objc_category *),
|
|
sec_none (* sec_objc_class_vars *),
|
|
sec_none (* sec_objc_instance_vars *),
|
|
sec_none (* sec_objc_module_info *),
|
|
sec_none (* sec_objc_class_names *),
|
|
sec_none (* sec_objc_meth_var_types *),
|
|
sec_none (* sec_objc_meth_var_names *),
|
|
sec_none (* sec_objc_selector_strs *),
|
|
sec_none (* sec_objc_protocol_ext *),
|
|
sec_none (* sec_objc_class_ext *),
|
|
sec_none (* sec_objc_property *),
|
|
sec_none (* sec_objc_image_info *),
|
|
sec_none (* sec_objc_cstring_object *),
|
|
sec_none (* sec_objc_sel_fixup *),
|
|
sec_none (* sec_objc_data *),
|
|
sec_none (* sec_objc_const *),
|
|
sec_none (* sec_objc_sup_refs *),
|
|
sec_none (* sec_data_coalesced *),
|
|
sec_none (* sec_objc_classlist *),
|
|
sec_none (* sec_objc_nlclasslist *),
|
|
sec_none (* sec_objc_catlist *),
|
|
sec_none (* sec_objc_nlcatlist *),
|
|
sec_none (* sec_objc_protlist *),
|
|
sec_none (* sec_stack *),
|
|
sec_none (* sec_heap *)
|
|
);
|
|
begin
|
|
Result := inherited SectionName (SecXTable [AType], AName, AOrder);
|
|
end;
|
|
|
|
|
|
{****************************************************************************}
|
|
{ Abstract Instruction Writer }
|
|
{****************************************************************************}
|
|
|
|
constructor TCPUInstrWriter.create(_owner: TGNUAssembler);
|
|
begin
|
|
inherited create;
|
|
owner := _owner;
|
|
end;
|
|
|
|
end.
|