我在将Delphi代码移植到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;
end.以上代码在Delphi中编译并按预期工作;FPC输出MUL EAX,EDX行上的编译时错误:
错误: Asm: mul reg32,reg32操作码和操作数的无效组合
我将Lazarus1.4.4/FPC2.6.4用于Win32 (当前稳定版本)
有什么解决办法或解决办法吗?
发布于 2015-12-30 06:27:05
FreePascal是正确的。只有3种形式的MUL
MUL r/m8
MUL r/m16
MUL r/m32执行第一个操作数(目标操作数)和第二个操作数(源操作数)的无符号乘法,并将结果存储在目标操作数中。目标操作数是位于寄存器AL、AX或EAX中的隐含操作数(取决于操作数的大小);源操作数位于通用寄存器或内存位置中。
换句话说,第一个操作数(用于输入和输出)在AL/AX/EAX,中指定,第二个输入操作数显式地指定为通用寄存器或内存地址。
因此,MUL EAX,EDX确实是一个无效的程序集指令。
如果在Delphi中编译此代码并使用调试器查看生成的程序集,您将看到对Mul(10,20)的调用生成以下程序集代码:
// Mul(10,20)
mov edx,$00000014
mov eax,$0000000a
call Mul
//MUL EAX,EDX
mul edx因此,正如您所看到的,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;虽然在本例中德尔菲确实使用了IMUL而不是MUL。来自德尔菲的文档
x / y的值为Extended类型,与x和y的类型无关。对于其他算术运算符,当至少一个操作数为实时,结果为Extended类型;否则,当至少一个操作数为Int64类型时,结果为Int64类型;否则,结果为类型。如果操作数的类型是整数类型的子范围,则将其视为整数类型。
它还使用一些难看的臃肿的程序集,除非禁用堆栈帧并启用优化。通过配置这两个选项,可以让Mul()生成单个IMUL EDX指令(当然还有RET指令)。如果不想在项目范围内更改选项,可以使用Mul() / {$STACKFRAMES OFF}/{$W-}和{$OPTIMIZATION ON}/{$O+}编译器指令将它们隔离为只使用{$OPTIMIZATION ON}。
{$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发布于 2015-12-30 06:26:51
MUL总是由AL、AX或EAX (更多细节)乘以,因此您应该只指定其他操作数。
https://stackoverflow.com/questions/34523936
复制相似问题