{ 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 cclasses, globtype,globals, aasmbase,aasmtai,aasmdata,aasmcpu, assemble; type TCPUInstrWriter = class; {# This is a derived class which is used to write GAS styled assembler. } TGNUAssembler=class(texternalassembler) protected function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;virtual; procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder); procedure WriteExtraHeader;virtual; procedure WriteInstruction(hp: tai); 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 overriden 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=class(TGNUAssembler) function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override; private debugframecount: aint; end; TAoutGNUAssembler=class(TGNUAssembler) function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override; end; implementation uses SysUtils, cutils,cfileutl,systems, fmodule,finput,verbose, itcpugas,cpubase ; const line_length = 70; var symendcount : longint; type {$ifdef cpuextended} t80bitarray = array[0..9] of byte; {$endif cpuextended} t64bitarray = array[0..7] of byte; t32bitarray = array[0..3] of byte; {****************************************************************************} { Support routines } {****************************************************************************} function fixline(s:string):string; { return s with all leading and ending spaces and tabs removed } var i,j,k : integer; begin i:=length(s); while (i>0) and (s[i] in [#9,' ']) do dec(i); j:=1; while (j'') and (atype <> sec_toc) and (atype<>sec_bss) 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; procedure TGNUAssembler.WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder); 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_m68k_linux: ; system_powerpc_darwin, system_i386_darwin, system_powerpc64_darwin, system_x86_64_darwin: begin if (atype = sec_stub) 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: AsmWriteln('__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5'); { darwin/x86-64 uses RIP-based GOT addressing } else internalerror(2006031101); end; 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_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit]) ) or (hp.sym.typ=AT_DATA); end; var ch : char; hp : tai; hp1 : tailineinfo; constdef : taiconst_type; s,t : string; i,pos,l : longint; InlineLevel : longint; last_align : longint; co : comp; sin : single; d : double; {$ifdef cpuextended} e : extended; {$endif cpuextended} do_line : boolean; sepChar : char; begin if not assigned(p) then exit; 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])); hp:=tai(p.first); while assigned(hp) do begin if not(hp.typ in SkipLineInfo) then begin hp1 := hp as tailineinfo; current_filepos:=hp1.fileinfo; { no line info for inlined code } if do_line and (inlinelevel=0) then begin { load infile } if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then begin infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex); if assigned(infile) then begin { open only if needed !! } if (cs_asm_source in current_settings.globalswitches) then infile.open; end; { avoid unnecessary reopens of the same file !! } lastfileinfo.fileindex:=hp1.fileinfo.fileindex; { be sure to change line !! } lastfileinfo.line:=-1; end; { write source } if (cs_asm_source in current_settings.globalswitches) and assigned(infile) then begin if (infile<>lastinfile) then begin AsmWriteLn(target_asm.comment+'['+infile.name^+']'); if assigned(lastinfile) then lastinfile.close; end; if (hp1.fileinfo.line<>lastfileinfo.line) and ((hp1.fileinfo.line0)) then begin if (hp1.fileinfo.line<>0) and ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+ fixline(infile.GetLineStr(hp1.fileinfo.line))); { set it to a negative value ! to make that is has been read already !! PM } if (infile.linebuf^[hp1.fileinfo.line]>=0) then infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1; end; end; lastfileinfo:=hp1.fileinfo; lastinfile:=infile; end; 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 begin {$ifdef EXTDEBUG} if assigned(tai_tempalloc(hp).problem) then AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+ tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^) else {$endif EXTDEBUG} AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+ tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]); end; end; ait_align : begin last_align := tai_align_abstract(hp).aligntype; if tai_align_abstract(hp).aligntype>1 then begin if not(target_info.system in systems_darwin) then begin AsmWrite(#9'.balign '+tostr(tai_align_abstract(hp).aligntype)); if tai_align_abstract(hp).use_op then AsmWrite(','+tostr(tai_align_abstract(hp).fillop)) {$ifdef x86} { force NOP as alignment op code } else if LastSecType=sec_code then AsmWrite(',0x90'); {$endif x86} end else begin { darwin as only supports .align } if not ispowerof2(tai_align_abstract(hp).aligntype,i) then internalerror(2003010305); AsmWrite(#9'.align '+tostr(i)); last_align := i; end; AsmLn; end; end; ait_section : begin if tai_section(hp).sectype<>sec_none then WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secorder) 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); 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 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); asmwrite(tai_datablock(hp).sym.name); asmwrite(','+tostr(tai_datablock(hp).size)); asmwrite(','+tostr(last_align)); asmln; 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 {$endif USE_COMM_IN_BSS} begin if Tai_datablock(hp).is_global then begin asmwrite(#9'.globl '); asmwriteln(Tai_datablock(hp).sym.name); end; if (target_info.system <> system_arm_linux) then sepChar := '@' else sepChar := '%'; 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); 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); 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; AsmLn; end; {$endif cpu64bitaddr} 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_indirect_symbol, aitconst_darwin_dwarf_delta32, aitconst_darwin_dwarf_delta64: begin 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 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 tai_const(hp).value<>0 then s:=s+tostr_with_plus(tai_const(hp).value); end else s:=tostr(tai_const(hp).value); AsmWrite(s); inc(l,length(s)); { 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; { the "and defined(FPC_HAS_TYPE_EXTENDED)" isn't optimal but currently the only solution it prevents proper cross compilation to i386 though } {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)} ait_real_80bit : begin if do_line then AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_real_80bit(hp).value)); { Make sure e is a extended type, bestreal could be a different type (bestreal) !! (PFV) } e:=tai_real_80bit(hp).value; AsmWrite(#9'.byte'#9); for i:=0 to 9 do begin if i<>0 then AsmWrite(','); AsmWrite(tostr(t80bitarray(e)[i])); end; AsmLn; end; {$endif cpuextended} ait_real_64bit : begin if do_line then AsmWriteLn(target_asm.comment+'value: '+double2str(tai_real_64bit(hp).value)); d:=tai_real_64bit(hp).value; { swap the values to correct endian if required } if source_info.endian <> target_info.endian then swap64bitarray(t64bitarray(d)); AsmWrite(#9'.byte'#9); {$ifdef arm} if tai_real_64bit(hp).formatoptions=fo_hiloswapped then begin for i:=4 to 7 do begin if i<>4 then AsmWrite(','); AsmWrite(tostr(t64bitarray(d)[i])); end; for i:=0 to 3 do begin AsmWrite(','); AsmWrite(tostr(t64bitarray(d)[i])); end; end else {$endif arm} begin for i:=0 to 7 do begin if i<>0 then AsmWrite(','); AsmWrite(tostr(t64bitarray(d)[i])); end; end; AsmLn; end; ait_real_32bit : begin if do_line then AsmWriteLn(target_asm.comment+'value: '+single2str(tai_real_32bit(hp).value)); sin:=tai_real_32bit(hp).value; { swap the values to correct endian if required } if source_info.endian <> target_info.endian then swap32bitarray(t32bitarray(sin)); AsmWrite(#9'.byte'#9); for i:=0 to 3 do begin if i<>0 then AsmWrite(','); AsmWrite(tostr(t32bitarray(sin)[i])); end; AsmLn; end; ait_comp_64bit : begin if do_line then AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_comp_64bit(hp).value)); AsmWrite(#9'.byte'#9); co:=comp(tai_comp_64bit(hp).value); { swap the values to correct endian if required } if source_info.endian <> target_info.endian then swap64bitarray(t64bitarray(co)); for i:=0 to 7 do begin if i<>0 then AsmWrite(','); AsmWrite(tostr(t64bitarray(co)[i])); end; AsmLn; end; ait_string : begin pos:=0; 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; ait_label : begin if (tai_label(hp).labsym.is_used) then begin if tai_label(hp).labsym.bind=AB_GLOBAL then begin AsmWrite('.globl'#9); AsmWriteLn(tai_label(hp).labsym.name); end; AsmWrite(tai_label(hp).labsym.name); AsmWriteLn(':'); end; end; ait_symbol : begin if (target_info.system = system_powerpc64_linux) and (tai_symbol(hp).sym.typ = AT_FUNCTION) and (cs_profile in current_settings.moduleswitches) then begin AsmWriteLn('.globl _mcount'); end; if tai_symbol(hp).is_global then begin AsmWrite('.globl'#9); AsmWriteLn(tai_symbol(hp).sym.name); end; if (target_info.system = system_powerpc64_linux) 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 begin if (target_info.system <> system_arm_linux) 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; AsmWriteLn(tai_symbol(hp).sym.name + ':'); 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 (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then AsmWrite('.'); AsmWrite(tai_symbol_end(hp).sym.name); AsmWrite(', '+s+' - '); if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then AsmWrite('.'); 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); AsmStartSize:=AsmSize; end; end; ait_marker : if tai_marker(hp).kind=mark_InlineStart then inc(InlineLevel) else if tai_marker(hp).kind=mark_InlineEnd then dec(InlineLevel); ait_directive : begin AsmWrite('.'+directivestr[tai_directive(hp).directive]+' '); if assigned(tai_directive(hp).name) then AsmWrite(tai_directive(hp).name^); AsmLn; end; else internalerror(2006012201); end; hp:=tai(hp.next); end; end; procedure TGNUAssembler.WriteExtraHeader; begin end; procedure TGNUAssembler.WriteInstruction(hp: tai); begin InstrWriter.WriteInstruction(hp); end; procedure TGNUAssembler.WriteAsmList; var n : string; hal : tasmlisttype; begin {$ifdef EXTDEBUG} if assigned(current_module.mainsource) then Comment(V_Debug,'Start writing gas-styled assembler output for '+current_module.mainsource^); {$endif} if assigned(current_module.mainsource) then n:=ExtractFileName(current_module.mainsource^) else n:=InputFileName; AsmWriteLn(#9'.file "'+FixFileName(n)+'"'); WriteExtraHeader; AsmStartSize:=AsmSize; symendcount:=0; for hal:=low(TasmlistType) to high(TasmlistType) do begin AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]); writetree(current_asmdata.asmlists[hal]); AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]); end; if create_smartlink_sections and (target_info.system in systems_darwin) then AsmWriteLn(#9'.subsections_via_symbols'); AsmLn; {$ifdef EXTDEBUG} if assigned(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 __DWARFA,__debug_frame,coalesced,no_toc+strip_static_syms'#10'EH_frame'+tostr(debugframecount)+':'; inc(debugframecount); 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; end; result := inherited sectionname(atype,aname,aorder); 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_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 *), { 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 *) ); begin Result := inherited SectionName (SecXTable [AType], AName, AOrder); end; {****************************************************************************} { Abstract Instruction Writer } {****************************************************************************} constructor TCPUInstrWriter.create(_owner: TGNUAssembler); begin inherited create; owner := _owner; end; end.