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
如果符合 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