diff --git a/compiler/x86/rax86att.pas b/compiler/x86/rax86att.pas index 9e7064e9ad..28190cc348 100644 --- a/compiler/x86/rax86att.pas +++ b/compiler/x86/rax86att.pas @@ -207,7 +207,105 @@ Implementation end; end; + procedure Consume_Index; + procedure Check_Scaling; + begin + { check for scaling ... } + case actasmtoken of + AS_RPAREN: + Begin + Consume_RParen; + exit; + end; + AS_COMMA: + Begin + Consume(AS_COMMA); + Consume_Scale; + Consume_RParen; + end; + else + Begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + end; + end; { end case } + end; + + var + tmp : tx86operand; + expr : string; + begin + if actasmtoken=AS_REGISTER then + Begin + oper.opr.ref.index:=actasmregister; + Consume(AS_REGISTER); + Check_Scaling; + end + else if actasmtoken=AS_ID then + begin + expr:=actasmpattern; + Consume(AS_ID); + tmp:=Tx86Operand.create; + if not tmp.SetupVar(expr,false) then + begin + { look for special symbols ... } + if expr= '__HIGH' then + begin + consume(AS_LPAREN); + if not tmp.setupvar('high'+actasmpattern,false) then + Message1(sym_e_unknown_id,'high'+actasmpattern); + consume(AS_ID); + consume(AS_RPAREN); + end + else + if expr = '__SELF' then + tmp.SetupSelf + else + begin + message1(sym_e_unknown_id,expr); + RecoverConsume(false); + tmp.free; + Exit; + end; + end; + { convert OPR_LOCAL register para into a reference base } + if (tmp.opr.typ=OPR_LOCAL) and + AsmRegisterPara(tmp.opr.localsym) then + begin + tmp.InitRefConvertLocal; + if (tmp.opr.ref.index<>NR_NO) or + (tmp.opr.ref.offset<>0) or + (tmp.opr.ref.scalefactor<>0) or + (tmp.opr.ref.segment<>NR_NO) or + (tmp.opr.ref.base=NR_NO) then + begin + message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + tmp.free; + Exit; + end; + oper.opr.ref.index:=tmp.opr.ref.base; + tmp.free; + Check_Scaling; + end + else + begin + message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + tmp.free; + Exit; + end; + end + else + Begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + end; + end; + + var + expr : string; begin oper.InitRef; Consume(AS_LPAREN); @@ -244,7 +342,7 @@ Implementation oper.opr.ref.refaddr:=addr_pic_no_got; {$endif x86_64} Consume(AS_REGISTER); - { can either be a register or a right parenthesis } + { can either be a register, an identifier or a right parenthesis } { (reg) } if actasmtoken=AS_RPAREN then Begin @@ -253,36 +351,53 @@ Implementation end; { (reg,reg .. } Consume(AS_COMMA); - if actasmtoken=AS_REGISTER then - Begin - oper.opr.ref.index:=actasmregister; - Consume(AS_REGISTER); - { check for scaling ... } - case actasmtoken of - AS_RPAREN: - Begin - Consume_RParen; - exit; - end; - AS_COMMA: - Begin - Consume(AS_COMMA); - Consume_Scale; - Consume_RParen; - end; - else - Begin - Message(asmr_e_invalid_reference_syntax); - RecoverConsume(false); - end; - end; { end case } - end - else - Begin - Message(asmr_e_invalid_reference_syntax); - RecoverConsume(false); - end; + Consume_Index; end; {end case } + AS_ID: { identifier (parameter, variable, ...), but only those that might be in a register } + begin + expr:=actasmpattern; + Consume(AS_ID); + if not oper.SetupVar(expr,false) then + begin + { look for special symbols ... } + if expr= '__HIGH' then + begin + consume(AS_LPAREN); + if not oper.setupvar('high'+actasmpattern,false) then + Message1(sym_e_unknown_id,'high'+actasmpattern); + consume(AS_ID); + consume(AS_RPAREN); + end + else + if expr = '__SELF' then + oper.SetupSelf + else + begin + message1(sym_e_unknown_id,expr); + RecoverConsume(false); + Exit; + end; + end; + { convert OPR_LOCAL register para into a reference base } + if (oper.opr.typ=OPR_LOCAL) and + AsmRegisterPara(oper.opr.localsym) then + oper.InitRefConvertLocal + else + begin + message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + Exit; + end; + { can either be a register, an identifier or a right parenthesis } + { (reg) } + if actasmtoken=AS_RPAREN then + begin + Consume_RParen; + exit; + end; + Consume(AS_COMMA); + Consume_Index; + end; AS_COMMA: { (, ... can either be scaling, or index } Begin Consume(AS_COMMA); diff --git a/tests/test/tasm28.pp b/tests/test/tasm28.pp new file mode 100644 index 0000000000..843c055ed8 --- /dev/null +++ b/tests/test/tasm28.pp @@ -0,0 +1,17 @@ +{ %NORUN } +{ %CPU=i386,x86_64 } + +program tasm28; + +{$mode objfpc} + +{$asmmode att} +procedure Test(aArr: array of LongInt); {$ifdef cpu386}register;{$endif} assembler; nostackframe; +asm + movb $5, (aArr, __HIGH(aArr)) + movb $5, (__HIGH(aArr), aArr) +end; + +begin + +end. diff --git a/tests/test/tasm29.pp b/tests/test/tasm29.pp new file mode 100644 index 0000000000..4e6403b4a4 --- /dev/null +++ b/tests/test/tasm29.pp @@ -0,0 +1,22 @@ +{ %NORUN } +{ %CPU=i386,x86_64 } + +program tasm29; + +{$mode objfpc} + +type + + TTest = class + procedure Test(aArg: Pointer); {$ifdef cpu386}register;{$endif} assembler; nostackframe; + end; + +procedure TTest.Test(aArg: Pointer); {$ifdef cpu386}register;{$endif} assembler; nostackframe; +asm + movb $5, (__SELF, aArg) + movb $5, (aArg, __SELF) +end; + +begin + +end. diff --git a/tests/webtbs/tw40390.pp b/tests/webtbs/tw40390.pp new file mode 100644 index 0000000000..c8052ead5f --- /dev/null +++ b/tests/webtbs/tw40390.pp @@ -0,0 +1,23 @@ +{ %NORUN } +{ %CPU=i386,x86_64 } + +program tw40390; + +{$asmmode att} +procedure SetMiddleTo5(p: pointer; n: SizeUint); {$ifdef cpu386}register;{$endif} assembler; nostackframe; +asm +{$ifdef cpu386} + shrl $1, n // becomes “shrq $1, %rdx” (Win64) or “shrq $1, %rsi” (System V) + movb $5, (p,n) // Invalid reference syntax. + movb $5, (%edx,n) + movb $5, (p,%edx) +{$elseif defined(cpux86_64)} + shrq $1, n // becomes “shrq $1, %rdx” (Win64) or “shrq $1, %rsi” (System V) + movb $5, (p,n) // Invalid reference syntax. + movb $5, (%rdx,n) + movb $5, (p,%rdx) +{$endif} +end; + +begin +end.