Assembly x64代码中的对齐问题,免费Pascal

Assembly x64代码中的对齐问题,免费Pascal,assembly,lazarus,freepascal,Assembly,Lazarus,Freepascal,如果符合32位(使用适用的寄存器重命名),下面的代码可以正常工作。但它在执行时会抛出一个错误(并且“警告:对象文件“project1.o”包含对symbol.data.n\u tc\u p$project1\u orbitkeyheader64$int64$longint$$int64\u shufidx的32位绝对重定位)。 “编译时) 如何校正(理想地调整常数) 编辑 我还试着使用movdqu 回答 这是@Jester回答的结果: function SwapBytes64(const Val

如果符合32位(使用适用的寄存器重命名),下面的代码可以正常工作。但它在执行时会抛出一个错误(并且“警告:对象文件“project1.o”包含对symbol.data.n\u tc\u p$project1\u orbitkeyheader64$int64$longint$$int64\u shufidx的32位绝对重定位)。 “编译时)

如何校正(理想地调整常数)

编辑 我还试着使用movdqu

回答 这是@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;

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


作为一种解决方法,您应该使用rip相对寻址或间接寻址。前者可能看起来像
movdquxmm1、[rip+SHUFIDX]
movdquxmm1、rel SHUFIDX
或类似的东西。请参阅编译器手册。

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


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

RIP+Var name解决了我的问题,即所讨论的变量被截断为32位内存分配。我甚至将变量的空间解释为Int64,但没有成功。用一个值加载RAX,然后将其分配给该变量是可行的,但需要额外的编码,使32位代码块大小加倍

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

这会起作用,但会使代码膨胀:

MOV RAX, RBX
MOV qword[var], RAX
…虽然这在MOV指令较少的情况下仍能正常工作:

MOV qword[RIP + var], RBX

既然它是一个局部变量,你不应该像
[rbp-8]那样做吗
或类似的方法来处理局部变量?64位模式不喜欢常量。32位就可以了。这是一个定义对齐问题。我不需要像rbp-8这样的东西,因为我可以直接引用常量。什么平台?我记得在Windows上看到类似的错误,而实际上符号在任何地方都没有定义。我正在使用L进行编译azarus/Free Pascal针对的是Win64/Athlon64。Lazarus是32位虚拟机,我从C#调用代码。在32位模式下,我可以在本地测试它,它可以工作(也没有编译器警告)。请参阅@IanC了解其他人的优点,您能告诉我们编译器接受哪种语法吗?根据@TheRaven的回答,它是
[RIP+var]
。噢,OP也在问题的答案中进行了编辑。:/请记住,这种评论应该在评论部分发表,只有相关的答案应该发布在这里。我非常怀疑
MOV-qword[var],RAX
MOV-qword[var]时起作用,RBX不支持,但由于显示了正确的语法(
[RIP+var]
)对于RIP相对寻址模式的此汇编器。恐怕它确实与FAsm和NAsm一起工作,但64位输出的FreePascal中的内联汇编器会由于64位可执行文件中的内存空间截断而引发寻址错误-对于upvote,编译器bug.Thanx-是的,当内存分配为explicitl时,RBX移动到vary设置为四字应该最有效,我同意你的观点Peter Cordes。小心。但这两个指令之间的唯一区别是使用不同的64位寄存器(
rax
,而不是
rbx
)。这有什么区别呢?如前所述,FreePascal编译器(本讨论的内容)正在截断内存(从64位到32位)FPC似乎唯一认可的即时通用寄存器(内存大小方面)是RAX;还有其他寄存器,但仍然很痛苦。因此我使用rip+内存地址(通过命名引用)作为补偿。这是一个RIP问题,FPC也知道它-我仍然不明白为什么它没有被修复,因为这个问题已经存在了2年。我还想知道为什么编译器在64位系统中将内存分配截断为32位,默认malloc大小为64位,除非明确说明必须是32位,这似乎是rs是FPC中的一个逻辑错误(设计),有助于该线程处理的实际错误。
MOV qword[RIP + var], RBX