{ Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman Does the parsing for the i386 GNU AS styled inline assembler. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **************************************************************************** } Unit rax64att; {$i fpcdefs.inc} interface uses raatt,rax86att,aasmtai; type tx8664attreader = class(tx86attreader) actsehdirective: TAsmSehDirective; procedure handleopcode;override; function is_targetdirective(const s:string):boolean;override; procedure handletargetdirective;override; end; implementation uses cutils,globtype,rabase,systems,rax86,aasmcpu,cgbase,procinfo,symconst,verbose; procedure tx8664attreader.handleopcode; var instr : Tx86Instruction; begin instr:=Tx86attInstruction.Create(Tx86Operand); instr.OpOrder:=op_att; BuildOpcode(instr); instr.AddReferenceSizes; instr.SetInstructionOpsize; instr.CheckOperandSizes; instr.FixupOpcode; instr.ConcatInstruction(curlist); instr.Free; end; const { x86_64 subset of SEH directives. .seh_proc and .seh_endproc excluded because they are generated automatically when needed. } recognized_directives: set of TAsmSehDirective=[ ash_endprologue,ash_handler,ash_handlerdata, ash_setframe,ash_stackalloc,ash_pushreg, ash_savereg,ash_savexmm,ash_pushframe ]; { max offset and bitmask for .seh_savereg and .seh_setframe } maxoffset: array[boolean] of aint=(high(dword), 240); modulo: array[boolean] of integer=(7, 15); function tx8664attreader.is_targetdirective(const s:string):boolean; var i: TAsmSehDirective; begin result:=false; if target_info.system<>system_x86_64_win64 then exit; for i:=low(TAsmSehDirective) to high(TAsmSehDirective) do begin if not (i in recognized_directives) then continue; if s=sehdirectivestr[i] then begin actsehdirective:=i; result:=true; break; end; end; { allow SEH directives only in pure assember routines } if result and not (po_assembler in current_procinfo.procdef.procoptions) then begin Message(asmr_e_seh_in_pure_asm_only); result:=false; end; end; procedure tx8664attreader.handletargetdirective; var hreg: TRegister; hnum: aint; flags: integer; ai: tai_seh_directive; hs: string; err: boolean; begin if actasmtoken<>AS_TARGET_DIRECTIVE then InternalError(2011100201); Consume(AS_TARGET_DIRECTIVE); Include(current_procinfo.flags,pi_has_unwind_info); case actsehdirective of { TODO: .seh_pushframe is supposed to have a boolean parameter, but GAS 2.21 does not support it. } ash_endprologue, ash_pushframe, ash_handlerdata: curlist.concat(cai_seh_directive.create(actsehdirective)); ash_handler: begin hs:=actasmpattern; Consume(AS_ID); flags:=0; err:=false; while actasmtoken=AS_COMMA do begin Consume(AS_COMMA); if actasmtoken=AS_AT then begin Consume(AS_AT); if actasmtoken=AS_ID then begin uppervar(actasmpattern); if actasmpattern='EXCEPT' then flags:=flags or 1 else if actasmpattern='UNWIND' then flags:=flags or 2 else err:=true; Consume(AS_ID); end else err:=true; end else err:=true; if err then begin Message(asmr_e_syntax_error); RecoverConsume(false); exit; end; end; ai:=cai_seh_directive.create_name(ash_handler,hs); ai.data.flags:=flags; curlist.concat(ai); end; ash_stackalloc: begin hnum:=BuildConstExpression(false,false); if (hnum<0) or (hnum>high(dword)) or ((hnum and 7)<>0) then Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[ash_stackalloc]) else curlist.concat(cai_seh_directive.create_offset(ash_stackalloc,hnum)); end; ash_pushreg: begin hreg:=actasmregister; Consume(AS_REGISTER); if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBQ) then Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[ash_pushreg]) else curlist.concat(cai_seh_directive.create_reg(ash_pushreg,hreg)); end; ash_setframe, ash_savereg: begin hreg:=actasmregister; Consume(AS_REGISTER); if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBQ) then Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]); Consume(AS_COMMA); hnum:=BuildConstExpression(false,false); if (hnum<0) or (hnum>maxoffset[actsehdirective=ash_setframe]) or ((hnum mod modulo[actsehdirective=ash_setframe])<>0) then Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[actsehdirective]) else curlist.concat(cai_seh_directive.create_reg_offset(actsehdirective,hreg,hnum)); end; ash_savexmm: begin hreg:=actasmregister; Consume(AS_REGISTER); if (getregtype(hreg)<>R_MMREGISTER) then Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[ash_savexmm]); Consume(AS_COMMA); hnum:=BuildConstExpression(false,false); if (hnum<0) or (hnum>high(dword)) or ((hnum and 15)<>0) then Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[ash_savexmm]) else curlist.concat(cai_seh_directive.create_reg_offset(actsehdirective,hreg,hnum)); end; else InternalError(2011100202); end; if actasmtoken<>AS_SEPARATOR then Consume(AS_SEPARATOR); end; const asmmode_x86_64_gas_info : tasmmodeinfo = ( id : asmmode_x86_64_gas; idtxt : 'GAS'; casmreader : tx8664attreader; ); { Added to be compatible with i386 } asmmode_x86_64_att_info : tasmmodeinfo = ( id : asmmode_x86_64_att; idtxt : 'ATT'; casmreader : tx8664attreader; ); asmmode_x86_64_standard_info : tasmmodeinfo = ( id : asmmode_standard; idtxt : 'STANDARD'; casmreader : tx8664attreader; ); initialization RegisterAsmMode(asmmode_x86_64_gas_info); RegisterAsmMode(asmmode_x86_64_att_info); RegisterAsmMode(asmmode_x86_64_standard_info); end.