The issue exists because the inline assembly assumes the first argument as well as the return value to be using register
eax
, which is true for Delphi in 32-bit mode as per Delphi's
calling convention(and although the
inline assembly documentationebp
and
esp
, this always held true even inside of inline assembly statements when they were placed at the top of a function).
否,64位模式使用一个不同的呼叫惯例,其中第一个参数在rcx
中,返回值正在使用rax
。因此,在这里,您将随机的非初始化垃圾作为恰好在该寄存器中的返回值(与其字节交换),因为它从未明确设置。
最好的便携式解决方案是在没有内联装配的情况下实现纯Pascal的字节交换:使用数十年的
Swap
函数换了值的较低2个字节。这本身就不再有用了,但是可以使用两次(以及一些位移和掩盖)来缩短代码以换成所有4个字节32位值的代码。
具有更多源代码但可能会产生较少复杂的装配代码的Another Way将是访问the in中的单个字节:
使用字节指针:Cardinal
64位组件通过与32位不同的寄存器中的参数传递。在这种情况下,参数将在ECX寄存器中,返回值必须在EAX中。
对于32位和64位组件需要不同的代码。
function SwapLong(Value: Cardinal): Cardinal; inline;
begin
PByte(@Result)^ := PByte(NativeUInt(@Value) + 3)^;
PByte(NativeUInt(@Result) + 1)^ := PByte(NativeUInt(@Value) + 2)^;
PByte(NativeUInt(@Result) + 2)^ := PByte(NativeUInt(@Value) + 1)^;
PByte(NativeUInt(@Result) + 3)^ := PByte(@Value)^;
end;
由于仅在Windows上可用,因此其他平台需要纯Pascal代码,如Cherrydt的答案
function SwapLong(Value: Cardinal): Cardinal;
{$IFDEF ASSEMBLER}
{$IFDEF CPUX86}
asm
bswap eax
end;
{$ENDIF CPUX86}
{$IFDEF CPUX64}
asm
mov eax, ecx
bswap eax
end;
{$ENDIF CPUX64}
{$ELSE}
begin
// pascal version
end;
{$ENDIF}