mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 15:47:54 +02:00
243 lines
8.1 KiB
ObjectPascal
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.
|