delphi - 在 64 位内联汇编器中访问 Delphi 类字段

标签 delphi 64-bit inline-assembly delphi-xe4

我正在尝试将 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 位。经过一番搜索,我发现我需要将 64 位编译器的 EAX 引用更改为 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 倍。

最佳答案

基本问题是您使用了错误的寄存器。 Self 作为隐式参数在所有其他参数之前传递。在 x64 calling convention ,这意味着它是在 RCX 中传递的,而不是在 RAX 中传递的。

因此,SelfRCX 中传递,IndexRDX 中传递。坦率地说,我认为在内联汇编程序中使用参数名称是错误的,因为它们隐藏了参数是在寄存器中传递的事实。如果您碰巧覆盖了RDX,那么就会改变Index的表观值。

因此 if 语句可能会编码为

CMP     EDX,[RCX].FSize
JNL     TBits.Error
CMP     EDX,0
JL      TBits.Error

FWIW,这是一个实现起来非常简单的函数,我不相信您需要使用任何堆栈空间。 x64 中有足够的寄存器,可以完全使用 volatile 寄存器来完成此操作。

关于delphi - 在 64 位内联汇编器中访问 Delphi 类字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29286157/

相关文章:

Delphi 叠瓦式回调函数

delphi - 如何在 2009 年之前的 Delphi 中解码包含日语字符的 url?

c++ - x64 CPU 上的原子 16 字节读取

windows - 在 64 位机器上安装 Coldfusion 8 32 位 - 有问题吗?

delphi - 组件构造函数中的 nil Owner 是什么意思

delphi - SuperObject 无法处理空字符串

ios - NSUInteger 字符串编码 32 位和 64 位

c - 使用内联汇编从 C 函数获取返回的字符

c - GCC x86 内联汇编中的 (+r) 与 (=r) 约束

将 C 代码转换为 x86-64 汇编