我正在尝试将 Delphi TBits.GetBit 转换为 64 位版本的内联汇编。VCL 源代码如下:
function TBits.GetBit(Index: Integer): Boolean;
{$IFNDEF X86ASM}
var
LRelInt: PInteger;
LMask: Integer;
begin
if (Index >= FSize) or (Index < 0) then
Error;
{ Calculate the address of the related integer }
LRelInt := FBits;
Inc(LRelInt, Index div BitsPerInt);
{ Generate the mask }
LMask := (1 shl (Index mod BitsPerInt));
Result := (LRelInt^ and LMask) <> 0;
end;
{$ELSE X86ASM}
asm
CMP Index,[EAX].FSize
JAE TBits.Error
MOV EAX,[EAX].FBits
BT [EAX],Index
SBB EAX,EAX
AND EAX,1
end;
{$ENDIF X86ASM}
我开始将32位的ASM代码转换为64位。经过搜索,我发现需要将EAX引用更改为64位编译器的RAX。我最终得到了以下第一行:
CMP Index,[RAX].FSize
这段代码编译通过,但在运行时会出现访问冲突。我尝试了几种组合(例如MOV ECX,[RAX].FSize
),但在尝试访问[RAX].FSize
时仍然出现访问冲突。当我查看由Delphi编译器生成的汇编代码时,它看起来我的[RAX].FSize
应该是正确的。
Unit72.pas.143: MOV ECX,[RAX].FSize
00000000006963C0 8B8868060000 mov ecx,[rax+$00000668]
同时,这是 Delphi 生成的代码:
Unit72.pas.131: if (Index >= FSize) or (Index < 0) then
00000000006963CF 488B4550 mov rax,[rbp+$50]
00000000006963D3 8B4D58 mov ecx,[rbp+$58]
00000000006963D6 3B8868060000 cmp ecx,[rax+$00000668]
00000000006963DC 7D06 jnl TForm72.GetBit + $24
00000000006963DE 837D5800 cmp dword ptr [rbp+$58],$00
00000000006963E2 7D09 jnl TForm72.GetBit + $2D
在这两种情况下,生成的汇编程序都使用
[rax+$00000668]
来访问FSize。在Delphi 64位汇编中访问类字段的正确方法是什么?这可能听起来像一件奇怪的优化事情,但是64位Pascal版本的汇编器似乎不是很高效。我们会多次调用这个例程,根据各种因素,它需要执行的时间长达5倍。
MOV RAX, Self
就可以保持代码不变了吗? - Graymatter