fpc/compiler/x86_64/rax64att.pas

243 lines
8.1 KiB
ObjectPascal

{
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);
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 and 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.