What should I do or not do to avoid the Delphi "push dword" error.

I found that Delphi 5 generates the wrong build code in certain cases. I canโ€™t understand in what cases at all. The following example shows an access violation because a very strange optimization is taking place. For a byte in a record or array, Delphi generates a push dword [...], pop ebx, mov .., bl, which works correctly if there is data after this byte (we need at least three to correctly press dword), but not works if data is not available. I emulated strict boundaries here using win32 Virtual * functions

In particular, an error occurs when the last byte of a block is accessed inside the FeedBytesToClass procedure. And if I try to change something like using a data array instead of an object property to delete the actionFlag variable, Delphi will generate the correct assembly instructions.

const
  BlockSize = 4096;

type
  TSomeClass = class
  private
    fBytes: PByteArray;
  public
    property Bytes: PByteArray read fBytes;
    constructor Create;
    destructor  Destroy;override;
  end;

constructor TSomeClass.Create;
begin
  inherited Create;
  GetMem(fBytes, BlockSize);
end;

destructor TSomeClass.Destroy;
begin
  FreeMem(fBytes);
  inherited;
end;

procedure FeedBytesToClass(SrcDataBytes: PByteArray; Count: integer);
var
  j: integer;
  Ofs: integer;
  actionFlag: boolean;
  AClass: TSomeClass;
begin
  AClass:=TSomeClass.Create;
  try
    actionFlag:=true;

    for j:=0 to Count-1 do
    begin
      Ofs:=j;
      if actionFlag then
      begin
        AClass.Bytes[Ofs]:=SrcDataBytes[j];
      end;
    end;
  finally
    AClass.Free;
  end;
end;

procedure TForm31.Button1Click(Sender: TObject);
var
  SrcDataBytes: PByteArray;
begin
  SrcDataBytes:=VirtualAlloc(Nil, BlockSize, MEM_COMMIT, PAGE_READWRITE);
  try
    if VirtualLock(SrcDataBytes, BlockSize) then
      try
        FeedBytesToClass(SrcDataBytes, BlockSize);
      finally
        VirtualUnLock(SrcDataBytes, BlockSize);
      end;
  finally
    VirtualFree(SrcDataBytes, MEM_DECOMMIT, BlockSize);
  end;
end;

Initially, an error occurred when I used access to the RGB data of bitmart bits, but the code there is too complicated, so I narrowed it down to this fragment.

So, the question is what is so specific here, what does Delphi produce push, pop, mov optim. I need to know this to avoid such side effects in general.

+3
source share
3 answers

, . actionFlag ( 4) push/pop . , ( , , cpu /):

AClass.Bytes[Ofs] := SrcDataBytes[j];
  mov exc,[ebp-$04]
  push dword ptr [ecx+eax]   <- ouch
  mov ecx,[ebp-$08]
  mov ecx,[exc+04]
  lea esi,[exc+esi]
  pop ecx
  mov [esi],cl
end;
  inc eax

4096 . , Delphi 6 . , , .

{$ O -}/{$ O +} . , , Delphi , -, , Delphi .

, , . , , , , . , , , , 90% Delphi 5. , .

+10

Upgrade. Delphi 5 10 .

+3

, , ... :

  • GetMem New, , ByteArray.
    D5, D2007:
    PByteArray = ^ TByteArray;
    TByteArray = [0.. 32767] ;

  • Try using FastMM4 to allocate memory. Its easier to see what is happening and find problems.

BTW, in D2007 asm generated by the compiler, is different from Paul-Jan :

Unit7.pas.67: AClass.Bytes[Ofs]:=SrcDataBytes[j];
        mov ebx,[ebp-$04]
        movzx ebx,[ebx+eax]
        push ebx
        mov ebx,[ebp-$08]
        mov ebx,[ebx+$04]
        lea esi,[ebx+esi]
        pop ebx
        mov [esi],bl
Unit7.pas.69: end;
        inc eax
+3
source

Source: https://habr.com/ru/post/1715440/


All Articles