【发布时间】:2010-11-20 15:35:57
【问题描述】:
我发现 Delphi 5 在特定情况下会生成无效的汇编代码。我不明白一般情况下是什么情况。下面的示例会产生访问冲突,因为发生了非常奇怪的优化。对于记录或数组中的一个字节,Delphi 生成 push dword [...], pop ebx, mov .., bl 如果此字节之后有数据(我们至少需要三个才能正确推送 dword),则可以正常工作,但失败如果数据不可访问。我在这里用 win32 Virtual* 函数模拟了严格的界限
特别是在 FeedBytesToClass 过程中访问块的最后一个字节时发生错误。如果我尝试更改诸如使用数据数组而不是删除 actionFlag 变量的对象属性之类的东西,Delphi 会生成正确的汇编指令。
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;
最初我使用访问位图位的RGB数据时发生错误,但是那里的代码太复杂,所以我将其缩小到这个片段。
所以问题是这里有什么特别的东西让 Delphi 产生 push、pop、mov 优化。我需要知道这一点,以便在一般情况下避免这种副作用。
【问题讨论】:
-
Delphi5 的所有升级都安装了吗?
-
是的,我有。实际上这个 bug 在 Delphi 中仍然存在,因为 globalalloc 之后经常分配额外的字节,而内部 getmem 甚至更频繁。
-
这是 QC 中的错误吗?这将告诉我们它是否已在更高版本中得到修复,并且可能有解决方法。
-
如果您说 Delphi 生成的代码不正确,如果您向我们展示该代码是什么,将会很有帮助。仅仅说“push、pop、mov”是不够的。显示导致错误的实际代码。另外,请修改您的第二段。它不会解析为英语。