* factored out check to determine whether a variable can be subscripted in

inline assembly, and fixed check after r35959 (mantis )
   o can also subscript parameters passed by value on the stack
   o can also subscript local variables, the parameters passed by reference
     that are subsequently copied into a local

git-svn-id: trunk@37886 -
This commit is contained in:
Jonas Maebe 2018-01-01 14:29:21 +00:00
parent dcac6b9c6f
commit 1b66995754
15 changed files with 363 additions and 294 deletions

1
.gitattributes vendored
View File

@ -15907,6 +15907,7 @@ tests/webtbs/tw3222.pp svneol=native#text/plain
tests/webtbs/tw3226.pp svneol=native#text/plain
tests/webtbs/tw3227.pp svneol=native#text/plain
tests/webtbs/tw3227a.pp svneol=native#text/plain
tests/webtbs/tw32318.pp svneol=native#text/plain
tests/webtbs/tw3235.pp svneol=native#text/plain
tests/webtbs/tw3235a.pp svneol=native#text/plain
tests/webtbs/tw3241a.pp svneol=native#text/plain

View File

@ -607,13 +607,8 @@ Unit racpugas;
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs,l)
end;
OPR_CONSTANT :

View File

@ -634,13 +634,8 @@ Unit raarmgas;
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs,l)
end;
OPR_CONSTANT :

View File

@ -256,13 +256,8 @@ Unit raavrgas;
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs,l)
end;
OPR_CONSTANT :

View File

@ -167,13 +167,8 @@ Interface
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs,l)
end;
OPR_CONSTANT :

View File

@ -2652,7 +2652,7 @@ asmr_w_32bit_const_for_address=07079_W_32bit constant created for address
asmr_n_align_is_target_specific=07080_N_.align is target specific, use .balign or .p2align
% Using the .align directive is platform specific, and its meaning will vary
% from one platform to another.
asmr_e_cannot_access_field_directly_for_parameters=07081_E_Can't access fields directly for parameters
asmr_e_cannot_access_field_directly_for_parameters=07081_E_Cannot directly access fields of pointer-based parameters
% You should load the parameter first into a register and then access the
% fields using that register.
asmr_e_cannot_access_object_field_directly=07082_E_Can't access fields of objects/classes directly

View File

@ -1091,7 +1091,7 @@ const
option_info=11024;
option_help_pages=11025;
MsgTxtSize = 81026;
MsgTxtSize = 81040;
MsgIdxMax : array[1..20] of longint=(
27,105,347,124,96,58,139,33,221,67,

File diff suppressed because it is too large Load Diff

View File

@ -339,13 +339,8 @@ Unit rappcgas;
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs,l)
end;
OPR_CONSTANT :

View File

@ -349,13 +349,8 @@ var
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs, l)
end;
OPR_CONSTANT:

View File

@ -27,6 +27,7 @@ unit rasm;
uses
cclasses,
symsym,
rabase,
aasmbase,
aasmdata,
@ -49,12 +50,21 @@ unit rasm;
destructor destroy;override;
function createlocallabel(const s: string; var hl: tasmlabel; emit: boolean): boolean;
procedure checklocallabels;
protected
{ allow subscripting a local if it is a:
1) pointer to a records/object, or a class instance pointer, passed in a register to a pure assembler routine
2) record located on the stack (passed as parameter, or local variable)
}
procedure checklocalsubscript(sym: tabstractnormalvarsym); virtual;
end;
implementation
uses
verbose;
verbose,
procinfo,
symconst,symdef,
paramgr;
type
TLocalLabel = class(TFPHashObject)
@ -129,4 +139,52 @@ unit rasm;
locallabels.Clear;
end;
procedure tasmreader.checklocalsubscript(sym: tabstractnormalvarsym);
var
isimplicitpointer: boolean;
begin
isimplicitpointer:=
(sym.typ=paravarsym) and
(is_implicit_pointer_object_type(sym.vardef) or
paramanager.push_addr_param(sym.varspez,sym.vardef,current_procinfo.procdef.proccalloption));
{ sym.initiallloc/localloc is not yet initialised here }
{ pointer parameter to aggregate passed in register to pure assembler routine }
if (po_assembler in current_procinfo.procdef.procoptions) and
(sym.typ=paravarsym) and
(tparavarsym(sym).paraloc[calleeside].location^.loc=LOC_REGISTER) and
isimplicitpointer then
exit;
{ aggregate parameter passed on the stack to a pure assembler routine }
if (po_assembler in current_procinfo.procdef.procoptions) and
(sym.typ=paravarsym) and
{ sym.localloc is not yet initialised here for pure assembler routines }
(tparavarsym(sym).paraloc[calleeside].location^.loc in [LOC_REFERENCE,LOC_CREFERENCE]) and
not isimplicitpointer then
exit;
{ aggregate parameter located on the stack for a non-assembler routine
(locals accessed from assembler code are never kept in registers) }
if not(po_assembler in current_procinfo.procdef.procoptions) and
(sym.typ=paravarsym) and
not isimplicitpointer then
exit;
{ local aggregate located on the stack (locals accessed from assembler
code are never kept in registers) }
if ((sym.typ=localvarsym) or
{ even if a parameter is passed by reference, it will be copied to
a local if it's a value parameter to a non assembler routines }
(not(po_assembler in current_procinfo.procdef.procoptions) and
(sym.typ=paravarsym) and
(sym.varspez=vs_value))) and
not is_implicit_pointer_object_type(sym.vardef) then
exit;
Message(asmr_e_cannot_access_field_directly_for_parameters);
end;
end.

View File

@ -226,13 +226,8 @@ Interface
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs,l)
end;
OPR_CONSTANT :

View File

@ -459,13 +459,8 @@ Implementation
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting }
if hasdot and
(not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
(not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
inc(oper.opr.localsymofs,l);
inc(oper.opr.localconstoffset,l);
end;

View File

@ -1733,13 +1733,8 @@ Unit Rax86int;
{ don't allow direct access to fields of parameters, because that
will generate buggy code. Allow it only for explicit typecasting
and when the parameter is in a register (delphi compatible) }
if (not oper.hastype) and
(oper.opr.localsym.typ=paravarsym) and
(not(po_assembler in current_procinfo.procdef.procoptions) or
(tparavarsym(oper.opr.localsym).paraloc[calleeside].location^.loc<>LOC_REGISTER) or
(not is_implicit_pointer_object_type(oper.opr.localsym.vardef) and
not paramanager.push_addr_param(oper.opr.localsym.varspez,oper.opr.localsym.vardef,current_procinfo.procdef.proccalloption))) then
Message(asmr_e_cannot_access_field_directly_for_parameters);
if (not oper.hastype) then
checklocalsubscript(oper.opr.localsym);
oper.opr.localforceref:=true;
inc(oper.opr.localsymofs,toffset);

54
tests/webtbs/tw32318.pp Normal file
View File

@ -0,0 +1,54 @@
{ %cpu=i386}
{$ifdef fpc}
{$mode delphi}
{$endif fpc}
function MakeProcInstanceData(M: TMethod): Pointer;
begin
asm
MOV EAX, M.Data
MOV @RESULT, EAX
end;
end;
function MakeProcInstanceCode(M: TMethod): Pointer;
begin
asm
MOV EAX, M.Code
MOV @RESULT, EAX
end;
end;
function MakeProcInstanceDataAsm(M: TMethod): Pointer; assembler;
asm
MOV EAX, M.Data
MOV @RESULT, EAX
end;
function MakeProcInstanceCodeAsm(M: TMethod): Pointer; assembler;
asm
MOV EAX, M.Code
MOV @RESULT, EAX
end;
var
m: tmethod;
begin
m.code:=pointer(1);
m.data:=pointer(2);
if MAkeProcInstanceData(M)<>pointer(2) then
halt(1);
m.code:=pointer(1);
m.data:=pointer(2);
if MAkeProcInstanceCode(M)<>pointer(1) then
halt(2);
m.code:=pointer(1);
m.data:=pointer(2);
if MAkeProcInstanceDataAsm(M)<>pointer(2) then
halt(3);
m.code:=pointer(1);
m.data:=pointer(2);
if MAkeProcInstanceCodeAsm(M)<>pointer(1) then
halt(4);
end.