Browse Source

* fix #40451: load the assembly symbol into a separate operand so that an offset already contained in oper isn't discarded + added test

Sven/Sarah Barth 1 year ago
parent
commit
f88ee7b2d8
2 changed files with 49 additions and 6 deletions
  1. 25 6
      compiler/x86/rax86att.pas
  2. 24 0
      tests/webtbs/tw40451.pp

+ 25 - 6
compiler/x86/rax86att.pas

@@ -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
-                 AsmRegisterPara(oper.opr.localsym) then
-                oper.InitRefConvertLocal
+              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.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 - 0
tests/webtbs/tw40451.pp

@@ -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.
+