Browse Source

* throw an error if instructions which needs an operand size is used with one operand being a reference without size

florian 1 year ago
parent
commit
803a6fea24
3 changed files with 50 additions and 1 deletions
  1. 28 0
      compiler/x86/aasmcpu.pas
  2. 12 1
      compiler/x86/rax86.pas
  3. 10 0
      tests/webtbf/tw40399.pp

+ 28 - 0
compiler/x86/aasmcpu.pas

@@ -659,6 +659,8 @@ interface
     function get_ref_address_size(const ref:treference):byte;
     function get_ref_address_size(const ref:treference):byte;
     function get_default_segment_of_ref(const ref:treference):tregister;
     function get_default_segment_of_ref(const ref:treference):tregister;
     procedure optimize_ref(var ref:treference; inlineasm: boolean);
     procedure optimize_ref(var ref:treference; inlineasm: boolean);
+    { returns true if opcode can be used with one memory operand without size }
+    function NoMemorySizeRequired(opcode : TAsmOp) : Boolean;
 
 
     function spilling_create_load(const ref:treference;r:tregister):Taicpu;
     function spilling_create_load(const ref:treference;r:tregister):Taicpu;
     function spilling_create_store(r:tregister; const ref:treference):Taicpu;
     function spilling_create_store(r:tregister; const ref:treference):Taicpu;
@@ -5581,6 +5583,32 @@ implementation
       end;
       end;
     end;
     end;
 
 
+
+    function NoMemorySizeRequired(opcode : TAsmOp) : Boolean;
+      var
+        i : LongInt;
+        insentry  : PInsEntry;
+      begin
+        result:=false;
+        i:=instabcache^[opcode];
+        if i=-1 then
+         begin
+           Message1(asmw_e_opcode_not_in_table,gas_op2str[opcode]);
+           exit;
+         end;
+        insentry:=@instab[i];
+        while (insentry^.opcode=opcode) do
+         begin
+           if (insentry^.ops=1) and (insentry^.optypes[0]=OT_MEMORY) then
+             begin
+               result:=true;
+               exit;
+             end;
+           inc(insentry);
+         end;
+      end;
+
+
     procedure InitAsm;
     procedure InitAsm;
       begin
       begin
         build_spilling_operation_type_table;
         build_spilling_operation_type_table;

+ 12 - 1
compiler/x86/rax86.pas

@@ -436,10 +436,11 @@ begin
   Opsize:=S_NO;
   Opsize:=S_NO;
 end;
 end;
 
 
-procedure Tx86Instruction.AddReferenceSizes;
 { this will add the sizes for references like [esi] which do not
 { this will add the sizes for references like [esi] which do not
   have the size set yet, it will take only the size if the other
   have the size set yet, it will take only the size if the other
   operand is a register }
   operand is a register }
+procedure Tx86Instruction.AddReferenceSizes;
+
 var
 var
   operand2,i,j,k : longint;
   operand2,i,j,k : longint;
   s : tasmsymbol;
   s : tasmsymbol;
@@ -1400,6 +1401,16 @@ begin
                    begin
                    begin
                      if opsize<>S_NO then
                      if opsize<>S_NO then
                        tx86operand(operands[i]).opsize:=opsize
                        tx86operand(operands[i]).opsize:=opsize
+                     else if not(NoMemorySizeRequired(opcode) or
+                       (opcode=A_JMP) or (opcode=A_JCC) or (opcode=A_CALL) or (opcode=A_LCALL) or (opcode=A_LJMP)) then
+                       begin
+                         if (m_delphi in current_settings.modeswitches) then
+                           Message(asmr_w_unable_to_determine_reference_size_using_dword)
+                         else
+                           Message(asmr_e_unable_to_determine_reference_size);
+                         { recovery }
+                         tx86operand(operands[i]).opsize:=S_L;
+                       end;
                    end;
                    end;
                 end;
                 end;
               OPR_SYMBOL :
               OPR_SYMBOL :

+ 10 - 0
tests/webtbf/tw40399.pp

@@ -0,0 +1,10 @@
+{ %cpu=i386 }
+{ %fail }
+{$asmmode intel}
+
+begin
+  asm
+    fnstcw [esi]
+    imul [esi]
+  end;
+end.