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

时间:2015-02-06 13:31:24

标签: assembly lazarus freepascal

如果符合32位(使用适用的寄存器重命名),下面的代码可以正常工作。但它在执行时会抛出错误("警告:对象文件" project1.o"包含32位绝对重定位到符号" .data.n_tc_p $ project1_orbitkeyheader64 $ int64 $ longint $ $ int64_shufidx&#34 ;. "编译时。)

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

如何纠正这个问题(理想情况下对齐常数)。

修改 我也尝试过使用movdqu。

ANSWER 这是@ Jester的回答结果:

function SwapBytes64(const Val: Int64): Int64;
const
  SHUFIDX : array [0..1] of Int64 = ($0001020304050607, 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 = ($0001020304050607, 0);
begin
asm
  movq          xmm0, rcx
  pshufb        xmm0, [rip+SHUFIDX]
  movq          rax, xmm0
end;
end;

3 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:3)

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

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

答案 2 :(得分:1)

RIP + Var名称解决了我的问题,其中有问题的变量被截断为32位内存分配。我甚至将变量的空间表示为Int64而没有成功。使用值加载RAX,然后将其分配给变量工作,但需要额外的编码使32位代码块大小加倍。

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

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

MOV RAX, RBX
MOV qword[var], RAX

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

MOV qword[RIP + var], RBX