Delphi FPC BASM32 MUL错误?
我在将Delphi BASM32代码移植到FPC时遇到一个问题:Delphi FPC BASM32 MUL错误?,delphi,lazarus,freepascal,fpc,basm,Delphi,Lazarus,Freepascal,Fpc,Basm,我在将Delphi BASM32代码移植到FPC时遇到一个问题: program MulTest; {$IFDEF FPC} {$mode delphi} {$asmmode intel} {$ELSE} {$APPTYPE CONSOLE} {$ENDIF} function Mul(A, B: LongWord): LongWord; asm MUL EAX,EDX end; begin Writeln(Mul(10,20)); Readln
program MulTest;
{$IFDEF FPC}
{$mode delphi}
{$asmmode intel}
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF}
function Mul(A, B: LongWord): LongWord;
asm
MUL EAX,EDX
end;
begin
Writeln(Mul(10,20));
Readln;
end.
上述代码在Delphi XE中编译并按预期工作;FPC在MUL EAX,EDX
行上输出编译时错误:
错误:Asm:[mul reg32,reg32]操作码和密码的组合无效
操作数
我正在使用Lazarus 1.4.4/FPC2.6.4 for Win32(当前稳定版本)
该问题的任何解决方法或修复方法?MUL总是乘以AL、AX或EAX(),因此您应该只指定另一个操作数。FreePascal是正确的。只有以下三种形式: 对第一个操作数(目标操作数)和第二个操作数(源操作数)执行无符号乘法,并将结果存储在目标操作数中目标操作数是位于寄存器AL、AX或EAX中的隐含操作数(取决于操作数的大小);源操作数位于通用寄存器或内存位置 换句话说,第一个操作数(用于输入和输出)在
AL
/AX
/EAX
中指定,第二个输入操作数明确指定为通用寄存器或内存地址
因此,MUL-EAX,EDX
确实是一条无效的汇编指令
如果您在Delphi中编译此代码并使用调试器查看生成的程序集,您将看到对Mul(10,20)
的调用生成以下程序集代码:
// Mul(10,20)
mov edx,$00000014
mov eax,$0000000a
call Mul
因此,正如您所看到的,Delphi正在实际解析您的源代码,看到第一个操作数是EAX
,并为您将其剥离,从而生成正确的程序集。FreePascal并不是为你做这一步
解决办法?首先编写正确的汇编代码。不要依赖编译器为您重新解释代码
function Mul(A, B: LongWord): LongWord;
asm
MUL EDX
end;
或者,您不能直接编写汇编代码,让编译器为您完成这项工作。它知道如何将两个LongWord
值组合在一起:
function Mul(A, B: LongWord): LongWord;
begin
Result := A * B;
end;
尽管在这种情况下,Delphi使用了IMUL
而不是MUL
。德尔福:
无论x
和y
的类型如何,x/y
的值都属于扩展的类型。对于其他算术运算符,只要至少有一个操作数是实数,则结果类型为Extended
;否则,当至少一个操作数的类型为Int64
时,结果的类型为Int64
否则,结果的类型为Integer
。如果操作数的类型是整数类型的子范围,则将其视为整数类型
除非禁用stackframes并启用优化,否则它还使用一些难看的臃肿部件。通过配置这两个选项,可以获得Mul()
以生成单个IMUL EDX
指令(当然还有RET
指令)。如果不想在项目范围内更改选项,可以使用{$STACKFRAMES OFF}
/{$W-}
和{$OPTIMIZATION ON}
/{$O+}
编译器指令将它们隔离为Mul()
{$IFOPT W+}{$W-}{$DEFINE SF_Was_On}{$ENDIF}
{$IFOPT O-}{$O+}{$DEFINE O_Was_Off}{$ENDIF}
function Mul(A, B: LongWord): LongWord;
begin
Result := A * B;
end;
{$IFDEF SF_Was_On}{W+}{$UNDEF SF_Was_On}{$ENDIF}
{$IFDEF O_Was_Off}{O-}{$UNDEF O_Was_Off}{$ENDIF}
生成:
imul edx
ret
Remy,这只是一个独立的问题:我可以看到您正在开始/结束对中设置编译器指令,并且之后不会重置它们。这是因为通过在函数体中设置它们,它们仅是该函数的本地对象吗?每当我需要临时设置一些编译器指令时,我总是沿着{$IFOPT W+}{$DEFINE WASON}{$W-}{$ENDIF}和{$IFDEF WASON}{$W+}{$ENDIF}做一些事情,但是如果可以通过将“本地”编译器指令放在主体中来实现,那么这是不必要的。我提到的两个指令都有局部作用域,但我认为我对与编译器指令相关的局部范围的理解是错误的。我已经更新了我的示例。在FPC中,您可以使用$push/$pop恢复状态。@MarcovandeVoort:True。Delphi没有与之等价的产品(我希望有)。
{$IFOPT W+}{$W-}{$DEFINE SF_Was_On}{$ENDIF}
{$IFOPT O-}{$O+}{$DEFINE O_Was_Off}{$ENDIF}
function Mul(A, B: LongWord): LongWord;
begin
Result := A * B;
end;
{$IFDEF SF_Was_On}{W+}{$UNDEF SF_Was_On}{$ENDIF}
{$IFDEF O_Was_Off}{O-}{$UNDEF O_Was_Off}{$ENDIF}
imul edx
ret