mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-20 13:29:14 +02:00
* fix #40451: load the assembly symbol into a separate operand so that an offset already contained in oper isn't discarded + added test
This commit is contained in:
parent
b003828d26
commit
f88ee7b2d8
@ -306,6 +306,7 @@ Implementation
|
|||||||
|
|
||||||
var
|
var
|
||||||
expr : string;
|
expr : string;
|
||||||
|
tmp : tx86operand;
|
||||||
begin
|
begin
|
||||||
oper.InitRef;
|
oper.InitRef;
|
||||||
Consume(AS_LPAREN);
|
Consume(AS_LPAREN);
|
||||||
@ -357,35 +358,53 @@ Implementation
|
|||||||
begin
|
begin
|
||||||
expr:=actasmpattern;
|
expr:=actasmpattern;
|
||||||
Consume(AS_ID);
|
Consume(AS_ID);
|
||||||
if not oper.SetupVar(expr,false) then
|
tmp:=Tx86Operand.create;
|
||||||
|
if not tmp.SetupVar(expr,false) then
|
||||||
begin
|
begin
|
||||||
{ look for special symbols ... }
|
{ look for special symbols ... }
|
||||||
if expr= '__HIGH' then
|
if expr= '__HIGH' then
|
||||||
begin
|
begin
|
||||||
consume(AS_LPAREN);
|
consume(AS_LPAREN);
|
||||||
if not oper.setupvar('high'+actasmpattern,false) then
|
if not tmp.setupvar('high'+actasmpattern,false) then
|
||||||
Message1(sym_e_unknown_id,'high'+actasmpattern);
|
Message1(sym_e_unknown_id,'high'+actasmpattern);
|
||||||
consume(AS_ID);
|
consume(AS_ID);
|
||||||
consume(AS_RPAREN);
|
consume(AS_RPAREN);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if expr = '__SELF' then
|
if expr = '__SELF' then
|
||||||
oper.SetupSelf
|
tmp.SetupSelf
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
message1(sym_e_unknown_id,expr);
|
message1(sym_e_unknown_id,expr);
|
||||||
RecoverConsume(false);
|
RecoverConsume(false);
|
||||||
|
tmp.free;
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
{ convert OPR_LOCAL register para into a reference base }
|
{ convert OPR_LOCAL register para into a reference base }
|
||||||
if (oper.opr.typ=OPR_LOCAL) and
|
if (tmp.opr.typ=OPR_LOCAL) and
|
||||||
AsmRegisterPara(oper.opr.localsym) then
|
AsmRegisterPara(tmp.opr.localsym) then
|
||||||
oper.InitRefConvertLocal
|
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.base:=tmp.opr.ref.base;
|
||||||
|
tmp.free;
|
||||||
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
message(asmr_e_invalid_reference_syntax);
|
message(asmr_e_invalid_reference_syntax);
|
||||||
RecoverConsume(false);
|
RecoverConsume(false);
|
||||||
|
tmp.free;
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
{ can either be a register, an identifier or a right parenthesis }
|
{ can either be a register, an identifier or a right parenthesis }
|
||||||
|
24
tests/webtbs/tw40451.pp
Normal file
24
tests/webtbs/tw40451.pp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{ %CPU=x86_64,i386 }
|
||||||
|
|
||||||
|
program tw40451;
|
||||||
|
|
||||||
|
{$mode objfpc}
|
||||||
|
{$asmmode att}
|
||||||
|
procedure DoubleUint32ToTheLeft(x: pointer); {$ifdef cpu386}register;{$endif} assembler; nostackframe;
|
||||||
|
asm
|
||||||
|
movl -4(x), %edx // Becomes "movl (x), %edx"
|
||||||
|
shl $1, %edx
|
||||||
|
movl %edx, -4(x) // Becomes "movl %edx, (x)"
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
a: array[0 .. 2] of uint32 = (10, 11, 12);
|
||||||
|
|
||||||
|
begin
|
||||||
|
DoubleUint32ToTheLeft(@a[1]);
|
||||||
|
writeln('Got: ', a[0], ' ', a[1], ' ', a[2]);
|
||||||
|
writeln('Expected: 20 11 12');
|
||||||
|
if (a[0] <> 20) or (a[1] <> 11) or (a[2] <> 12) then
|
||||||
|
Halt(1);
|
||||||
|
end.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user