x64 代码中的对齐问题,Free Pascal

Alignment issue in x64 code, Free Pascal

如果符合 32 位(使用适用的寄存器重命名),下面的代码可以正常工作。但它在执行时会抛出错误(并且 "Warning: Object file "project1.o" 包含 32 位绝对重定位到符号 ".data.n_tc_p$project1_orbitkeyheader64$int64$longint$$int64_shufidx”。 “编译时)。

function SwapBytes64(const Val: Int64): Int64;
{$A 16}
const
  SHUFIDX : array [0..1] of Int64 = ([=10=]01020304050607, 0);
begin
asm
  movq          xmm0, rcx
  pshufb        xmm0, SHUFIDX    // throws
  movq          rax, xmm0
end;
end;

我该如何纠正这个问题(最好是对齐常量)。

编辑 我也试过使用 movdqu.

回答 这是@Jester 回答的结果:

function SwapBytes64(const Val: Int64): Int64;
const
  SHUFIDX : array [0..1] of Int64 = ([=11=]01020304050607, 0);
begin
asm
  movq          xmm0, rcx
  movdqu        xmm1, [rip+SHUFIDX]
  pshufb        xmm0, xmm1
  movq          rax, xmm0
end;
end;

这也有效,但没有明显的速度优势:

function SwapBytes64(const Val: Int64): Int64;
const
  SHUFIDX : array [0..1] of Int64 = ([=12=]01020304050607, 0);
begin
asm
  movq          xmm0, rcx
  pshufb        xmm0, [rip+SHUFIDX]
  movq          rax, xmm0
end;
end;

这可能根本不是对齐问题。编译器已警告您对 SHUFIDX 的绝对引用将被截断为 32 位。如果地址不在前 4GiB 内,将导致错误的内存引用。您应该在调试器中进行检查。

作为解决方法,您应该使用 rip-relative 或间接寻址。前者可能看起来像 movdqu xmm1, [rip+SHUFIDX]movdqu xmm1, rel SHUFIDX 或类似的东西。请查阅您的编译器手册。

与您的实际问题无关:您的代码不安全。除非你写一个纯汇编函数("assembler; asm .. end;",或者——在 Delphi 模式下——只包含一个 "asm .. end;" 块而没有周围的 "begin .. end;",编译器可以在前后插入代码你的汇编程序块。特别是,它可能会在你的汇编程序块完成执行后覆盖 rax 的值。

要解决此问题,请将您的函数设为纯汇编函数,或在末尾添加 "movq @result, rax"。

RIP + Var 名称解决了我的问题,即相关变量被截断为 32 位内存分配。我什至将变量的 space 解释为 Int64 但没有成功。用一个值加载 RAX 然后将其分配给变量工作,但需要额外的编码将 32 位代码块大小加倍。

MOV qword[var], RBX 会抛出错误

这可行,但会使代码膨胀:

MOV RAX, RBX
MOV qword[var], RAX

...虽然这可以按预期使用更少的 MOV 指令:

MOV qword[RIP + var], RBX