{ 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} 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 WriteWeakSymbolDef(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 WriteWeakSymbolDef(s: tasmsymbol); 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; 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'.long'#9,#9'.quad'#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 ); { Alpha type of unaligned pseudo-instructions } use_ua_alpha_systems = [system_alpha_linux]; ait_ua_alpha_const2str : array[aitconst_16bit_unaligned..aitconst_64bit_unaligned] of string[20]=( #9'.uword'#9,#9'.ulong'#9,#9'.uquad'#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 := target_asm.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 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,sec_objc_data,sec_objc_const,sec_data_coalesced]) then AsmWrite('.section '); end else AsmWrite('.section '); end; s:=sectionname(atype,aname,aorder); AsmWrite(s); case atype of sec_fpc : if aname = 'resptrs' then 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 AsmWriteln('__TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32') else AsmWriteln('__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,16'); system_i386_darwin, system_i386_iphonesim: AsmWriteln('__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5'); system_arm_darwin: if (cs_create_pic in current_settings.moduleswitches) then AsmWriteln('__TEXT,__picsymbolstub4,symbol_stubs,none,16') else 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 AsmWrite(',"'+s+'"'); end else if target_info.system in systems_aix then begin s:=sectionalignment_aix(atype,secalign); if s<>'' then AsmWrite(','+s); end; end; 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 AsmWrite(','); 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 AsmWrite(','); 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'; AsmWrite(#9'.balignw '+tostr(alignment)+','+instr); end else begin {$endif m68k} AsmWrite(#9'.balign '+tostr(alignment)); if use_op then AsmWrite(','+tostr(fillop)) {$ifdef x86} { force NOP as alignment op code } else if LastSecType=sec_code then 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); AsmWrite(#9'.align '+tostr(i)); last_align:=i; end; AsmLn; end; end; var ch : char; lasthp, hp : tai; constdef : taiconst_type; s,t : string; i,pos,l : longint; InlineLevel : cardinal; last_align : longint; co : comp; sin : single; d : double; {$ifdef cpuextended} e : extended; {$endif cpuextended} do_line : boolean; sepChar : char; replaceforbidden: boolean; begin if not assigned(p) then exit; replaceforbidden:=target_asm.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 AsmWrite(target_asm.comment); AsmWritePChar(tai_comment(hp).str); AsmLn; End; ait_regalloc : begin if (cs_asm_regalloc in current_settings.globalswitches) then begin AsmWrite(#9+target_asm.comment+'Register '); repeat 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); AsmWrite(','); until false; AsmWrite(' '); 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} AsmWrite(target_asm.comment); 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 asmwrite('.globl '); asmwriteln(tai_datablock(hp).sym.name); asmwriteln('.data'); asmwrite('.zerofill __DATA, __common, '); asmwrite(tai_datablock(hp).sym.name); 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 asmwrite(#9'.lcomm'#9); asmwrite(tai_datablock(hp).sym.name); asmwrite(','+tostr(tai_datablock(hp).size)); asmwrite(','+tostr(last_align)); asmln; end; end else if target_info.system in systems_aix then begin if tai_datablock(hp).is_global then begin asmwrite(#9'.globl '); asmwriteln(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)); asmwrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)); asmwriteln(':'); asmwrite(#9'.space '); 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 asmwrite(#9'.lcomm '); asmwrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)); asmwrite(','); asmwrite(tostr(tai_datablock(hp).size)+','); asmwrite('_data.bss_,'); 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 asmwrite(#9'.comm'#9); if replaceforbidden then asmwrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)) else asmwrite(tai_datablock(hp).sym.name); asmwrite(','+tostr(tai_datablock(hp).size)); asmwrite(','+tostr(last_align)); asmln; end else begin asmwrite(#9'.lcomm'#9); if replaceforbidden then asmwrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)); else asmwrite(tai_datablock(hp).sym.name); asmwrite(','+tostr(tai_datablock(hp).size)); asmwrite(','+tostr(last_align)); asmln; end end else {$endif USE_COMM_IN_BSS} begin if Tai_datablock(hp).is_global then begin asmwrite(#9'.globl '); if replaceforbidden then asmwriteln(ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name)) else 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 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 asmwriteln(#9'.size '+ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name)+','+tostr(Tai_datablock(hp).size)); asmwrite(ReplaceForbiddenAsmSymbolChars(Tai_datablock(hp).sym.name)) end else begin if (tf_needs_symbol_type in target_info.flags) then 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 asmwriteln(#9'.size '+Tai_datablock(hp).sym.name+','+tostr(Tai_datablock(hp).size)); asmwrite(Tai_datablock(hp).sym.name); end; asmwriteln(':'); 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 AsmWrite(ait_const2str[aitconst_32bit]); if target_info.endian = endian_little then begin AsmWrite(tostr(longint(lo(tai_const(hp).value)))); AsmWrite(','); AsmWrite(tostr(longint(hi(tai_const(hp).value)))); end else begin AsmWrite(tostr(longint(hi(tai_const(hp).value)))); AsmWrite(','); AsmWrite(tostr(longint(lo(tai_const(hp).value)))); end; end else WriteAixIntConst(tai_const(hp)); AsmLn; end; {$endif cpu64bitaddr} aitconst_got: begin AsmWrite(#9'.word'#9+tai_const(hp).sym.name+'(GOT)'); 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 AsmWrite(#9'.gpword'#9); AsmWrite(tai_const(hp).sym.name); end; cpu_i386: begin AsmWrite(ait_const2str[aitconst_32bit]); AsmWrite(tai_const(hp).sym.name); end; else InternalError(2014022602); end; if (tai_const(hp).value<>0) then AsmWrite(tostr_with_plus(tai_const(hp).value)); 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_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 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 AsmWrite(ait_ua_sparc_const2str[constdef]) else if (constdef in ait_unaligned_consts) and (target_info.system in use_ua_alpha_systems) then AsmWrite(ait_ua_alpha_const2str[constdef]) else if (constdef in ait_unaligned_consts) and (target_info.system in use_ua_elf_systems) then 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 AsmWrite(#9'.vbyte'#9+tostr(tai_const(hp).size)+',') else 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'; 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); AsmWrite(','); until false; if (t <> '') then begin AsmLn; AsmWrite(t); end; end; 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 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; AsmWrite(s); inc(pos,length(s)); if (pos>line_length) or (i=tai_string(hp).len) then begin 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 AsmWrite(#9'.private_extern '); 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 AsmWriteln(#9'.thumb_func'#9); {$endif arm} AsmWrite('.globl'#9); if replaceforbidden then AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name)) else AsmWriteLn(tai_label(hp).labsym.name); end; if replaceforbidden then AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_label(hp).labsym.name)) else AsmWrite(tai_label(hp).labsym.name); AsmWriteLn(':'); end; end; ait_symbol : begin if (tai_symbol(hp).sym.bind=AB_PRIVATE_EXTERN) then begin AsmWrite(#9'.private_extern '); if replaceforbidden then AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)) else 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 AsmWriteLn('.globl _mcount'); if tai_symbol(hp).is_global then begin AsmWrite('.globl'#9); if replaceforbidden then AsmWriteln(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)) else 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 AsmWriteLn('.section ".opd", "aw"'); AsmWriteLn('.align 3'); AsmWriteLn(tai_symbol(hp).sym.name + ':'); AsmWriteLn('.quad .' + tai_symbol(hp).sym.name + ', .TOC.@tocbase, 0'); AsmWriteLn('.previous'); AsmWriteLn('.size ' + tai_symbol(hp).sym.name + ', 24'); if (tai_symbol(hp).is_global) then AsmWriteLn('.globl .' + tai_symbol(hp).sym.name); AsmWriteLn('.type .' + tai_symbol(hp).sym.name + ', @function'); { the dotted name is the name of the actual function entry } 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; AsmWriteLn(#9'.csect '+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+'[DS],'+ch); AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+':'); AsmWriteln(s+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+', TOC[tc0], 0'); AsmWriteln(#9'.csect .text[PR]'); if (tai_symbol(hp).is_global) then AsmWriteLn('.globl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)) else AsmWriteLn('.lglobl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)); { the dotted name is the name of the actual function entry } 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 AsmWrite(#9'.type'#9 + tai_symbol(hp).sym.name); if (needsObject(tai_symbol(hp))) then AsmWriteLn(',' + sepChar + 'object') else AsmWriteLn(',' + sepChar + 'function'); end; end; if replaceforbidden then if not(tai_symbol(hp).has_value) then AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name + ':')) else AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name + '=' + tostr(tai_symbol(hp).value))) else if not(tai_symbol(hp).has_value) then AsmWriteLn(tai_symbol(hp).sym.name + ':') else AsmWriteLn(tai_symbol(hp).sym.name + '=' + tostr(tai_symbol(hp).value)); end; ait_symbolpair: begin AsmWrite(#9); AsmWrite(symbolpairkindstr[tai_symbolpair(hp).kind]); 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 } AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).sym^)+s); AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbolpair(hp).value^)); end else begin { avoid string truncation } AsmWrite(tai_symbolpair(hp).sym^+s); AsmWriteLn(tai_symbolpair(hp).value^); end; end; ait_weak: begin if replaceforbidden then AsmWriteLn(#9'.weak '+ReplaceForbiddenAsmSymbolChars(tai_weak(hp).sym^)) else AsmWriteLn(#9'.weak '+tai_weak(hp).sym^); end; ait_symbol_end : begin if tf_needs_symbol_size in target_info.flags then begin s:=target_asm.labelprefix+'e'+tostr(symendcount); inc(symendcount); AsmWriteLn(s+':'); 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 AsmWrite('.'); if replaceforbidden then AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name)) else AsmWrite(tai_symbol_end(hp).sym.name); AsmWrite(', '+s+' - '); if (target_info.system=system_powerpc64_linux) and use_dotted_functions and (tai_symbol_end(hp).sym.typ=AT_FUNCTION) then AsmWrite('.'); if replaceforbidden then AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol_end(hp).sym.name)) else 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 AsmWrite(#9'.'+stabtypestr[tai_stab(hp).stabtype]+' '); AsmWritePChar(tai_stab(hp).str); AsmLn; end; end; 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 AsmClose; DoAssemble; 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); 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 WriteDirectiveName(tai_directive(hp).directive); if tai_directive(hp).name <>'' then begin if replaceforbidden then AsmWrite(ReplaceForbiddenAsmSymbolChars(tai_directive(hp).name)) else AsmWrite(tai_directive(hp).name); end; AsmLn; end; ait_seh_directive : begin {$ifndef DISABLE_WIN64_SEH} AsmWrite(sehdirectivestr[tai_seh_directive(hp).kind]); case tai_seh_directive(hp).datatype of sd_none:; sd_string: begin AsmWrite(' '+tai_seh_directive(hp).data.name^); if (tai_seh_directive(hp).data.flags and 1)<>0 then AsmWrite(',@except'); if (tai_seh_directive(hp).data.flags and 2)<>0 then AsmWrite(',@unwind'); end; sd_reg: AsmWrite(' '+gas_regname(tai_seh_directive(hp).data.reg)); sd_offset: AsmWrite(' '+tostr(tai_seh_directive(hp).data.offset)); sd_regoffset: AsmWrite(' '+gas_regname(tai_seh_directive(hp).data.reg)+', '+ tostr(tai_seh_directive(hp).data.offset)); end; AsmLn; {$endif DISABLE_WIN64_SEH} end; ait_varloc: begin if tai_varloc(hp).newlocationhi<>NR_NO then AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+ std_regname(tai_varloc(hp).newlocationhi)+':'+std_regname(tai_varloc(hp).newlocation))) else AsmWrite(strpnew('Var '+tai_varloc(hp).varsym.realname+' located in register '+ std_regname(tai_varloc(hp).newlocation))); 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.WriteWeakSymbolDef(s: tasmsymbol); begin 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: AsmWriteLn('"'); term_nostring: AsmLn; end; 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; AsmWrite(s); inc(pos,length(s)); if (pos>line_length) or (i=tai_string(hp).len) then begin if instring then AsmWriteLn('"') else 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 AsmWrite(#9'.vbyte'#9'4, '); AsmWriteln(tostr(longint(tai_const(hp).value shr ((size-pos-4)*8)))); inc(pos,4); end; AsmWrite(#9'.vbyte'#9); AsmWrite(tostr(size-pos)); AsmWrite(', '); case size-pos of 1: AsmWrite(tostr(byte(tai_const(hp).value))); 2: AsmWrite(tostr(word(tai_const(hp).value))); 4: 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; AsmWrite(#9'.byte'#9); if target_info.endian=endian_big then begin pos:=size-1; while pos>=0 do begin AsmWrite(tostr((tai_const(hp).value shr (pos*8)) and $ff)); dec(pos); if pos>=0 then AsmWrite(', ') else AsmLn; end; end else begin pos:=0; while pos'' 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 AsmWriteLn(#9'.file "'+FixFileName(n)+'"'); WriteExtraHeader; AsmStartSize:=AsmSize; symendcount:=0; 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; { 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 writeweaksymboldef(tasmsymbol(current_asmdata.asmsymboldict[i])); if create_smartlink_sections and (target_info.system in systems_darwin) then 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 AsmWriteLn('.section .note.GNU-stack,"",%progbits'); end; 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_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; sec_objc_protocol_ext: begin result:='.section __OBJC, __protocol_ext, regular, no_dead_strip'; exit; end; sec_objc_class_ext: begin result:='.section __OBJC, __class_ext, regular, no_dead_strip'; exit; end; sec_objc_property: begin result:='.section __OBJC, __property, regular, no_dead_strip'; exit; end; sec_objc_image_info: begin if (target_info.system in systems_objc_nfabi) then result:='.section __DATA,__objc_imageinfo,regular,no_dead_strip' else result:='.section __OBJC, __image_info, regular, no_dead_strip'; exit; end; sec_objc_cstring_object: begin result:='.section __OBJC, __cstring_object, regular, no_dead_strip'; exit; end; sec_objc_sel_fixup: begin result:='.section __OBJC, __sel_fixup, regular, no_dead_strip'; exit; end; sec_objc_message_refs: begin if (target_info.system in systems_objc_nfabi) then begin result:='.section __DATA, __objc_selrefs, literal_pointers, no_dead_strip'; exit; end; end; sec_objc_cls_refs: begin if (target_info.system in systems_objc_nfabi) then begin result:='.section __DATA, __objc_clsrefs, regular, no_dead_strip'; exit; end; end; sec_objc_meth_var_types: begin if (target_info.system in systems_objc_nfabi) then begin result:='.section __TEXT,__objc_methtype,cstring_literals'; exit end; end; sec_objc_meth_var_names: begin if (target_info.system in systems_objc_nfabi) then begin result:='.section __TEXT,__objc_methname,cstring_literals'; exit end; end; sec_objc_class_names: begin if (target_info.system in systems_objc_nfabi) then begin result:='.section __TEXT,__objc_classname,cstring_literals'; exit end; end; sec_objc_inst_meth, sec_objc_cls_meth, sec_objc_cat_inst_meth, sec_objc_cat_cls_meth: begin if (target_info.system in systems_objc_nfabi) then begin result:='.section __DATA, __objc_const'; exit; end; end; sec_objc_meta_class, sec_objc_class: begin if (target_info.system in systems_objc_nfabi) then begin result:='.section __DATA, __objc_data'; exit; end; end; sec_objc_sup_refs: begin result:='.section __DATA, __objc_superrefs, regular, no_dead_strip'; exit end; sec_objc_classlist: begin result:='.section __DATA, __objc_classlist, regular, no_dead_strip'; exit end; sec_objc_nlclasslist: begin result:='.section __DATA, __objc_nlclasslist, regular, no_dead_strip'; exit end; sec_objc_catlist: begin result:='.section __DATA, __objc_catlist, regular, no_dead_strip'; exit end; sec_objc_nlcatlist: begin result:='.section __DATA, __objc_nlcatlist, regular, no_dead_strip'; exit end; sec_objc_protolist: begin result:='.section __DATA, __objc_protolist, coalesced, no_dead_strip'; exit; end; end; result := inherited sectionname(atype,aname,aorder); end; procedure TAppleGNUAssembler.WriteWeakSymbolDef(s: tasmsymbol); begin AsmWriteLn(#9'.weak_reference '+s.name); 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.